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 SavePNG(const Path& in_file, BitmapData* in_pData) { PROFILE_BLOCK; if (in_pData == nullptr) return false; FILE *fp = nullptr; FOPEN(&fp, in_file.GetData(), L("wb")); if (!fp) { AssertMsg(false, L("File %s could not be opened for writing"), in_file.GetData()); return false; } png_struct* png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (!png_ptr) { AssertMsg(false, L("png_create_write_struct failed")); return false; } png_info* info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { AssertMsg(false, L("png_create_info_struct failed")); return false; } if (setjmp(png_jmpbuf(png_ptr))) { AssertMsg(false, L("Error during init_io")); return false; } png_init_io(png_ptr, fp); if (setjmp(png_jmpbuf(png_ptr))) { AssertMsg(false, L("Error during writing header")); return false; } s32 bit_depth = 0; s32 color_type = 0; switch (in_pData->GetFormat()) { case BufferFormat::A_U1: color_type = ePNG_GrayScale; bit_depth = 1; break; case BufferFormat::A_U8: color_type = ePNG_GrayScale; bit_depth = 8; break; case BufferFormat::BGR_U24: color_type = ePNG_TrueColor; bit_depth = 8; break; case BufferFormat::ABGR_U32: color_type = ePNG_TrueColor | ePNG_Alpha; bit_depth = 8; break; default: return false; } png_set_IHDR(png_ptr, info_ptr, in_pData->GetWidth(), in_pData->GetHeight(), bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_write_info(png_ptr, info_ptr); if (setjmp(png_jmpbuf(png_ptr))) AssertMsg(false, L("Error during writing bytes")); u8* pBuffer = (u8*)in_pData->GetBuffer(); u8** row_pointers = new u8*[in_pData->GetHeight()]; for (u32 i = 0; i < in_pData->GetHeight(); i++) { row_pointers[i] = pBuffer; pBuffer += in_pData->GetBufferPitch(); } png_write_image(png_ptr, row_pointers); if (setjmp(png_jmpbuf(png_ptr))) { delete[] row_pointers; AssertMsg(false, L("Error during end of write")); return false; } png_write_end(png_ptr, nullptr); delete[] row_pointers; fclose(fp); return true; }
static PoolVector<uint8_t> _lossless_pack_png(const Ref<Image> &p_image) { Ref<Image> img = p_image->duplicate(); if (img->is_compressed()) img->decompress(); ERR_FAIL_COND_V(img->is_compressed(), PoolVector<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, PoolVector<uint8_t>()); info_ptr = png_create_info_struct(png_ptr); ERR_FAIL_COND_V(!info_ptr, PoolVector<uint8_t>()); if (setjmp(png_jmpbuf(png_ptr))) { ERR_FAIL_V(PoolVector<uint8_t>()); } PoolVector<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(PoolVector<uint8_t>()); } int pngf = 0; int cs = 0; switch (img->get_format()) { case Image::FORMAT_L8: { pngf = PNG_COLOR_TYPE_GRAY; cs = 1; } break; case Image::FORMAT_LA8: { pngf = PNG_COLOR_TYPE_GRAY_ALPHA; cs = 2; } break; case Image::FORMAT_RGB8: { pngf = PNG_COLOR_TYPE_RGB; cs = 3; } break; case Image::FORMAT_RGBA8: { pngf = PNG_COLOR_TYPE_RGB_ALPHA; cs = 4; } break; default: { if (img->detect_alpha()) { img->convert(Image::FORMAT_RGBA8); pngf = PNG_COLOR_TYPE_RGB_ALPHA; cs = 4; } else { img->convert(Image::FORMAT_RGB8); 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(PoolVector<uint8_t>()); } PoolVector<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(PoolVector<uint8_t>()); } png_write_end(png_ptr, NULL); return ret; }
bool ImageWriter::writePNG(SDL_Surface *surface, const std::string &filename) { // TODO Maybe someone can make this look nice? FILE *fp = fopen(filename.c_str(), "wb"); if (!fp) { logger->log("could not open file %s for writing", filename.c_str()); return false; } png_structp png_ptr; png_infop info_ptr; png_bytep *row_pointers; int colortype; if (SDL_MUSTLOCK(surface)) { SDL_LockSurface(surface); } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (!png_ptr) { logger->log("Had trouble creating png_structp"); return false; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); logger->log("Could not create png_info"); return false; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); logger->log("problem writing to %s", filename.c_str()); return false; } png_init_io(png_ptr, fp); colortype = (surface->format->BitsPerPixel == 24) ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA; png_set_IHDR(png_ptr, info_ptr, surface->w, surface->h, 8, colortype, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_write_info(png_ptr, info_ptr); png_set_packing(png_ptr); row_pointers = new png_bytep[surface->h]; if (!row_pointers) { logger->log("Had trouble converting surface to row pointers"); return false; } for (int i = 0; i < surface->h; i++) { row_pointers[i] = (png_bytep)(Uint8 *)surface->pixels + i * surface->pitch; } png_write_image(png_ptr, row_pointers); png_write_end(png_ptr, info_ptr); fclose(fp); delete [] row_pointers; png_destroy_write_struct(&png_ptr, (png_infopp)NULL); if (SDL_MUSTLOCK(surface)) { SDL_UnlockSurface(surface); } return true; }
int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) { png_structp png_ptr; png_infop info_ptr; unsigned char *pixels = NULL; unsigned char *from, *to; png_bytepp row_pointers = NULL; int i, bytesperpixel, color_type = PNG_COLOR_TYPE_GRAY; FILE *fp = NULL; /* use the jpeg quality setting for compression */ int compression; compression= (int)(((float)(ibuf->ftype & 0xff) / 11.1111f)); compression= compression < 0 ? 0 : (compression > 9 ? 9 : compression); /* for prints */ if(flags & IB_mem) name= "<memory>"; bytesperpixel = (ibuf->depth + 7) >> 3; if ((bytesperpixel > 4) || (bytesperpixel == 2)) { printf("imb_savepng: Cunsupported bytes per pixel: %d for file: '%s'\n", bytesperpixel, name); return (0); } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { printf("imb_savepng: Cannot png_create_write_struct for file: '%s'\n", name); return 0; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); printf("imb_savepng: Cannot png_create_info_struct for file: '%s'\n", name); return 0; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); printf("imb_savepng: Cannot setjmp for file: '%s'\n", name); return 0; } // copy image data pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels"); if (pixels == NULL) { png_destroy_write_struct(&png_ptr, &info_ptr); printf("imb_savepng: Cannot allocate pixels array of %dx%d, %d bytes per pixel for file: '%s'\n", ibuf->x, ibuf->y, bytesperpixel, name); return 0; } from = (unsigned char *) ibuf->rect; to = pixels; switch (bytesperpixel) { case 4: color_type = PNG_COLOR_TYPE_RGBA; for (i = ibuf->x * ibuf->y; i > 0; i--) { to[0] = from[0]; to[1] = from[1]; to[2] = from[2]; to[3] = from[3]; to += 4; from += 4; } break; case 3: color_type = PNG_COLOR_TYPE_RGB; for (i = ibuf->x * ibuf->y; i > 0; i--) { to[0] = from[0]; to[1] = from[1]; to[2] = from[2]; to += 3; from += 4; } break; case 1: color_type = PNG_COLOR_TYPE_GRAY; for (i = ibuf->x * ibuf->y; i > 0; i--) { to[0] = from[0]; to++; from += 4; } break; } if (flags & IB_mem) { // create image in memory imb_addencodedbufferImBuf(ibuf); ibuf->encodedsize = 0; png_set_write_fn(png_ptr, (png_voidp) ibuf, WriteData, Flush); } else { fp = fopen(name, "wb"); if (!fp) { png_destroy_write_struct(&png_ptr, &info_ptr); MEM_freeN(pixels); printf("imb_savepng: Cannot open file for writing: '%s'\n", name); return 0; } png_init_io(png_ptr, fp); } /* png_set_filter(png_ptr, 0, PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE | PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB | PNG_FILTER_UP | PNG_FILTER_VALUE_UP | PNG_FILTER_AVG | PNG_FILTER_VALUE_AVG | PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH| PNG_ALL_FILTERS); */ png_set_compression_level(png_ptr, compression); // png image settings png_set_IHDR(png_ptr, info_ptr, ibuf->x, ibuf->y, 8, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); /* image text info */ if (ibuf->metadata) { png_text* metadata; ImMetaData* iptr; int num_text = 0; iptr = ibuf->metadata; while (iptr) { num_text++; iptr = iptr->next; } metadata = MEM_callocN(num_text*sizeof(png_text), "png_metadata"); iptr = ibuf->metadata; num_text = 0; while (iptr) { metadata[num_text].compression = PNG_TEXT_COMPRESSION_NONE; metadata[num_text].key = iptr->key; metadata[num_text].text = iptr->value; num_text++; iptr = iptr->next; } png_set_text(png_ptr, info_ptr, metadata, num_text); MEM_freeN(metadata); } if(ibuf->ppm[0] > 0.0 && ibuf->ppm[1] > 0.0) { png_set_pHYs(png_ptr, info_ptr, (unsigned int)(ibuf->ppm[0] + 0.5), (unsigned int)(ibuf->ppm[1] + 0.5), PNG_RESOLUTION_METER); } // write the file header information png_write_info(png_ptr, info_ptr); // allocate memory for an array of row-pointers row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers"); if (row_pointers == NULL) { printf("imb_savepng: Cannot allocate row-pointers array for file '%s'\n", name); png_destroy_write_struct(&png_ptr, &info_ptr); MEM_freeN(pixels); if (fp) { fclose(fp); } return 0; } // set the individual row-pointers to point at the correct offsets for (i = 0; i < ibuf->y; i++) { row_pointers[ibuf->y-1-i] = (png_bytep) ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char)); } // write out the entire image data in one call png_write_image(png_ptr, row_pointers); // write the additional chunks to the PNG file (not really needed) png_write_end(png_ptr, info_ptr); // clean up MEM_freeN(pixels); MEM_freeN(row_pointers); png_destroy_write_struct(&png_ptr, &info_ptr); if (fp) { fflush(fp); fclose(fp); } return(1); }
// this code is heavily adapted from the paint license, which is in // the file paint.license (BSD compatible) included in this // distribution. TODO, add license file to MANIFEST.in and CVS Py::Object _png_module::write_png(const Py::Tuple& args) { args.verify_length(4, 5); FILE *fp = NULL; bool close_file = false; bool close_dup_file = false; Py::Object buffer_obj = Py::Object(args[0]); PyObject* buffer = buffer_obj.ptr(); if (!PyObject_CheckReadBuffer(buffer)) { throw Py::TypeError("First argument must be an rgba buffer."); } const void* pixBufferPtr = NULL; Py_ssize_t pixBufferLength = 0; if (PyObject_AsReadBuffer(buffer, &pixBufferPtr, &pixBufferLength)) { throw Py::ValueError("Couldn't get data from read buffer."); } png_byte* pixBuffer = (png_byte*)pixBufferPtr; int width = (int)Py::Int(args[1]); int height = (int)Py::Int(args[2]); if (pixBufferLength < width * height * 4) { throw Py::ValueError("Buffer and width, height don't seem to match."); } Py::Object py_fileobj = Py::Object(args[3]); PyObject* py_file = NULL; if (py_fileobj.isString()) { if ((py_file = npy_PyFile_OpenFile(py_fileobj.ptr(), (char *)"wb")) == NULL) { throw Py::Exception(); } close_file = true; } else { py_file = py_fileobj.ptr(); } if ((fp = npy_PyFile_Dup(py_file, (char *)"wb"))) { close_dup_file = true; } else { PyErr_Clear(); PyObject* write_method = PyObject_GetAttrString( py_file, "write"); if (!(write_method && PyCallable_Check(write_method))) { Py_XDECREF(write_method); throw Py::TypeError( "Object does not appear to be a 8-bit string path or " "a Python file-like object"); } Py_XDECREF(write_method); } png_bytep *row_pointers = NULL; png_structp png_ptr = NULL; png_infop info_ptr = NULL; try { struct png_color_8_struct sig_bit; png_uint_32 row; row_pointers = new png_bytep[height]; for (row = 0; row < (png_uint_32)height; ++row) { row_pointers[row] = pixBuffer + row * width * 4; } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { throw Py::RuntimeError("Could not create write struct"); } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { throw Py::RuntimeError("Could not create info struct"); } if (setjmp(png_jmpbuf(png_ptr))) { throw Py::RuntimeError("Error building image"); } if (fp) { png_init_io(png_ptr, fp); } else { png_set_write_fn(png_ptr, (void*)py_file, &write_png_data, &flush_png_data); } 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); // Save the dpi of the image in the file if (args.size() == 5) { double dpi = Py::Float(args[4]); size_t dots_per_meter = (size_t)(dpi / (2.54 / 100.0)); png_set_pHYs(png_ptr, info_ptr, dots_per_meter, dots_per_meter, PNG_RESOLUTION_METER); } // this a a color image! sig_bit.gray = 0; sig_bit.red = 8; sig_bit.green = 8; sig_bit.blue = 8; /* if the image has an alpha channel then */ sig_bit.alpha = 8; png_set_sBIT(png_ptr, info_ptr, &sig_bit); png_write_info(png_ptr, info_ptr); png_write_image(png_ptr, row_pointers); png_write_end(png_ptr, info_ptr); } catch (...) { if (png_ptr && info_ptr) { png_destroy_write_struct(&png_ptr, &info_ptr); } delete [] row_pointers; if (close_dup_file) { if (npy_PyFile_DupClose(py_file, fp)) { throw Py::RuntimeError("Error closing dupe file handle"); } } if (close_file) { npy_PyFile_CloseFile(py_file); Py_DECREF(py_file); } /* Changed calls to png_destroy_write_struct to follow http://www.libpng.org/pub/png/libpng-manual.txt. This ensures the info_ptr memory is released. */ throw; } png_destroy_write_struct(&png_ptr, &info_ptr); delete [] row_pointers; if (close_dup_file) { if (npy_PyFile_DupClose(py_file, fp)) { throw Py::RuntimeError("Error closing dupe file handle"); } } if (close_file) { npy_PyFile_CloseFile(py_file); Py_DECREF(py_file); } if (PyErr_Occurred()) { throw Py::Exception(); } else { return Py::Object(); } }
int IMG_SavePNG_RW(SDL_RWops *src, SDL_Surface *surf,int compression){ png_structp png_ptr; png_infop info_ptr; SDL_PixelFormat *fmt=NULL; SDL_Surface *tempsurf=NULL; int ret,funky_format; unsigned int i; png_colorp palette; Uint8 *palette_alpha=NULL; png_byte **row_pointers=NULL; png_ptr=NULL;info_ptr=NULL;palette=NULL;ret=-1; funky_format=0; SDL_BlendMode temp_blend; if( !src || !surf) { goto savedone; /* Nothing to do. */ } row_pointers=(png_byte **)malloc(surf->h * sizeof(png_byte*)); if (!row_pointers) { SDL_SetError("Couldn't allocate memory for rowpointers"); goto savedone; } png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL,NULL); if (!png_ptr){ SDL_SetError("Couldn't allocate memory for PNG file"); goto savedone; } info_ptr= png_create_info_struct(png_ptr); if (!info_ptr){ SDL_SetError("Couldn't allocate image information for PNG file"); goto savedone; } /* setup custom writer functions */ png_set_write_fn(png_ptr,(png_voidp)src,png_write_data,NULL); if (setjmp(png_jmpbuf(png_ptr))){ SDL_SetError("Unknown error writing PNG"); goto savedone; } if(compression>Z_BEST_COMPRESSION) compression=Z_BEST_COMPRESSION; if(compression == Z_NO_COMPRESSION) // No compression { png_set_filter(png_ptr,0,PNG_FILTER_NONE); png_set_compression_level(png_ptr,Z_NO_COMPRESSION); } else if(compression<0) // Default compression png_set_compression_level(png_ptr,Z_DEFAULT_COMPRESSION); else png_set_compression_level(png_ptr,compression); fmt=surf->format; if(fmt->BitsPerPixel==8){ /* Paletted */ png_set_IHDR(png_ptr,info_ptr, surf->w,surf->h,8,PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); palette=(png_colorp) malloc(fmt->palette->ncolors * sizeof(png_color)); if (!palette) { SDL_SetError("Couldn't create memory for palette"); goto savedone; } for (i=0;i<fmt->palette->ncolors;i++) { palette[i].red=fmt->palette->colors[i].r; palette[i].green=fmt->palette->colors[i].g; palette[i].blue=fmt->palette->colors[i].b; } png_set_PLTE(png_ptr,info_ptr,palette,fmt->palette->ncolors); // if (surf->flags&SDL_SRCCOLORKEY) { // palette_alpha=(Uint8 *)malloc((fmt->colorkey+1)*sizeof(Uint8)); // if (!palette_alpha) { // SDL_SetError("Couldn't create memory for palette transparency"); // goto savedone; // } // /* FIXME: memset? */ // for (i=0;i<(fmt->colorkey+1);i++) { // palette_alpha[i]=255; // } // palette_alpha[fmt->colorkey]=0; // png_set_tRNS(png_ptr,info_ptr,palette_alpha,fmt->colorkey+1,NULL); // } }else{ /* Truecolor */ if (fmt->Amask) { png_set_IHDR(png_ptr,info_ptr, surf->w,surf->h,8,PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); } else { png_set_IHDR(png_ptr,info_ptr, surf->w,surf->h,8,PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); } } png_write_info(png_ptr, info_ptr); if (fmt->BitsPerPixel==8) { /* Paletted */ for(i=0;i<surf->h;i++){ row_pointers[i]= ((png_byte*)surf->pixels) + i*surf->pitch; } if(SDL_MUSTLOCK(surf)){ SDL_LockSurface(surf); } png_write_image(png_ptr, row_pointers); if(SDL_MUSTLOCK(surf)){ SDL_UnlockSurface(surf); } }else{ /* Truecolor */ if(fmt->BytesPerPixel==3){ if(fmt->Amask){ /* check for 24 bit with alpha */ funky_format=1; }else{ /* Check for RGB/BGR/GBR/RBG/etc surfaces.*/ #if SDL_BYTEORDER == SDL_BIG_ENDIAN if(fmt->Rmask!=0xFF0000 || fmt->Gmask!=0x00FF00 || fmt->Bmask!=0x0000FF){ #else if(fmt->Rmask!=0x0000FF || fmt->Gmask!=0x00FF00 || fmt->Bmask!=0xFF0000){ #endif funky_format=1; } } }else if (fmt->BytesPerPixel==4){ if (!fmt->Amask) { /* check for 32bit but no alpha */ funky_format=1; }else{ /* Check for ARGB/ABGR/GBAR/RABG/etc surfaces.*/ #if SDL_BYTEORDER == SDL_BIG_ENDIAN if(fmt->Rmask!=0xFF000000 || fmt->Gmask!=0x00FF0000 || fmt->Bmask!=0x0000FF00 || fmt->Amask!=0x000000FF){ #else if(fmt->Rmask!=0x000000FF || fmt->Gmask!=0x0000FF00 || fmt->Bmask!=0x00FF0000 || fmt->Amask!=0xFF000000){ #endif funky_format=1; } } }else{ /* 555 or 565 16 bit color */ funky_format=1; } if (funky_format) { /* Allocate non-funky format, and copy pixeldata in*/ if(fmt->Amask){ #if SDL_BYTEORDER == SDL_BIG_ENDIAN tempsurf = SDL_CreateRGBSurface(SDL_SWSURFACE, surf->w, surf->h, 24, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff); #else tempsurf = SDL_CreateRGBSurface(SDL_SWSURFACE, surf->w, surf->h, 24, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); #endif }else{ #if SDL_BYTEORDER == SDL_BIG_ENDIAN tempsurf = SDL_CreateRGBSurface(SDL_SWSURFACE, surf->w, surf->h, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x00000000); #else tempsurf = SDL_CreateRGBSurface(SDL_SWSURFACE, surf->w, surf->h, 24, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000); #endif } if(!tempsurf){ SDL_SetError("Couldn't allocate temp surface"); goto savedone; } SDL_GetSurfaceBlendMode(surf, &temp_blend); SDL_SetSurfaceBlendMode(surf, SDL_BLENDMODE_NONE); if(SDL_BlitSurface(surf,NULL,tempsurf,NULL)!=0){ SDL_SetError("Couldn't blit surface to temp surface"); SDL_FreeSurface(tempsurf); goto savedone; } SDL_SetSurfaceBlendMode(surf, temp_blend); for(i=0;i<tempsurf->h;i++){ row_pointers[i]= ((png_byte*)tempsurf->pixels) + i*tempsurf->pitch; } if(SDL_MUSTLOCK(tempsurf)){ SDL_LockSurface(tempsurf); } png_write_image(png_ptr, row_pointers); if(SDL_MUSTLOCK(tempsurf)){ SDL_UnlockSurface(tempsurf); } SDL_FreeSurface(tempsurf); } else { for(i=0;i<surf->h;i++){ row_pointers[i]= ((png_byte*)surf->pixels) + i*surf->pitch; } if(SDL_MUSTLOCK(surf)){ SDL_LockSurface(surf); } png_write_image(png_ptr, row_pointers); if(SDL_MUSTLOCK(surf)){ SDL_UnlockSurface(surf); } } } png_write_end(png_ptr, NULL); ret=0; /* got here, so nothing went wrong. YAY! */ savedone: /* clean up and return */ png_destroy_write_struct(&png_ptr,&info_ptr); if (palette) { free(palette); } if (palette_alpha) { free(palette_alpha); } if (row_pointers) { free(row_pointers); } return ret; }
bool ImageMemory::SaveImage(const std::string &filename) { if(pixels == NULL) { IF_PRINT_WARNING(VIDEO_DEBUG) << "pixels member was NULL upon function invocation for file: " << filename << std::endl; return false; } // 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; } // 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, (png_infopp)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, (png_infopp)NULL); fclose(fp); return false; } // tell it where to look png_init_io(png_ptr, fp); // write the header int32 color_type = rgb_format ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA; png_set_IHDR(png_ptr, info_ptr, width, height, 8, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_write_info(png_ptr, info_ptr); png_set_packing(png_ptr); // get the row array from our data png_bytep *row_pointers = new png_bytep[height]; if(!row_pointers) { IF_PRINT_WARNING(VIDEO_DEBUG) << "Couldn't allocate png row_pointers for: " << filename << std::endl; png_destroy_write_struct(&png_ptr, (png_infopp)NULL); fclose(fp); return false; } int32 bytes_per_row = rgb_format ? width * 3 : width * 4; for(uint32 i = 0; i < height; ++i) { row_pointers[i] = (png_bytep)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); fclose(fp); // free the memory delete[] row_pointers; png_destroy_write_struct(&png_ptr, (png_infopp)NULL); return true; } // bool ImageMemory::SaveImage(const std::string& filename)
void Openchunk::run() { png_structp png_ptr_read; png_infop info_ptr_read; png_structp png_ptr_write; png_infop info_ptr_write; png_uint_32 next_frame_width; png_uint_32 next_frame_height; png_uint_32 next_frame_x_offset; png_uint_32 next_frame_y_offset; png_uint_16 next_frame_delay_num; png_uint_16 next_frame_delay_den; png_byte next_frame_dispose_op; png_byte next_frame_blend_op; png_color_16p Framebg; framlist.clear(); buffer = new StreamFile(); buffer->LoadFile(subfile); qDebug() << "### start read ->" << subfile; if (!buffer->isValid()) { alert("unvalid buffer fill",__LINE__); exit(0); } validpng = buffer->device()->peek(4).contains("PNG"); qDebug() << "### ahed ->" << validpng; frame1.loadFromData(buffer->stream()); /* load first frame */ if (frame1.isNull()) { alert("unable find a valid image",__LINE__); return; } png_ptr_read = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(png_ptr_read == NULL) { alert("unable to create read struct",__LINE__); return; } info_ptr_read = png_create_info_struct(png_ptr_read); if(info_ptr_read == NULL) { alert("unable to create info struct",__LINE__); return; } png_set_read_fn(png_ptr_read,buffer,EncoderReaderCallback); if(setjmp(png_ptr_read->jmpbuf)) { alert("something didn't work, jump 1",__LINE__); return; } png_read_info(png_ptr_read, info_ptr_read); if(!png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_acTL)) { alert("source image must be animated",__LINE__); return; } QRect Frect(0,0,info_ptr_read->width,info_ptr_read->height); ////////////qDebug() << "### Frame rect from head ->" << Frect; QImage master(Frect.width(),Frect.height(),QImage::Format_ARGB32); const uint height = master.height(); png_bytep *row_pointers = new png_bytep[height]; for (uint i = 0; i < height; ++i) { row_pointers[i] = (png_bytep)master.scanLine(i); } int validloop = -1; for(int i = 0; i < png_get_num_frames(png_ptr_read, info_ptr_read); i++) { /////////qDebug() << "### frame read ------------- " << i; png_ptr_write = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(png_ptr_write == NULL) { alert("unable to create write struct"); return; } StreamFile *framer = new StreamFile(); png_set_write_fn(png_ptr_write,framer,EncoderWriteCallback, NULL); info_ptr_write = png_create_info_struct(png_ptr_write); if(info_ptr_write == NULL) { alert("unable to create write struct"); return; } if(setjmp(png_ptr_write->jmpbuf)) { alert("something didn't work, jump 2"); return; } png_read_frame_head(png_ptr_read, info_ptr_read); if(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_fcTL)) { png_get_next_frame_fcTL(png_ptr_read, info_ptr_read, &next_frame_width, &next_frame_height, &next_frame_x_offset, &next_frame_y_offset, &next_frame_delay_num, &next_frame_delay_den, &next_frame_dispose_op, &next_frame_blend_op); } else { /* the first frame doesn't have an fcTL so it's expected to be hidden, * but we'll extract it anyway next_frame_x_offset , next_frame_y_offset */ next_frame_width = png_get_image_width(png_ptr_read, info_ptr_read); next_frame_height = png_get_image_height(png_ptr_read, info_ptr_read); } QRect C_frame_rect(0,0,next_frame_width,next_frame_height); AFRAMES FrameInfo = OneFrameReader(png_ptr_read, info_ptr_read, png_ptr_write, info_ptr_write, next_frame_width, next_frame_height); png_write_info(png_ptr_write, info_ptr_write); png_read_image(png_ptr_read, row_pointers); png_write_image(png_ptr_write, row_pointers); png_write_end(png_ptr_write, NULL); float Fraction = (float)next_frame_delay_num / (float)next_frame_delay_den + 0.00; ////////qDebug() << "### Fraction " << Fraction; int PlayGo; if (Fraction < 0.001 ) { PlayGo = 100; } else if (Fraction < 1.010 && Fraction > 0.9) { PlayGo = 1000; } else { PlayGo = Fraction * 1000; } /* extract frames */ if ( framer->isValid() && Frect.contains(C_frame_rect) ) { validloop++; int Coalpha = 255; /* prepare image if no background find grab a pixel color! */ QImage tmpgd(C_frame_rect.width(),C_frame_rect.height(),QImage::Format_ARGB32); /* compose it files */ APNGFRAME one; one.dimg = framer->stream(); one.maxframe = Frect; one.pos = validloop; one.point = QPoint(next_frame_x_offset,next_frame_y_offset); one.play = PlayGo; if (!(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_bKGD))) { tmpgd.loadFromData(one.dimg); QRgb GrepColor = tmpgd.pixel(QPoint(2,2)); one.bg = QColor(GrepColor); one.bg.setAlpha(qAlpha(GrepColor)); Coalpha = qAlpha(GrepColor); } else { one.bg = FrameInfo.bg; } QImage tmpe; QImage Pvidi(one.maxframe.width(),one.maxframe.height(),QImage::Format_ARGB32); if (tmpe.loadFromData(one.dimg)) { QPainter p(&Pvidi); p.setRenderHint(QPainter::Antialiasing, true); p.setBrush(one.bg); p.drawRect(Pvidi.rect()); p.drawImage(one.point,tmpe); p.end(); one.item = Pvidi; ////qDebug() << "### isNull() in theard .." << one.item.isNull(); } //////item tmpe //////qDebug() << "### Frame rect ->" << one.point << ",nr." << validloop << "C." << one.bg.name() << "Al." << Coalpha; framlist.insert(validloop,one); } framer->~StreamFile(); png_ptr_write = 0; info_ptr_write = 0; } qDebug() << "### Frame size() ->" << framlist.size(); //////alert("end of chunks",__LINE__); validpng = true; buffer->~StreamFile(); exit(0); }
/* save rgb888 to png format in fp */ int save_png(const char* path, const char* data, int width, int height) { FILE *fp; png_byte **volatile rows; png_struct *png; png_info *info; fp = fopen(path, "w"); if (!fp) { int errsv = errno; E("Cannot open file %s for writing.\n", path); return errsv; } rows = malloc(height * sizeof rows[0]); if (!rows) goto oops; int i; for (i = 0; i < height; i++) rows[i] = (png_byte *) data + i * width * 3 /*fb.stride*/; png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, png_simple_error_callback, png_simple_warning_callback); if (!png) { E("png_create_write_struct failed\n"); goto oops; } info = png_create_info_struct (png); if (!info) { E("png_create_info_struct failed\n"); png_destroy_write_struct (&png, NULL); goto oops; } png_set_write_fn (png, fp, stdio_write_func, png_simple_output_flush_fn); png_set_IHDR (png, info, width, height, #define DEPTH 8 DEPTH, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_color_16 white; white.gray = (1 << DEPTH) - 1; white.red = white.blue = white.green = white.gray; png_set_bKGD (png, info, &white); png_write_info (png, info); png_write_image (png, rows); png_write_end (png, info); png_destroy_write_struct (&png, &info); fclose(fp); free (rows); return 0; oops: fclose(fp); free (rows); return -1; }
int write_png(struct image image, char *filename) { int rc = 0, i = 0, x = 0, y = 0, width = 0, height = 0; unsigned char *data = NULL; FILE *file = NULL; png_byte color_type, bit_depth; png_structp png_ptr; png_infop info_ptr; png_bytep *row_pointers; file = fopen(filename, "wb"); if (!file) { printf("Could not open %s\n", filename); rc = 1; goto cleanup; } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { printf("png_create_write_struct failed\n"); rc = 1; goto cleanup; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { printf("png_create_info_struct failed\n"); rc = 1; goto cleanup; } if (setjmp(png_jmpbuf(png_ptr))) { printf("Error initializing write\n"); rc = 1; goto cleanup; } png_init_io(png_ptr, file); if (setjmp(png_jmpbuf(png_ptr))) { printf("Error writing header\n"); rc = 1; goto cleanup; } data = image.data; width = image.width; height = image.height; color_type = 2; bit_depth = 8; 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); row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height + 1); for (y = 0; y < height; y++) { row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png_ptr, info_ptr) + 1); } for (y = 0, i = 0; y < height; y++) { png_byte *row = row_pointers[y]; for (x = 0; x < width; x++) { png_byte *rgb = &(row[x * 3]); rgb[0] = data[i++]; rgb[1] = data[i++]; rgb[2] = data[i++]; } } png_write_image(png_ptr, row_pointers); if (setjmp(png_jmpbuf(png_ptr))) { printf("Error ending write\n"); rc = 1; goto cleanup; } png_write_end(png_ptr, NULL); cleanup: if (file) { fclose(file); } return rc; }
ImageIO::errorType ImageIO::savePNG(const char * filename) { #ifdef ENABLE_PNG FILE *file = fopen(filename, "wb"); if (!file) { printf("Error in savePNG: Cannot open file %s.\n", filename); return IO_ERROR; } png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { printf("Error in savePNG: Creating the internal structure failed.\n"); fclose(file); return (IO_ERROR); } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); printf("Error in savePNG: Creating the information structure failed.\n"); fclose(file); return (IO_ERROR); } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); fclose(file); printf("Error in savePNG: cannot setup the error handling.\n"); return (IO_ERROR); } // setup the output png_init_io(png_ptr, file); if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); fclose(file); printf("Error in savePNG: cannot write the png header.\n"); return (IO_ERROR); } int bit_depth = BITS_PER_CHANNEL_8; // currently we only support 8 bits per channel int color_type; switch(bytesPerPixel) { case IMAGE_IO_RGB: color_type = PNG_COLOR_TYPE_RGB; break; case IMAGE_IO_RGB_ALPHA: color_type = PNG_COLOR_TYPE_RGB_ALPHA; break; default: png_destroy_write_struct(&png_ptr, &info_ptr); printf("Error in savePNG: cannot handle bytesPerPixel that is not 3 or 4.\n"); return OTHER_ERROR; break; } png_set_IHDR(png_ptr, info_ptr, (png_uint_32)width, (png_uint_32)height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_write_info(png_ptr, info_ptr); if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); fclose(file); printf("Error in savePNG: cannot write the png file.\n"); return (IO_ERROR); } unsigned int bytesPerRow = bytesPerPixel * width; png_bytep * row_pointers = (png_bytep*) malloc (sizeof(png_bytep) * height); for(unsigned int row = 0; row < height; row++) row_pointers[row] = (png_byte*)(&pixels[(height - row - 1) * bytesPerRow]); png_write_image(png_ptr, row_pointers); free(row_pointers); if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); fclose(file); printf("Error in savePNG: unknown error occurred during end of file.\n"); return (IO_ERROR); } png_write_end(png_ptr, NULL); png_destroy_write_struct(&png_ptr, &info_ptr); fclose(file); return OK; #else return INVALID_FILE_FORMAT; #endif }
static Bool writePng (unsigned char *buffer, png_rw_ptr writeFunc, void *closure, int width, int height, int stride) { png_struct *png; png_info *info; png_byte **rows; png_color_16 white; int i; rows = malloc (height * sizeof (png_byte *)); if (!rows) return FALSE; for (i = 0; i < height; i++) rows[height - i - 1] = buffer + i * stride; png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png) { free (rows); return FALSE; } info = png_create_info_struct (png); if (!info) { png_destroy_read_struct (&png, NULL, NULL); free (rows); return FALSE; } if (setjmp (png_jmpbuf (png))) { png_destroy_read_struct (&png, NULL, NULL); free (rows); return FALSE; } png_set_write_fn (png, closure, writeFunc, NULL); png_set_IHDR (png, info, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); white.red = 0xff; white.blue = 0xff; white.green = 0xff; png_set_bKGD (png, info, &white); png_write_info (png, info); png_write_image (png, rows); png_write_end (png, info); png_destroy_write_struct (&png, &info); free (rows); return TRUE; }
BMMRES BitmapIO_PNG::Save(const TCHAR *filename, Bitmap *map) { if(!map) return(ProcessImageIOError(&bi,BMMRES_INTERNALERROR)); openMode = BMM_OPEN_W; if((ostream = _tfopen(filename,_T("wb"))) == NULL) return (ProcessImageIOError(&bi)); BitmapStorage *palettedStorage = NULL; png = png_create_write_struct (PNG_VERSION, (void *) this, error_func, warning_func); if (setjmp(png->jmpbuf)) { if (info) for (png_uint_32 i = 0; i < info->height; i++) if (row_pointers[i]) free(row_pointers[i]); if (row_pointers) { free(row_pointers); row_pointers = NULL; } if (palettedStorage) delete palettedStorage; fclose(ostream); _tremove(filename); png_destroy_write_struct (&png, &info); return BMMRES_IOERROR; } info = png_create_info_struct(png); png_init_io(png, ostream); switch(cfg.color_type) { case PngPalette: info->color_type = PNG_COLOR_TYPE_PALETTE; info->pixel_depth = 8; info->valid |= PNG_INFO_PLTE; info->num_palette = 256; break; case PngRGB: info->color_type = PNG_COLOR_TYPE_RGB; break; case PngRGBA: info->color_type = PNG_COLOR_TYPE_RGB_ALPHA; break; case PngGray: info->color_type = PNG_COLOR_TYPE_GRAY; break; case PngGrayA: info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break; } info->width = map->Width(); info->height = map->Height(); if (OutputGamma() != 1.0f) { info->valid |= PNG_INFO_gAMA; info->gamma = OutputGamma(); } else info->gamma = 1.0f; if (map->Aspect() != 1.0f) { info->valid |= PNG_INFO_pHYs; info->x_pixels_per_unit = (png_uint_32)(1024.0f * map->Aspect()); info->y_pixels_per_unit = 1024; info->phys_unit_type = 0; } if (cfg.interlaced) info->interlace_type = 1; else info->interlace_type = 0; switch( info->color_type) { case PNG_COLOR_TYPE_PALETTE: case PNG_COLOR_TYPE_GRAY: info->channels = 1; break; case PNG_COLOR_TYPE_GRAY_ALPHA: info->channels = 2; break; case PNG_COLOR_TYPE_RGB: info->channels = 3; break; case PNG_COLOR_TYPE_RGB_ALPHA: info->channels = 4; break; } info->bit_depth = cfg.bitdepth; info->rowbytes = info->width * info->channels * info->bit_depth / 8; row_pointers = (png_bytep *)malloc(info->height * sizeof(png_bytep)); for (png_uint_32 i = 0; i < info->height; i++) row_pointers[i] = (png_bytep)malloc(info->rowbytes); switch (info->bit_depth) { case 16: // this is only RGB/RGBA/Gray/GrayA switch(info->color_type) { case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: { BMM_Color_64 *line64 = (BMM_Color_64 *) calloc(info->width,sizeof(BMM_Color_64)); for (png_uint_32 iy = 0; iy < info->height; ++iy) { if (GetOutputPixels(0, iy, info->width, line64) != 1) { for (png_uint_32 i = 0; i < info->height; i++) if (row_pointers[i]) free(row_pointers[i]); if (row_pointers) { free(row_pointers); row_pointers = NULL; } fclose(ostream); _tremove(filename); free(line64); png_destroy_write_struct (&png, &info); return BMMRES_IOERROR; } BMM_Color_64 *l64=line64; unsigned short *oshort = (unsigned short *)row_pointers[iy]; for (png_uint_32 ix = 0; ix < info->width; ++l64, ix++) { *oshort = (unsigned short)l64->r; oshort++; *oshort = (unsigned short)l64->g; oshort++; *oshort = (unsigned short)l64->b; oshort++; if (info->channels == 4) { *oshort = (unsigned short)l64->a; oshort++; } } } free(line64); } break; case PNG_COLOR_TYPE_GRAY: { for (png_uint_32 iy = 0; iy < info->height; ++iy) if (map->Get16Gray(0, iy, info->width, (unsigned short *)row_pointers[iy]) != 1) { for (png_uint_32 i = 0; i < info->height; i++) if (row_pointers[i]) free(row_pointers[i]); if (row_pointers) { free(row_pointers); row_pointers = NULL; } fclose(ostream); _tremove(filename); png_destroy_write_struct (&png, &info); return BMMRES_IOERROR; } } break; case PNG_COLOR_TYPE_GRAY_ALPHA: { BMM_Color_64 *line64 = (BMM_Color_64 *) calloc(info->width, sizeof(BMM_Color_64)); unsigned short *line = (unsigned short *) calloc(info->width, sizeof(unsigned short)); for (png_uint_32 iy = 0; iy < info->height; ++iy) { if (GetOutputPixels(0, iy, info->width, line64) != 1 || map->Get16Gray(0, iy, info->width, line) != 1) { for (png_uint_32 i = 0; i < info->height; i++) if (row_pointers[i]) free(row_pointers[i]); if (row_pointers) { free(row_pointers); row_pointers = NULL; } free(line64); free(line); fclose(ostream); _tremove(filename); png_destroy_write_struct (&png, &info); return BMMRES_IOERROR; } BMM_Color_64 *l64 = line64; unsigned short *l=line; unsigned short *oshort = (unsigned short *)row_pointers[iy]; for (png_uint_32 ix = 0; ix < info->width; ix++, l64++) { *oshort++ = *l++; *oshort++ = (unsigned short)l64->a; } } free(line64); free(line); } break; } break; case 8: // this can be any type switch(info->color_type) { case PNG_COLOR_TYPE_PALETTE: { // Set up a palette buffer PixelBuf48 palettebuf(info->num_palette); BMM_Color_48 *pal = palettebuf.Ptr(); // Must compute a color palette, and reduce the image to 256 colors! // this calculates a palette based on the gamma corrected values, which // corresponds to what GetOutputPixels returns. if(CalcOutputPalette(256, pal) == 0) { for (png_uint_32 i = 0; i < info->height; i++) if (row_pointers[i]) free(row_pointers[i]); if (row_pointers) { free(row_pointers); row_pointers = NULL; } fclose(ostream); _tremove(filename); png_destroy_write_struct (&png, &info); return BMMRES_IOERROR; } info->palette = (png_color *)malloc(info->num_palette * sizeof(png_color)); for (int i = 0; i < info->num_palette; i++) { info->palette[i].red = (unsigned char)(pal[i].r >> 8); info->palette[i].green = (unsigned char)(pal[i].g >> 8); info->palette[i].blue = (unsigned char)(pal[i].b >> 8); } PixelBuf64 line(info->width); ColorPacker* cpack = BMMNewColorPacker(info->width, pal, info->num_palette); for (png_uint_32 iy=0; iy < info->height; ++iy) { if(!GetOutputPixels(0, iy, info->width, line.Ptr())) { for (png_uint_32 i = 0; i < info->height; i++) if (row_pointers[i]) free(row_pointers[i]); if (row_pointers) { free(row_pointers); row_pointers = NULL; } fclose(ostream); _tremove(filename); png_destroy_write_struct (&png, &info); return BMMRES_IOERROR; } cpack->PackLine(line.Ptr(), row_pointers[iy], info->width); } cpack->DeleteThis(); } break; case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: { BMM_Color_32 *line32 = (BMM_Color_32 *) calloc(info->width,sizeof(BMM_Color_32)); for (png_uint_32 iy = 0; iy < info->height; ++iy) { if (GetDitheredOutputPixels(0, iy, info->width, line32) != 1) { for (png_uint_32 i = 0; i < info->height; i++) if (row_pointers[i]) free(row_pointers[i]); if (row_pointers) { free(row_pointers); row_pointers = NULL; } fclose(ostream); _tremove(filename); free(line32); png_destroy_write_struct (&png, &info); return BMMRES_IOERROR; } BMM_Color_32 *l32=line32; unsigned char *obyte = (unsigned char *)row_pointers[iy]; for (png_uint_32 ix = 0; ix < info->width; ++l32, ix++) { *obyte = (unsigned char)l32->r; obyte++; *obyte = (unsigned char)l32->g; obyte++; *obyte = (unsigned char)l32->b; obyte++; if (info->channels == 4) { *obyte = (unsigned char)l32->a; obyte++; } } } free(line32); } break; case PNG_COLOR_TYPE_GRAY: { unsigned short *line = (unsigned short *) calloc(info->width * info->channels, sizeof(unsigned short)); for (png_uint_32 iy = 0; iy < info->height; ++iy) { if (map->Get16Gray(0, iy, info->width, line) != 1) { for (png_uint_32 i = 0; i < info->height; i++) if (row_pointers[i]) free(row_pointers[i]); if (row_pointers) { free(row_pointers); row_pointers = NULL; } fclose(ostream); _tremove(filename); free(line); png_destroy_write_struct (&png, &info); return BMMRES_IOERROR; } unsigned short *l=line; unsigned char *obyte = (unsigned char *)row_pointers[iy]; for (png_uint_32 ix = 0; ix < info->width; ix++) { *obyte++ = (unsigned char)(*l >> 8); l++; } } free(line); } break; case PNG_COLOR_TYPE_GRAY_ALPHA: { BMM_Color_64 *line64 = (BMM_Color_64 *) calloc(info->width,sizeof(BMM_Color_64)); unsigned short *line = (unsigned short *) calloc(info->width, sizeof(unsigned short)); for (png_uint_32 iy = 0; iy < info->height; ++iy) { if (GetOutputPixels(0, iy, info->width, line64) != 1 || map->Get16Gray(0, iy, info->width, line) != 1) { for (png_uint_32 i = 0; i < info->height; i++) if (row_pointers[i]) free(row_pointers[i]); if (row_pointers) { free(row_pointers); row_pointers = NULL; } fclose(ostream); _tremove(filename); free(line); free(line64); png_destroy_write_struct (&png, &info); return BMMRES_IOERROR; } unsigned short *l=line; BMM_Color_64 *l64 = line64; unsigned char *obyte = (unsigned char *)row_pointers[iy]; for (png_uint_32 ix = 0; ix < info->width; ix++, l64++) { *obyte++ = (unsigned char)(*l >> 8); l++; *obyte++ = (unsigned char)(l64->a >> 8); } } free(line); free(line64); } break; } break; #ifdef OUTPUT_1_2_4 case 4: { // Paletted only } break; case 2: { // Paletted only } break; case 1: { // Paletted only } #endif break; } png_write_info(png, info); png_set_swap(png); png_write_image(png, row_pointers); png_write_end(png, info); fclose(ostream); for (i = 0; i < info->height; i++) free(row_pointers[i]); free(row_pointers); png_destroy_write_struct (&png, &info); return BMMRES_SUCCESS; }
int write_RGBA_to_png(uint16_t width, uint16_t height, uint8_t * array, const char * filename) { int x, y; png_structp png_ptr; png_infop info_ptr; png_bytep * row_pointers; FILE * fp = fopen(filename, "wb"); if(fp == NULL) return 0; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info_ptr = png_create_info_struct(png_ptr); PNGSETJMP png_init_io(png_ptr, fp); PNGSETJMP 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_write_info(png_ptr, info_ptr); /* write bytes */ PNGSETJMP /* convert uint8_t[] to pngbyte[][] */ row_pointers = malloc(sizeof(*row_pointers) * height); for(y = 0;y < height;y++) { row_pointers[y] = malloc(png_get_rowbytes(png_ptr, info_ptr)); for(x = 0;x < width * 4;x += 4) { row_pointers[y][x] = array[y * width * 4 + x]; row_pointers[y][x+1] = array[y * width * 4 + x+1]; row_pointers[y][x+2] = array[y * width * 4 + x+2]; row_pointers[y][x+3] = array[y * width * 4 + x+3]; } } png_write_image(png_ptr, row_pointers); /* end write */ PNGSETJMP png_write_end(png_ptr, NULL); png_destroy_write_struct(&png_ptr, &info_ptr); for(y = 0;y < height;y++) { free(row_pointers[y]); } free(row_pointers); fclose(fp); return 1; }
bool CCImage::_saveImageToPNG(const char * pszFilePath, bool bIsToRGB) { bool bRet = false; do { CC_BREAK_IF(NULL == pszFilePath); FILE *fp; png_structp png_ptr; png_infop info_ptr; png_colorp palette; png_bytep *row_pointers; fp = fopen(pszFilePath, "wb"); CC_BREAK_IF(NULL == fp); png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (NULL == png_ptr) { fclose(fp); break; } info_ptr = png_create_info_struct(png_ptr); if (NULL == info_ptr) { fclose(fp); png_destroy_write_struct(&png_ptr, NULL); break; } if (setjmp(png_jmpbuf(png_ptr))) { fclose(fp); png_destroy_write_struct(&png_ptr, &info_ptr); break; } png_init_io(png_ptr, fp); if (!bIsToRGB && m_bHasAlpha) { png_set_IHDR(png_ptr, info_ptr, m_nWidth, m_nHeight, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); } else { png_set_IHDR(png_ptr, info_ptr, m_nWidth, m_nHeight, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); } palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof (png_color)); png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); png_write_info(png_ptr, info_ptr); png_set_packing(png_ptr); row_pointers = (png_bytep *)malloc(m_nHeight * sizeof(png_bytep)); if(row_pointers == NULL) { fclose(fp); png_destroy_write_struct(&png_ptr, &info_ptr); break; } if (!m_bHasAlpha) { for (int i = 0; i < (int)m_nHeight; i++) { row_pointers[i] = (png_bytep)m_pData + i * m_nWidth * 3; } png_write_image(png_ptr, row_pointers); free(row_pointers); row_pointers = NULL; } else { if (bIsToRGB) { unsigned char *pTempData = new unsigned char[m_nWidth * m_nHeight * 3]; if (NULL == pTempData) { fclose(fp); png_destroy_write_struct(&png_ptr, &info_ptr); break; } for (int i = 0; i < m_nHeight; ++i) { for (int j = 0; j < m_nWidth; ++j) { pTempData[(i * m_nWidth + j) * 3] = m_pData[(i * m_nWidth + j) * 4]; pTempData[(i * m_nWidth + j) * 3 + 1] = m_pData[(i * m_nWidth + j) * 4 + 1]; pTempData[(i * m_nWidth + j) * 3 + 2] = m_pData[(i * m_nWidth + j) * 4 + 2]; } } for (int i = 0; i < (int)m_nHeight; i++) { row_pointers[i] = (png_bytep)pTempData + i * m_nWidth * 3; } png_write_image(png_ptr, row_pointers); free(row_pointers); row_pointers = NULL; CC_SAFE_DELETE_ARRAY(pTempData); } else { for (int i = 0; i < (int)m_nHeight; i++) { row_pointers[i] = (png_bytep)m_pData + i * m_nWidth * 4; } png_write_image(png_ptr, row_pointers); free(row_pointers); row_pointers = NULL; } } png_write_end(png_ptr, info_ptr); png_free(png_ptr, palette); palette = NULL; png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); bRet = true; } while (0); return bRet; }
/* ****************************************************************** */ void WritePNG (double ***Vdbl, char *var_name, char *filename, Grid *grid) /* * * * * ******************************************************************** */ { int ic, ir, i; png_structp png_ptr; png_infop info_ptr; int backgroundcolour_; int bit_depth_; int colortype_; int compressionlevel_; int indx; double filegamma_; Image *png; unsigned char **image; FILE *fp; png = GetImage (var_name); SetColorMap (png->r, png->g, png->b, png->colormap); GetSlice (Vdbl, png, grid); if (prank != 0) return; image = (png_bytepp)malloc(png->nrow*sizeof(png_bytep)); for (ir = 0; ir < png->nrow; ir++) { image[ir] = (png_bytep)malloc(6*png->ncol*sizeof(png_byte)); } for(ic = 0; ic < png->ncol; ic++){ for(ir = 0; ir < png->nrow; ir++){ i = 6*ic; image[ir][i] = png->rgb[ir][ic].r; /* -- red -- */ image[ir][i+1] = 0; image[ir][i+2] = png->rgb[ir][ic].g; /* -- green -- */ image[ir][i+3] = 0; image[ir][i+4] = png->rgb[ir][ic].b; /* -- blue -- */ image[ir][i+5] = 0; }} /* -- write --- */ compressionlevel_ = 6; backgroundcolour_ = 0; bit_depth_ = 16; filegamma_ = 0.; colortype_ = 2.; fp = fopen(filename, "wb"); if(fp == NULL){ printf(" ! error opening file in writing data\n"); exit(1); } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info_ptr = png_create_info_struct(png_ptr); png_init_io(png_ptr, fp); /* if(compressionlevel_ != -2){ */ png_set_compression_level(png_ptr, compressionlevel_); /* } else { png_set_compression_level(png_ptr, PNGWRITER_DEFAULT_COMPRESSION); }*/ png_set_IHDR(png_ptr, info_ptr, png->ncol, png->nrow, bit_depth_, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); if(filegamma_ < 1.0e-1){ filegamma_ = 0.7; } png_set_gAMA(png_ptr, info_ptr, filegamma_); /* time_t gmt; png_time mod_time; png_text text_ptr[5]; time(&gmt); png_convert_from_time_t(&mod_time, gmt); png_set_tIME(png_ptr, info_ptr, &mod_time); */ png_write_info(png_ptr, info_ptr); png_write_image(png_ptr, image); png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); free((char *) image[0]); free((char *) image); }
int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) { png_structp png_ptr; png_infop info_ptr; unsigned char *pixels = NULL; unsigned char *from, *to; unsigned short *pixels16 = NULL, *to16; float *from_float, from_straight[4]; png_bytepp row_pointers = NULL; int i, bytesperpixel, color_type = PNG_COLOR_TYPE_GRAY; FILE *fp = NULL; bool is_16bit = (ibuf->ftype & PNG_16BIT) != 0; bool has_float = (ibuf->rect_float != NULL); int channels_in_float = ibuf->channels ? ibuf->channels : 4; float (*chanel_colormanage_cb)(float); /* use the jpeg quality setting for compression */ int compression; compression = (int)(((float)(ibuf->ftype & 0xff) / 11.1111f)); compression = compression < 0 ? 0 : (compression > 9 ? 9 : compression); if (ibuf->float_colorspace) { /* float buffer was managed already, no need in color space conversion */ chanel_colormanage_cb = channel_colormanage_noop; } else { /* standard linear-to-srgb conversion if float buffer wasn't managed */ chanel_colormanage_cb = linearrgb_to_srgb; } /* for prints */ if (flags & IB_mem) name = "<memory>"; bytesperpixel = (ibuf->planes + 7) >> 3; if ((bytesperpixel > 4) || (bytesperpixel == 2)) { printf("imb_savepng: Unsupported bytes per pixel: %d for file: '%s'\n", bytesperpixel, name); return (0); } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { printf("imb_savepng: Cannot png_create_write_struct for file: '%s'\n", name); return 0; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); printf("imb_savepng: Cannot png_create_info_struct for file: '%s'\n", name); return 0; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); printf("imb_savepng: Cannot setjmp for file: '%s'\n", name); return 0; } /* copy image data */ if (is_16bit) pixels16 = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned short), "png 16bit pixels"); else pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "png 8bit pixels"); if (pixels == NULL && pixels16 == NULL) { png_destroy_write_struct(&png_ptr, &info_ptr); printf("imb_savepng: Cannot allocate pixels array of %dx%d, %d bytes per pixel for file: '%s'\n", ibuf->x, ibuf->y, bytesperpixel, name); return 0; } from = (unsigned char *) ibuf->rect; to = pixels; from_float = ibuf->rect_float; to16 = pixels16; switch (bytesperpixel) { case 4: color_type = PNG_COLOR_TYPE_RGBA; if (is_16bit) { if (has_float) { if (channels_in_float == 4) { for (i = ibuf->x * ibuf->y; i > 0; i--) { premul_to_straight_v4_v4(from_straight, from_float); to16[0] = ftoshort(chanel_colormanage_cb(from_straight[0])); to16[1] = ftoshort(chanel_colormanage_cb(from_straight[1])); to16[2] = ftoshort(chanel_colormanage_cb(from_straight[2])); to16[3] = ftoshort(chanel_colormanage_cb(from_straight[3])); to16 += 4; from_float += 4; } } else if (channels_in_float == 3) { for (i = ibuf->x * ibuf->y; i > 0; i--) { to16[0] = ftoshort(chanel_colormanage_cb(from_float[0])); to16[1] = ftoshort(chanel_colormanage_cb(from_float[1])); to16[2] = ftoshort(chanel_colormanage_cb(from_float[2])); to16[3] = 65535; to16 += 4; from_float += 3; } } else { for (i = ibuf->x * ibuf->y; i > 0; i--) { to16[0] = ftoshort(chanel_colormanage_cb(from_float[0])); to16[2] = to16[1] = to16[0]; to16[3] = 65535; to16 += 4; from_float++; } } } else { for (i = ibuf->x * ibuf->y; i > 0; i--) { to16[0] = UPSAMPLE_8_TO_16(from[0]); to16[1] = UPSAMPLE_8_TO_16(from[1]); to16[2] = UPSAMPLE_8_TO_16(from[2]); to16[3] = UPSAMPLE_8_TO_16(from[3]); to16 += 4; from += 4; } } } else { for (i = ibuf->x * ibuf->y; i > 0; i--) { to[0] = from[0]; to[1] = from[1]; to[2] = from[2]; to[3] = from[3]; to += 4; from += 4; } } break; case 3: color_type = PNG_COLOR_TYPE_RGB; if (is_16bit) { if (has_float) { if (channels_in_float == 4) { for (i = ibuf->x * ibuf->y; i > 0; i--) { premul_to_straight_v4_v4(from_straight, from_float); to16[0] = ftoshort(chanel_colormanage_cb(from_straight[0])); to16[1] = ftoshort(chanel_colormanage_cb(from_straight[1])); to16[2] = ftoshort(chanel_colormanage_cb(from_straight[2])); to16 += 3; from_float += 4; } } else if (channels_in_float == 3) { for (i = ibuf->x * ibuf->y; i > 0; i--) { to16[0] = ftoshort(chanel_colormanage_cb(from_float[0])); to16[1] = ftoshort(chanel_colormanage_cb(from_float[1])); to16[2] = ftoshort(chanel_colormanage_cb(from_float[2])); to16 += 3; from_float += 3; } } else { for (i = ibuf->x * ibuf->y; i > 0; i--) { to16[0] = ftoshort(chanel_colormanage_cb(from_float[0])); to16[2] = to16[1] = to16[0]; to16 += 3; from_float++; } } } else { for (i = ibuf->x * ibuf->y; i > 0; i--) { to16[0] = UPSAMPLE_8_TO_16(from[0]); to16[1] = UPSAMPLE_8_TO_16(from[1]); to16[2] = UPSAMPLE_8_TO_16(from[2]); to16 += 3; from += 4; } } } else { for (i = ibuf->x * ibuf->y; i > 0; i--) { to[0] = from[0]; to[1] = from[1]; to[2] = from[2]; to += 3; from += 4; } } break; case 1: color_type = PNG_COLOR_TYPE_GRAY; if (is_16bit) { if (has_float) { float rgb[3]; if (channels_in_float == 4) { for (i = ibuf->x * ibuf->y; i > 0; i--) { premul_to_straight_v4_v4(from_straight, from_float); rgb[0] = chanel_colormanage_cb(from_straight[0]); rgb[1] = chanel_colormanage_cb(from_straight[1]); rgb[2] = chanel_colormanage_cb(from_straight[2]); to16[0] = ftoshort(rgb_to_bw(rgb)); to16++; from_float += 4; } } else if (channels_in_float == 3) { for (i = ibuf->x * ibuf->y; i > 0; i--) { rgb[0] = chanel_colormanage_cb(from_float[0]); rgb[1] = chanel_colormanage_cb(from_float[1]); rgb[2] = chanel_colormanage_cb(from_float[2]); to16[0] = ftoshort(rgb_to_bw(rgb)); to16++; from_float += 3; } } else { for (i = ibuf->x * ibuf->y; i > 0; i--) { to16[0] = ftoshort(chanel_colormanage_cb(from_float[0])); to16++; from_float++; } } } else { for (i = ibuf->x * ibuf->y; i > 0; i--) { to16[0] = UPSAMPLE_8_TO_16(from[0]); to16++; from += 4; } } } else { for (i = ibuf->x * ibuf->y; i > 0; i--) { to[0] = from[0]; to++; from += 4; } } break; } if (flags & IB_mem) { /* create image in memory */ imb_addencodedbufferImBuf(ibuf); ibuf->encodedsize = 0; png_set_write_fn(png_ptr, (png_voidp) ibuf, WriteData, Flush); } else { fp = BLI_fopen(name, "wb"); if (!fp) { png_destroy_write_struct(&png_ptr, &info_ptr); if (pixels) MEM_freeN(pixels); if (pixels16) MEM_freeN(pixels16); printf("imb_savepng: Cannot open file for writing: '%s'\n", name); return 0; } png_init_io(png_ptr, fp); } #if 0 png_set_filter(png_ptr, 0, PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE | PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB | PNG_FILTER_UP | PNG_FILTER_VALUE_UP | PNG_FILTER_AVG | PNG_FILTER_VALUE_AVG | PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH | PNG_ALL_FILTERS); #endif png_set_compression_level(png_ptr, compression); /* png image settings */ png_set_IHDR(png_ptr, info_ptr, ibuf->x, ibuf->y, is_16bit ? 16 : 8, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); /* image text info */ if (ibuf->metadata) { png_text *metadata; ImMetaData *iptr; int num_text = 0; iptr = ibuf->metadata; while (iptr) { num_text++; iptr = iptr->next; } metadata = MEM_callocN(num_text * sizeof(png_text), "png_metadata"); iptr = ibuf->metadata; num_text = 0; while (iptr) { metadata[num_text].compression = PNG_TEXT_COMPRESSION_NONE; metadata[num_text].key = iptr->key; metadata[num_text].text = iptr->value; num_text++; iptr = iptr->next; } png_set_text(png_ptr, info_ptr, metadata, num_text); MEM_freeN(metadata); } if (ibuf->ppm[0] > 0.0 && ibuf->ppm[1] > 0.0) { png_set_pHYs(png_ptr, info_ptr, (unsigned int)(ibuf->ppm[0] + 0.5), (unsigned int)(ibuf->ppm[1] + 0.5), PNG_RESOLUTION_METER); } /* write the file header information */ png_write_info(png_ptr, info_ptr); #ifdef __LITTLE_ENDIAN__ png_set_swap(png_ptr); #endif /* allocate memory for an array of row-pointers */ row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers"); if (row_pointers == NULL) { printf("imb_savepng: Cannot allocate row-pointers array for file '%s'\n", name); png_destroy_write_struct(&png_ptr, &info_ptr); if (pixels) MEM_freeN(pixels); if (pixels16) MEM_freeN(pixels16); if (fp) { fclose(fp); } return 0; } /* set the individual row-pointers to point at the correct offsets */ if (is_16bit) { for (i = 0; i < ibuf->y; i++) { row_pointers[ibuf->y - 1 - i] = (png_bytep) ((unsigned short *)pixels16 + (i * ibuf->x) * bytesperpixel); } } else { for (i = 0; i < ibuf->y; i++) { row_pointers[ibuf->y - 1 - i] = (png_bytep) ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char)); } } /* write out the entire image data in one call */ png_write_image(png_ptr, row_pointers); /* write the additional chunks to the PNG file (not really needed) */ png_write_end(png_ptr, info_ptr); /* clean up */ if (pixels) MEM_freeN(pixels); if (pixels16) MEM_freeN(pixels16); MEM_freeN(row_pointers); png_destroy_write_struct(&png_ptr, &info_ptr); if (fp) { fflush(fp); fclose(fp); } return(1); }
Error ResourceSaverPNG::save_image(const String &p_path, Image &p_img) { if (p_img.get_format() > Image::FORMAT_INDEXED_ALPHA) p_img.decompress(); ERR_FAIL_COND_V(p_img.get_format() > Image::FORMAT_INDEXED_ALPHA, ERR_INVALID_PARAMETER); 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,ERR_CANT_CREATE); info_ptr = png_create_info_struct(png_ptr); ERR_FAIL_COND_V(!info_ptr,ERR_CANT_CREATE); if (setjmp(png_jmpbuf(png_ptr))) { ERR_FAIL_V(ERR_CANT_OPEN); } //change this Error err; FileAccess* f = FileAccess::open(p_path,FileAccess::WRITE,&err); if (err) { ERR_FAIL_V(err); } png_set_write_fn(png_ptr,f,_write_png_data,NULL); /* write header */ if (setjmp(png_jmpbuf(png_ptr))) { ERR_FAIL_V(ERR_CANT_OPEN); } int pngf=0; int pngb=8; int cs=0; switch(p_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 (p_img.detect_alpha()) { p_img.convert(Image::FORMAT_RGBA); pngf=PNG_COLOR_TYPE_RGB_ALPHA; cs=4; } else { p_img.convert(Image::FORMAT_RGB); pngf=PNG_COLOR_TYPE_RGB; cs=3; } } } int w = p_img.get_width(); int h = p_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))) { memdelete(f); ERR_FAIL_V(ERR_CANT_OPEN); } DVector<uint8_t>::Read r = p_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))) { memdelete(f); ERR_FAIL_V(ERR_CANT_OPEN); } png_write_end(png_ptr, NULL); memdelete(f); /* cleanup heap allocation */ return OK; }
int main(int argc, char **argv) { if (argc != 4) { fprintf(stderr, "usage: %s <filename> <type> <width>\n", argv[0]); return 1; } type = atoi(argv[2]); fractal = fractals_get(type); if (type > 1) { abort_("type > 1"); } width = atoi(argv[3]); if (width < 1) { abort_("width < 1"); } height = (float)(width * fractal->ratio_height) / fractal->ratio_width; printf("fractal name: %s\nfractal size: %ux%u\ndest file: %s\n", fractal->name, width, height, argv[1]); /* create file */ FILE *fp = fopen(argv[1], "wb"); if (!fp) { abort_("[write_png_file] File %s could not be opened for writing", argv[1]); } /* initialize stuff */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { abort_("[write_png_file] png_create_write_struct failed"); } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { abort_("[write_png_file] png_create_info_struct failed"); } if (setjmp(png_jmpbuf(png_ptr))) { abort_("[write_png_file] Error during init_io"); } png_init_io(png_ptr, fp); /* write header */ if (setjmp(png_jmpbuf(png_ptr))) { abort_("[write_png_file] Error during writing header"); } png_set_IHDR(png_ptr, info_ptr, width, height, 8, 6, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_write_info(png_ptr, info_ptr); /* allocate memory */ row_pointers = (png_bytep *) malloc(sizeof(png_bytep) * height); for (y = 0; y < height; ++y) { row_pointers[y] = (png_byte*) malloc(width * 4); } /* render the fractal */ fractals_write(row_pointers, width, height, type); /* write bytes */ if (setjmp(png_jmpbuf(png_ptr))) { abort_("[write_png_file] Error during writing bytes"); } png_write_image(png_ptr, row_pointers); /* end write */ if (setjmp(png_jmpbuf(png_ptr))) { abort_("[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); return 0; }
/*! * 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; }
int main(int argc, char *argv[]) { setlocale(LC_ALL, ""); setvbuf(stdout, (char*)NULL, _IONBF, 0); if(argc != 4) { fprintf(stderr, MSG[I_HELP1], argv[0]); fputs(MSG[I_HELP2], stderr); return EXIT_FAILURE; } char *inname = argv[1], *outname = argv[2], *valarg = argv[3]; /* Quelldatei oeffnen und auf PNG-Signatur ueberpruefen **********************/ puts(MSG[I_OPEN]); FILE *f; f = fopen(inname, "rb"); if (f == NULL) { fputs(inname, stderr); fputs(MSG[E_OPEN], stderr); fputc('\n', stderr); return EXIT_FAILURE; } unsigned char sig[SIG_BYTES]; fread(sig, 1, SIG_BYTES, f); if (png_sig_cmp(sig, 0, SIG_BYTES)) { fputs(inname, stderr); fputs(MSG[E_CORRUPTED], stderr); fputc('\n', stderr); fclose(f); return EXIT_FAILURE; } /* PNG-Lesevorgang initialisieren *****************************************/ png_struct *png_ptr; png_info *info_ptr, *end_info; png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL ); if (png_ptr == NULL) { fputs(MSG[E_GENERIC], stderr); fputc('\n', stderr); fclose(f); return EXIT_FAILURE; } info_ptr = png_create_info_struct(png_ptr); end_info = png_create_info_struct(png_ptr); try_png_read( (info_ptr == NULL) || (end_info == NULL), &png_ptr, &info_ptr, &end_info, f, (char*)NULL ); try_png_read( setjmp(png_jmpbuf(png_ptr)), &png_ptr, &info_ptr, &end_info, f, MSG[E_READ] ); png_init_io(png_ptr, f); png_set_sig_bytes(png_ptr, SIG_BYTES); /* Bildinfo lesen: Bilddimensionen und ggf. Farbpalette. * Palette ggf. konvertieren. *********************************************/ long int width, height, pwidth, pheight; // png_uint_32 width, height, pwidth, pheight; comp_t *image, **row, *rwp; png_read_info(png_ptr, info_ptr); width = info_ptr->width; height = info_ptr->height; const long int original_width = info_ptr->width; const int bit_depth = info_ptr->bit_depth, color_type = info_ptr->color_type; const bool image_is_pal = (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE); const bool image_is_gray = ( (color_type == PNG_COLOR_TYPE_GRAY) || (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ); const bool alpha = ( (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) || (color_type == PNG_COLOR_TYPE_RGB_ALPHA) ); int num_palette = 0; png_color *png_pal_got = NULL; if (image_is_pal) try_png_read( !png_get_PLTE(png_ptr, info_ptr, &png_pal_got, &num_palette), &png_ptr, &info_ptr, &end_info, f, MSG[E_READPAL] ); png_color png_pal[num_palette]; comp_t comp_pal[num_palette]; if (image_is_pal) for (int i = 0; i < num_palette; i++) { png_pal[i] = png_pal_got[i]; comp_t c; c = png_pal[i].red; c <<= CHAR_BIT; c |= png_pal[i].green; c <<= CHAR_BIT; c |= png_pal[i].blue; comp_pal[i] = c; } png_color_16 *img_bkgd; png_color_16 background; if (png_get_bKGD(png_ptr, info_ptr, &img_bkgd)) background = *img_bkgd; /* Parameter fuer Groessenaenderung auswerten: * diff: (Seitenlaenge nachher) - (Seitenlaenge vorher), * vert: true <=> Aenderung der Bildhoehe (sonst -breite). ******************/ long int diff; bool vert; bool aspp = false, asp2 = false, enlg = false, sign = true; switch (tolower(*valarg++)) { case 'h': vert = false; break; case 'v': vert = true; break; case '%': aspp = true; break; case '@': asp2 = true; break; default : try_png_read(true, &png_ptr, &info_ptr, &end_info, f, MSG[E_DIM]); } switch (*valarg) { case '+': enlg = true; break; case '-': enlg = false; break; default: sign = false; break; } diff = atol(valarg); bool valargok = !!diff; if (aspp || asp2) { try_png_read(!sign, &png_ptr, &info_ptr, &end_info, f, MSG[E_SIGN]); const float fheight = (float)height, fwidth = (float)width, casp = fheight / fwidth; float nasp; if (asp2) { const char *aspsw = strtok(valarg, ":"), *aspsh = strtok((char*)NULL, ":"); valargok = ((aspsw != NULL) && (aspsh != NULL)); const float aspw = valargok? atol(aspsw): 0, asph = valargok? atol(aspsh): 0; nasp = valargok? fabs(asph / aspw): 0; } else nasp = ((float)labs(diff) / 100.0f); vert = ((nasp < casp) ^ enlg); diff = valargok? labs(vert? (height - (fwidth * nasp)): (width - (fheight / nasp)) ): 0; if (!enlg) diff = -diff; } if (!diff) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(f); if (valargok) { puts(MSG[I_NOTHINGTODO]); // const char copycmd[] = "copy /b /y"; const char copycmd[] = "cp"; char copycmdln[ strlen(copycmd) + strlen(argv[1]) + strlen(argv[2]) + 7 ]; sprintf( copycmdln, "%s \"%s\" \"%s\"", copycmd, argv[1], argv[2] ); return system(copycmdln); } try_png_read(!valargok, &png_ptr, &info_ptr, &end_info, f, MSG[E_PAR]); } if (!(aspp || asp2 || sign)) diff -= vert? height: width; try_png_read( labs(diff) > (vert? height: width), &png_ptr, &info_ptr, &end_info, f, MSG[E_SIZE] ); /* Bild- sowie Zeilenzeigerspeicher anfordern und Zeiger setzen. **********/ image = malloc(width * height * sizeof(comp_t)); try_png_read(image == NULL, &png_ptr, &info_ptr, &end_info, f, (char*)NULL); row = malloc(height * sizeof(comp_t*)); try_png_read(row == NULL, &png_ptr, &info_ptr, &end_info, f, (char*)NULL); rwp = image; for (int i = 0; i < height; i++) { row[i] = rwp; rwp += width; } /* Bild laden. * Falls Alphakanal vorhanden, Alpha invertieren: hoher Wert => hohe Deckung. * Falls Nicht-Palettenbild ohne Alphakanal (24 bpp) oder Graubild * (8 oder 16 bpp), mit "png_set_filler" die Bilddaten auf 32 bzw. 16 bpp * ausweiten. 32 Bit ist die * comp_t-Breite. ****************************/ puts(MSG[I_LOAD]); if (alpha) png_set_invert_alpha(png_ptr); else if (!image_is_pal) png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); png_read_image(png_ptr, (void*)row); /* Falls 8 oder 16 bpp, Bilddaten auf "Pixel = comp_t-Element" ausweiten. */ // trw: Temporaere Zeile. void *trw = malloc(image_is_gray? (width * 2): width); try_png_read(trw == NULL, &png_ptr, &info_ptr, &end_info, f, (char*)NULL); // Zunaechst Bildzeile nach Temporaerzeile kopieren, dann Elemente einzeln zurueck. if (image_is_pal) { for (int i = 0; i < height; i++) { uint8_t *trwp = trw; rwp = row[i]; memcpy(trw, row[i], width * sizeof *trwp); for (int j = 0; j < width; j++) *rwp++ = *trwp++; } } if (image_is_gray) { for (int i = 0; i < height; i++) { uint16_t *trwp = trw; rwp = row[i]; memcpy(trw, row[i], width * sizeof *trwp); for (int j = 0; j < width; j++) *rwp++ = *trwp++; } } /* Lesevorgang beenden und Quelldatei schliessen. ************************/ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(f); printf( "%s: %d*%d > %d*%d: %s %+d\n", MSG[I_MEASURES], width, height, vert? width: width + diff, vert? height + diff: height, vert? MSG[I_VERT]: MSG[I_HORI], diff ); /* Hier kommt Fugenschnitzer zum Einsatz. * diff: (Seitenlaenge nachher) - (Seitenlaenge vorher), * vert: true <=> Aenderung der Bildhoehe (sonst -breite). ****************/ sc_init(); sc_load(image, &width, &height, 0); const int prep = sc_prepare( vert, diff, // Bild ggf. erweitern false, alpha? MARK_ALPHA: MARK_KEEP, // Ggf. Alpha-Markierung (mark_t*)NULL, // keine Markierung sonst &width, &height, &pwidth, &pheight ); if (prep < 0) { fputs(MSG[E_GENERIC], stderr); fputc('\n', stderr); free(image); free(row); return EXIT_FAILURE; } if (prep & 2) puts(MSG[E_ALPHA]); // Bildspeicher erweitern, falls das Bild vergroessert wurde: if (prep & 1) { image = realloc(image, (size_t)width * (size_t)height * sizeof(comp_t)); if (image == NULL) { fputs(MSG[E_GENERIC], stderr); fputc('\n', stderr); return EXIT_FAILURE; } if (vert) { row = realloc(row, (size_t)height * sizeof(comp_t*)); if (row == NULL) { fputs(MSG[E_GENERIC], stderr); fputc('\n', stderr); free(image); return EXIT_FAILURE; } } } pthread_t seam_th; pthread_create(&seam_th, NULL, seam_progress, (void*)(&diff)); // sc_seam(diff); seam_paral(diff); pthread_join(seam_th, NULL); putchar('\n'); printf(MSG[I_RESIZING]); // sc_carve(diff, &width, &height, &pwidth, &pheight); carve_paral(diff, &width, &height, &pwidth, &pheight); sc_fix( false, // Nicht wiederherstellen &width, &height, &pwidth, &pheight ); sc_eject(image); sc_close(); /* Das war's mit Fugenschnitzer. -- Zeilenzeiger neu setzen. **************/ rwp = image; for (int i = 0; i < height; i++) { row[i] = rwp; rwp += width; } /* Zieldatei oeffnen und Schreibvorgang initialisieren. ********************/ putchar('\n'); printf(MSG[I_SAVE]); f = fopen(outname, "wb"); if (f == NULL) { fputs(outname, stderr); fputs(MSG[E_SAVE], stderr); fputc('\n', stderr); return EXIT_FAILURE; } png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL ); if (png_ptr == NULL) { fputs(MSG[E_GENERIC], stderr); fputc('\n', stderr); fclose(f); return EXIT_FAILURE; } info_ptr = png_create_info_struct(png_ptr); try_png_write(info_ptr == NULL, &png_ptr, &info_ptr, f, (char*)NULL); try_png_write( setjmp(png_jmpbuf(png_ptr)), &png_ptr, &info_ptr, f, MSG[E_WRITE] ); png_init_io(png_ptr, f); /* Bildparameter setzen. **************************************************/ png_set_IHDR( png_ptr, info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); if (image_is_pal) png_set_PLTE(png_ptr, info_ptr, png_pal, num_palette); if (alpha) png_set_bKGD(png_ptr, info_ptr, &background); png_write_info(png_ptr, info_ptr); /* Falls 8 oder 16 bpp, Bilddaten wieder zusammenschieben. ****************/ trw = realloc(trw, image_is_gray? (width * 2): width); try_png_write(trw == NULL, &png_ptr, &info_ptr, f, (char*)NULL); if (image_is_pal) { for (int i = 0; i < height; i++) { uint8_t *trwp = trw; rwp = row[i]; for (int j = 0; j < width; j++) *trwp++ = *rwp++; memcpy(row[i], trw, width * sizeof *trwp); } } if (image_is_gray) { for (int i = 0; i < height; i++) { uint16_t *trwp = trw; rwp = row[i]; for (int j = 0; j < width; j++) *trwp++ = *rwp++; memcpy(row[i], trw, width * sizeof *trwp); } } /* Bild speichern. Wieder Alpha invertieren (hoher Wert => hohe Transparenz) * sowie mit "png_set_filler" 32/16 bpp => 24/8 bpp setzen. ***************/ if (alpha) png_set_invert_alpha(png_ptr); else png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); png_write_image(png_ptr, (void*)row); png_write_end(png_ptr, (png_info*)NULL); puts(MSG[I_FINISHED]); /* Schreibvorgang beenden, Datei schliessen, Speicher freigeben, fertig. ***/ png_destroy_write_struct(&png_ptr, &info_ptr); fclose(f); free(trw); free(image); free(row); puts(MSG[I_COMPLETED]); return EXIT_SUCCESS; }
//----------------------------------------------------------------- bool WritePNG(Image* image, File* file) { if (!image || !file) { return false; } Image::Ptr src_image = image; switch (src_image->getPixelFormat()) { case PixelFormat::RGB_P8: case PixelFormat::RGB: case PixelFormat::RGBA: // ok, we can handle these directly break; case PixelFormat::BGR: // convert to RGB src_image = src_image->convert(PixelFormat::RGB); break; case PixelFormat::BGRA: // convert to RGBA src_image = src_image->convert(PixelFormat::RGBA); break; default: // shouldn't happen return false; } // initialize the necessary libpng data structures png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (!png_ptr) { return false; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, 0); return false; } // libpng uses SJLJ for error handling, so we need to define // any automatic variables before the call to setjmp() ArrayAutoPtr<png_bytep> rows; // establish a return point if (setjmp(png_jmpbuf(png_ptr)) != 0) { png_destroy_write_struct(&png_ptr, &info_ptr); return false; } // tell libpng that we are going to use our own io functions png_set_write_fn(png_ptr, file, write_callback, flush_callback); // set the image attributes switch (src_image->getPixelFormat()) { case PixelFormat::RGB_P8: { png_set_IHDR( png_ptr, info_ptr, src_image->getWidth(), src_image->getHeight(), 8, /* 8 bits per channel */ PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); png_set_PLTE( png_ptr, info_ptr, (png_colorp)src_image->getPalette(), 256 /* size of palette */ ); break; } case PixelFormat::RGB: { png_set_IHDR( png_ptr, info_ptr, src_image->getWidth(), src_image->getHeight(), 8, /* 8 bits per channel */ PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); break; } case PixelFormat::RGBA: { png_set_IHDR( png_ptr, info_ptr, src_image->getWidth(), src_image->getHeight(), 8, /* 8 bits per channel */ PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); break; } default: // shouldn't happen png_destroy_write_struct(&png_ptr, &info_ptr); return false; } // write png header png_write_info(png_ptr, info_ptr); // prepare an array of row pointers for libpng PixelFormatDescriptor pfd = Image::GetPixelFormatDescriptor(src_image->getPixelFormat()); rows = new png_bytep[src_image->getHeight()]; for (int i = 0; i < src_image->getHeight(); ++i) { rows[i] = (png_bytep)(src_image->getPixels() + i * src_image->getWidth() * pfd.bytesPerPixel); } // write image data png_write_image(png_ptr, rows.get()); // finish the write process png_write_end(png_ptr, 0); // clean up png_destroy_write_struct(&png_ptr, &info_ptr); return true; }
/* * write audio block to png file */ void frame_loop(size_t frame, char* output_dir, SNDFILE* audio_file, s_dimension d) { size_t x, y; size_t area = d.width * d.height; size_t wsec = ceil(d.width / d.channels); sf_count_t req, cnt; sf_count_t copy_frames = ceil(area / d.channels); png_uint_32 i; png_infop info_ptr; png_structp png_ptr; png_color_8 sig_bit; png_byte pixelbuffer[d.height][d.width * BYTES_PER_PIXEL]; png_bytep row_pointers[d.height]; short int audiobuffer[d.channels * area]; char file_name[11 + strlen(output_dir)]; // open file for writing set_filename(file_name, output_dir, frame); FILE *fp = fopen(file_name, "wb"); if (!fp) { exit(ERROR); } printf("%s\n", file_name); // clear pixelbuffer memset(&pixelbuffer, 0, area * BYTES_PER_PIXEL); // assign row pointers for (i = 0; i < d.height; i++) { row_pointers[i] = &(pixelbuffer[i][0]); } req = (size_t)sf_seek(audio_file, d.audio_frames * frame, SEEK_SET); if(req == -1) { puts("[!] audiofile seek error"); // skip frame return; } cnt = sf_readf_short(audio_file, audiobuffer, copy_frames); // copy block for(x=0; x<cnt; x++) { //pixelbuffer[ (int) floor(x / width) ][x % width] = (char) audiobuffer[x * channels]; for(y=0; y<d.channels; y++) { size_t ix = min(floor(x / wsec), d.height-1); size_t iy = x % wsec + y * wsec; pixelbuffer[ix][iy] = abs((audiobuffer[x * d.channels + y]) / 128); //printf("%lu ", (audiobuffer[x * channels + y] + sizeof(short int)) / 2); //printf("%i ", abs((audiobuffer[x * channels + y]) / 128)); } //printf("\n"); } // generate png from pixelbuffer png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fclose(fp); exit(ERROR); } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, NULL); fclose(fp); exit(ERROR); } if (setjmp(png_jmpbuf(png_ptr))) { puts("png error"); png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); exit(ERROR); } // write png png_init_io(png_ptr, fp); png_set_IHDR(png_ptr, info_ptr, d.width, d.height, d.bit_depth, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); sig_bit.gray = d.bit_depth; png_set_sBIT(png_ptr, info_ptr, &sig_bit); png_write_info(png_ptr, info_ptr); png_write_image(png_ptr, row_pointers); png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); }
int main(int argc, char *argv[]) { unsigned char header[8]; if ( argc != 3 ) { printf( "usage: %s filename gamma_value", argv[0] ); } FILE *fp = fopen(argv[1],"rb"); float gamma ; sscanf(argv[2], "%f", &gamma); if(!fp) printf("not a file"); fread(header, 1, 8, fp); int is_png = !png_sig_cmp(header, 0, 8); //Quite weird. cmp return 0 if bytes match PNG signature if(!is_png) printf("not a png"); else printf("input file confirmed as png\n"); //Creating png_structp png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, //(png_voidp)user_error_ptr, NULL, //user_error_fn, NULL); //user_warning_fn); if(!png_ptr) printf("png_ptr construct error\n"); //Creating png_infop 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); printf("something wrong with pngInfo\n"); } //setjmp for error condition from libpng if(setjmp(png_jmpbuf(png_ptr))) printf("something wrong with jmp setting\n"); //eventually, we are reading the file :-) png_init_io(png_ptr, fp); //since we've sampled 8 byes for testing if it is png, we need to let libpng know png_set_sig_bytes(png_ptr, 8); //There're bunch of error handling from the manual... we skip as usual /* //High-level of reading interface, we'll read into memory directly png_read_png(png_ptr, info_ptr, 0, NULL); //third para as png_transforms bitwise OR mask png_bytep *row_pointers = png_get_rows(png_ptr, info_ptr); */ /* low level of reading, we need it to manipulate more detailed stuff*/ png_read_info(png_ptr, info_ptr); int width = png_get_image_width(png_ptr, info_ptr); int height = png_get_image_height(png_ptr, info_ptr); png_byte color_type = png_get_color_type(png_ptr, info_ptr); png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr); png_bytep *row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height); int x, y,k; k = (int)((log(bit_depth)/log(2))); printf("%d\n", k); for (y = 0; y < height; y++) row_pointers[y] = (png_bytep) malloc(width*k); png_read_image(png_ptr, row_pointers); printf("color_type:%d\nbit_depth: %d\n",color_type, bit_depth); //processing image for (y = 0; y< height; y++) { png_byte* row = row_pointers[y]; for(x = 0; x < width; x ++) { png_byte* ptr = &(row[x*k]); //ptr[0] = 255 - ptr[0]; //shouldn't invert alpha :) //ptr[0] = (int)(pow(ptr[0], 0.9)) ; ptr[1] = (int)(255 * pow((ptr[1]/255.0), gamma)) ; ptr[2] = (int)(255 * pow((ptr[2]/255.0), gamma)) ; ptr[3] = (int)(255 * pow((ptr[3]/255.0), gamma)) ; } } //output FILE *outfp = fopen("gammaout.png", "wb"); png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); info_ptr = png_create_info_struct(png_ptr); png_init_io(png_ptr, outfp); png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_write_info(png_ptr, info_ptr); png_write_image(png_ptr, row_pointers); png_write_end(png_ptr, NULL); free(row_pointers); fclose(fp); }
bool PngEncoder::write( const Mat& img, const std::vector<int>& params ) { png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 ); png_infop info_ptr = 0; FILE* f = 0; int y, width = img.cols, height = img.rows; int depth = img.depth(), channels = img.channels(); bool result = false; AutoBuffer<uchar*> buffer; if( depth != CV_8U && depth != CV_16U ) return false; if( png_ptr ) { info_ptr = png_create_info_struct( png_ptr ); if( info_ptr ) { if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 ) { if( m_buf ) { png_set_write_fn(png_ptr, this, (png_rw_ptr)writeDataToBuf, (png_flush_ptr)flushBuf); } else { f = fopen( m_filename.c_str(), "wb" ); if( f ) png_init_io( png_ptr, f ); } int compression_level = -1; // Invalid value to allow setting 0-9 as valid int compression_strategy = Z_RLE; // Default strategy bool isBilevel = false; for( size_t i = 0; i < params.size(); i += 2 ) { if( params[i] == CV_IMWRITE_PNG_COMPRESSION ) { compression_level = params[i+1]; compression_level = MIN(MAX(compression_level, 0), Z_BEST_COMPRESSION); } if( params[i] == CV_IMWRITE_PNG_STRATEGY ) { compression_strategy = params[i+1]; compression_strategy = MIN(MAX(compression_strategy, 0), Z_FIXED); } if( params[i] == CV_IMWRITE_PNG_BILEVEL ) { isBilevel = params[i+1] != 0; } } if( m_buf || f ) { if( compression_level >= 0 ) { png_set_compression_level( png_ptr, compression_level ); } else { // tune parameters for speed // (see http://wiki.linuxquestions.org/wiki/Libpng) png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_SUB); png_set_compression_level(png_ptr, Z_BEST_SPEED); } png_set_compression_strategy(png_ptr, compression_strategy); png_set_IHDR( png_ptr, info_ptr, width, height, depth == CV_8U ? isBilevel?1:8 : 16, channels == 1 ? PNG_COLOR_TYPE_GRAY : channels == 3 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); png_write_info( png_ptr, info_ptr ); if (isBilevel) png_set_packing(png_ptr); png_set_bgr( png_ptr ); if( !isBigEndian() ) png_set_swap( png_ptr ); buffer.allocate(height); for( y = 0; y < height; y++ ) buffer[y] = img.data + y*img.step; png_write_image( png_ptr, buffer ); png_write_end( png_ptr, info_ptr ); result = true; } } } } png_destroy_write_struct( &png_ptr, &info_ptr ); if(f) fclose( f ); return result; }
void WritePNG(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 = safe_malloc(width * height * numBytes); // set error handling if(setjmp(png_jmpbuf(png))) { free(buffer); png_destroy_write_struct(&png, &info); return; } png_set_write_fn(png, buffer, png_write_data, png_flush_data); if(numBytes == 4) { png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); } else { // should be 3 png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); } // write the file header information png_write_info(png, info); row_pointers = safe_malloc(height * sizeof(png_bytep)); if(setjmp(png_jmpbuf(png))) { free(row_pointers); free(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); free(row_pointers); SaveFile(name, buffer, png_compressed_size); free(buffer); }
// Also informed by https://gist.github.com/niw/5963798 bool WritePNG(ImageData* outImage, char* fileName) { // Step 0: Make sure we can open the input file FILE* outFile = fopen(fileName, "wb"); if (!outFile) { abort_("WritePNG: Can't open %s for writing\n", fileName); } int width = outImage->xDim; int height = outImage->yDim; // The image we get has RGB-only data, in 3-byte pixels // We need an array of rows, with pointers to them, each row having RGBA data png_bytep row_pointers[height]; for (int row = 0; row < height; row++) { // Output image rows are RGBA row_pointers[row] = (png_bytep)malloc(width * 4); if (!row_pointers[row]) { abort_("WritePNG: Can't allocate memory for row %d\n", row); } // Set all to 0xff, for initializing alpha channel memset(row_pointers[row], 0xff, width * 4); // Now copy pixels from input image to output for (int pixel = 0; pixel < width; pixel++) { *(Pixel*)(row_pointers[row] + pixel * 4) = *(outImage->pixels + row * width + pixel); } } png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png) abort(); png_infop info = png_create_info_struct(png); if (!info) abort(); if (setjmp(png_jmpbuf(png))) abort(); png_init_io(png, outFile); // Output is 8bit depth, RGBA format. png_set_IHDR( png, info, width, height, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); png_write_info(png, info); // To remove the alpha channel for PNG_COLOR_TYPE_RGB format, Use png_set_filler(). //png_set_filler(png, 0, PNG_FILLER_AFTER); png_write_image(png, row_pointers); png_write_end(png, NULL); for(int y = 0; y < height; y++) { free(row_pointers[y]); } fclose(outFile); return false; }
short imb_savepng(struct ImBuf *ibuf, char *name, int flags) { png_structp png_ptr; png_infop info_ptr; unsigned char *pixels = 0; unsigned char *from, *to; png_bytepp row_pointers = 0; int i, bytesperpixel, color_type = PNG_COLOR_TYPE_GRAY; FILE *fp = 0; bytesperpixel = (ibuf->depth + 7) >> 3; if ((bytesperpixel > 4) || (bytesperpixel == 2)) { printf("imb_savepng: unsupported bytes per pixel: %d\n", bytesperpixel); return (0); } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { printf("Cannot png_create_write_struct\n"); return 0; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); printf("Cannot png_create_info_struct\n"); return 0; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); if (pixels) MEM_freeN(pixels); if (row_pointers) MEM_freeN(row_pointers); // printf("Aborting\n"); if (fp) { fflush(fp); fclose(fp); } return 0; } // copy image data pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels"); if (pixels == NULL) { printf("Cannot allocate pixels array\n"); return 0; } from = (unsigned char *) ibuf->rect; to = pixels; switch (bytesperpixel) { case 4: color_type = PNG_COLOR_TYPE_RGBA; for (i = ibuf->x * ibuf->y; i > 0; i--) { to[0] = from[0]; to[1] = from[1]; to[2] = from[2]; to[3] = from[3]; to += 4; from += 4; } break; case 3: color_type = PNG_COLOR_TYPE_RGB; for (i = ibuf->x * ibuf->y; i > 0; i--) { to[0] = from[0]; to[1] = from[1]; to[2] = from[2]; to += 3; from += 4; } break; case 1: color_type = PNG_COLOR_TYPE_GRAY; for (i = ibuf->x * ibuf->y; i > 0; i--) { to[0] = from[0]; to++; from += 4; } break; } if (flags & IB_mem) { // create image in memory imb_addencodedbufferImBuf(ibuf); ibuf->encodedsize = 0; png_set_write_fn(png_ptr, (png_voidp) ibuf, WriteData, Flush); } else { fp = fopen(name, "wb"); if (!fp) { MEM_freeN(pixels); return 0; } png_init_io(png_ptr, fp); } /* png_set_filter(png_ptr, 0, PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE | PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB | PNG_FILTER_UP | PNG_FILTER_VALUE_UP | PNG_FILTER_AVG | PNG_FILTER_VALUE_AVG | PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH| PNG_ALL_FILTERS); png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); */ // png image settings png_set_IHDR(png_ptr, info_ptr, ibuf->x, ibuf->y, 8, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); /* image text info */ if (ibuf->img_info) { png_text* imginfo; ImgInfo* iptr; int num_text = 0; iptr = ibuf->img_info; while (iptr) { num_text++; iptr = iptr->next; } imginfo = MEM_callocN(num_text*sizeof(png_text), "png_imginfo"); iptr = ibuf->img_info; num_text = 0; while (iptr) { imginfo[num_text].compression = PNG_TEXT_COMPRESSION_NONE; imginfo[num_text].key = iptr->key; imginfo[num_text].text = iptr->value; num_text++; iptr = iptr->next; } png_set_text(png_ptr, info_ptr, imginfo, num_text); MEM_freeN(imginfo); } // write the file header information png_write_info(png_ptr, info_ptr); // allocate memory for an array of row-pointers row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers"); if (row_pointers == NULL) { printf("Cannot allocate row-pointers array\n"); MEM_freeN(pixels); return 0; } // set the individual row-pointers to point at the correct offsets for (i = 0; i < ibuf->y; i++) { row_pointers[ibuf->y-1-i] = (png_bytep) ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char)); } // write out the entire image data in one call png_write_image(png_ptr, row_pointers); // write the additional chunks to the PNG file (not really needed) png_write_end(png_ptr, info_ptr); // clean up MEM_freeN(pixels); MEM_freeN(row_pointers); png_destroy_write_struct(&png_ptr, &info_ptr); if (fp) { fflush(fp); fclose(fp); } return(1); }
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 }