void putBmpIntoPixels(FIBITMAP * bmp, ofPixels_<PixelType> &pix, bool swapForLittleEndian = true) { // convert to correct type depending on type of input bmp and PixelType FIBITMAP* bmpConverted = NULL; FREE_IMAGE_TYPE imgType = FreeImage_GetImageType(bmp); if(sizeof(PixelType)==1 && (FreeImage_GetColorType(bmp) == FIC_PALETTE || FreeImage_GetBPP(bmp) < 8 || imgType!=FIT_BITMAP)) { if(FreeImage_IsTransparent(bmp)) { bmpConverted = FreeImage_ConvertTo32Bits(bmp); } else { bmpConverted = FreeImage_ConvertTo24Bits(bmp); } bmp = bmpConverted; }else if(sizeof(PixelType)==2 && imgType!=FIT_UINT16 && imgType!=FIT_RGB16 && imgType!=FIT_RGBA16){ if(FreeImage_IsTransparent(bmp)) { bmpConverted = FreeImage_ConvertToType(bmp,FIT_RGBA16); } else { bmpConverted = FreeImage_ConvertToType(bmp,FIT_RGB16); } bmp = bmpConverted; }else if(sizeof(PixelType)==4 && imgType!=FIT_FLOAT && imgType!=FIT_RGBF && imgType!=FIT_RGBAF){ if(FreeImage_IsTransparent(bmp)) { bmpConverted = FreeImage_ConvertToType(bmp,FIT_RGBAF); } else { bmpConverted = FreeImage_ConvertToType(bmp,FIT_RGBF); } bmp = bmpConverted; } unsigned int width = FreeImage_GetWidth(bmp); unsigned int height = FreeImage_GetHeight(bmp); unsigned int bpp = FreeImage_GetBPP(bmp); unsigned int channels = (bpp / sizeof(PixelType)) / 8; unsigned int pitch = FreeImage_GetPitch(bmp); // ofPixels are top left, FIBITMAP is bottom left FreeImage_FlipVertical(bmp); unsigned char* bmpBits = FreeImage_GetBits(bmp); if(bmpBits != NULL) { pix.setFromAlignedPixels((PixelType*) bmpBits, width, height, channels, pitch); } else { ofLogError("ofImage") << "putBmpIntoPixels(): unable to set ofPixels from FIBITMAP"; } if(bmpConverted != NULL) { FreeImage_Unload(bmpConverted); } #ifdef TARGET_LITTLE_ENDIAN if(swapForLittleEndian && sizeof(PixelType) == 1) { pix.swapRgb(); } #endif }
HBITMAP BmpFilterLoadBitmap(BOOL *bIsTransparent, const wchar_t *ptszFilename) { FIBITMAP *dib = (FIBITMAP*)Image_Load(ptszFilename, IMGL_RETURNDIB); if (dib == nullptr) return nullptr; FIBITMAP *dib32 = nullptr; if (FreeImage_GetBPP(dib) != 32) { dib32 = FreeImage_ConvertTo32Bits(dib); FreeImage_Unload(dib); } else dib32 = dib; if (dib32 == nullptr) return nullptr; if (FreeImage_IsTransparent(dib32)) if (bIsTransparent) *bIsTransparent = TRUE; if (FreeImage_GetWidth(dib32) > 128 || FreeImage_GetHeight(dib32) > 128) { FIBITMAP *dib_new = FreeImage_MakeThumbnail(dib32, 128, FALSE); FreeImage_Unload(dib32); if (dib_new == nullptr) return nullptr; dib32 = dib_new; } HBITMAP bitmap = FreeImage_CreateHBITMAPFromDIB(dib32); FreeImage_Unload(dib32); FreeImage_CorrectBitmap32Alpha(bitmap, FALSE); return bitmap; }
/*! * \brief Opens the image file using the FreeImage library in the specified orientation * and builds the 2D Texture MipMaps. * \param pathImagefile Path to the image file. * \param bVertFlip 1, if the image texture must be vertically flipped * 0, otherwise * \param bHorzFlip 1, if the image texture must be horizontally flipped * 0, otherwise * \return Texture ID. */ GLuint loadTexture(const char* pathImagefile, int bVertFlip, int bHorzFlip) { GLuint textureID; FREE_IMAGE_FORMAT format = FreeImage_GetFileType(pathImagefile,0); FIBITMAP* image = FreeImage_Load(format, pathImagefile,0); int bRGBA = FreeImage_IsTransparent(image); FIBITMAP* temp = image; if(bRGBA) { image = FreeImage_ConvertTo32Bits(temp); } else { image = FreeImage_ConvertTo24Bits(temp); } FreeImage_Unload(temp); if(bVertFlip) { FreeImage_FlipVertical(image); } if(bHorzFlip) { FreeImage_FlipHorizontal(image); } int w = FreeImage_GetWidth(image); int h = FreeImage_GetHeight(image); glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); //// turn off bilinear filtering //gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_NEAREST) //gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); if(bRGBA) { gluBuild2DMipmaps(GL_TEXTURE_2D, 4, w, h, GL_BGRA, GL_UNSIGNED_BYTE, FreeImage_GetBits(image)); } else { gluBuild2DMipmaps(GL_TEXTURE_2D, 3, w, h, GL_BGR, GL_UNSIGNED_BYTE, FreeImage_GetBits(image)); } FreeImage_Unload(image); return textureID; }
void putBmpIntoPixels(FIBITMAP * bmp, ofPixels_<PixelType> &pix, bool swapForLittleEndian = true) { // some images use a palette, or <8 bpp, so convert them to raster 8-bit channels FIBITMAP* bmpConverted = NULL; if(FreeImage_GetColorType(bmp) == FIC_PALETTE || FreeImage_GetBPP(bmp) < 8) { if(FreeImage_IsTransparent(bmp)) { bmpConverted = FreeImage_ConvertTo32Bits(bmp); } else { bmpConverted = FreeImage_ConvertTo24Bits(bmp); } bmp = bmpConverted; } unsigned int width = FreeImage_GetWidth(bmp); unsigned int height = FreeImage_GetHeight(bmp); unsigned int bpp = FreeImage_GetBPP(bmp); unsigned int channels = (bpp / sizeof(PixelType)) / 8; unsigned int pitch = FreeImage_GetPitch(bmp); // ofPixels are top left, FIBITMAP is bottom left FreeImage_FlipVertical(bmp); unsigned char* bmpBits = FreeImage_GetBits(bmp); if(bmpBits != NULL) { pix.setFromAlignedPixels((PixelType*) bmpBits, width, height, channels, pitch); } else { ofLogError() << "ofImage::putBmpIntoPixels() unable to set ofPixels from FIBITMAP"; } if(bmpConverted != NULL) { FreeImage_Unload(bmpConverted); } #ifdef TARGET_LITTLE_ENDIAN if(swapForLittleEndian && sizeof(PixelType) == 1) { pix.swapRgb(); } #endif }
BOOL fipImage::isTransparent() const { return FreeImage_IsTransparent(_dib); }
virtual bool load(const std::string& filename, Array &lat) { FREE_IMAGE_FORMAT type = FreeImage_GetFIFFromFilename(filename.c_str()); if(type == FIF_UNKNOWN) { AL_WARN("image format not recognized: %s", filename.c_str()); return false; } if(!FreeImage_FIFSupportsReading(type)) { AL_WARN("image format not supported: %s", filename.c_str()); return false; } destroy(); mImage = FreeImage_Load(type, filename.c_str(), 0); if (mImage == NULL) { AL_WARN("image failed to load: %s", filename.c_str()); return false; } FREE_IMAGE_COLOR_TYPE colorType = FreeImage_GetColorType(mImage); switch(colorType) { case FIC_MINISBLACK: case FIC_MINISWHITE: { FIBITMAP *res = FreeImage_ConvertToGreyscale(mImage); FreeImage_Unload(mImage); mImage = res; } break; case FIC_PALETTE: { if(FreeImage_IsTransparent(mImage)) { FIBITMAP *res = FreeImage_ConvertTo32Bits(mImage); FreeImage_Unload(mImage); mImage = res; } else { FIBITMAP *res = FreeImage_ConvertTo24Bits(mImage); FreeImage_Unload(mImage); mImage = res; } } break; case FIC_CMYK: { AL_WARN("CMYK images currently not supported"); return false; } break; default: break; } // flip vertical for OpenGL: //FreeImage_FlipVertical(mImage); //Freeimage is not tightly packed, so we use //a custom method instead of one of the Matrix //utility methods int planes = getPlanes(); AlloTy ty = getDataType(); int w, h; getDim(w, h); lat.format(planes, ty, w, h); Image::Format format = Image::getFormat(planes); switch(format) { case Image::LUMINANCE: { char *o_pix = (char *)(lat.data.ptr); int rowstride = lat.header.stride[1]; for(unsigned j = 0; j < lat.header.dim[1]; ++j) { char *pix = (char *)FreeImage_GetScanLine(mImage, j); memcpy(o_pix, pix, rowstride); o_pix += rowstride; } } break; case Image::RGB: { switch(lat.header.type) { case AlloUInt8Ty: { char *bp = (char *)(lat.data.ptr); int rowstride = lat.header.stride[1]; for(unsigned j = 0; j < lat.header.dim[1]; ++j) { RGBTRIPLE * pix = (RGBTRIPLE *)FreeImage_GetScanLine(mImage, j); Image::RGBPix<uint8_t> *o_pix = (Image::RGBPix<uint8_t> *)(bp + j*rowstride); for(unsigned i=0; i < lat.header.dim[0]; ++i) { o_pix->r = pix->rgbtRed; o_pix->g = pix->rgbtGreen; o_pix->b = pix->rgbtBlue; ++pix; ++o_pix; } } } break; case AlloFloat32Ty: { char *o_pix = (char *)(lat.data.ptr); int rowstride = lat.header.stride[1]; for(unsigned j = 0; j < lat.header.dim[1]; ++j) { char *pix = (char *)FreeImage_GetScanLine(mImage, j); memcpy(o_pix, pix, rowstride); o_pix += rowstride; } } break; default: break; } } break; case Image::RGBA: { switch(lat.header.type) { case AlloUInt8Ty: { char *bp = (char *)(lat.data.ptr); int rowstride = lat.header.stride[1]; for(unsigned j = 0; j < lat.header.dim[1]; ++j) { RGBQUAD *pix = (RGBQUAD *)FreeImage_GetScanLine(mImage, j); Image::RGBAPix<uint8_t> *o_pix = (Image::RGBAPix<uint8_t> *)(bp + j*rowstride); for(unsigned i=0; i < lat.header.dim[0]; ++i) { o_pix->r = pix->rgbRed; o_pix->g = pix->rgbGreen; o_pix->b = pix->rgbBlue; o_pix->a = pix->rgbReserved; ++pix; ++o_pix; } } } break; case AlloFloat32Ty: { char *o_pix = (char *)(lat.data.ptr); int rowstride = lat.header.stride[1]; for(unsigned j = 0; j < lat.header.dim[1]; ++j) { char *pix = (char *)FreeImage_GetScanLine(mImage, j); memcpy(o_pix, pix, rowstride); o_pix += rowstride; } } break; default: break; } } break; default: AL_WARN("image data not understood"); destroy(); return false; } return true; }
void ofxGifDecoder::processFrame(FIBITMAP * bmp, int _frameNum){ FITAG *tag; ofPixels pix; unsigned int frameLeft, frameTop; float frameDuration; GifFrameDisposal disposal_method = GIF_DISPOSAL_BACKGROUND; if( FreeImage_GetMetadata(FIMD_ANIMATION, bmp, "FrameLeft", &tag)) { frameLeft = *(unsigned short *)FreeImage_GetTagValue(tag); } if( FreeImage_GetMetadata(FIMD_ANIMATION, bmp, "FrameTop", &tag)) { frameTop = *(unsigned short *)FreeImage_GetTagValue(tag); } if( FreeImage_GetMetadata(FIMD_ANIMATION, bmp, "FrameTime", &tag)) { long frameTime = *(long *)FreeImage_GetTagValue(tag);// centiseconds 1/100 sec frameDuration =(float)frameTime/1000.f; } if( FreeImage_GetMetadata(FIMD_ANIMATION, bmp, "DisposalMethod", &tag)) { disposal_method = (GifFrameDisposal) *(unsigned char *)FreeImage_GetTagValue(tag); } // we do this for drawing. eventually we should be able to draw 8 bits? at least to retain the data // if(FreeImage_GetBPP(bmp) == 8) { // // maybe we should only do this when asked for rendering? // bmp = FreeImage_ConvertTo24Bits(bmp); // } FIBITMAP* bmpConverted = NULL; if(FreeImage_GetColorType(bmp) == FIC_PALETTE || FreeImage_GetBPP(bmp) < 8) { if(FreeImage_IsTransparent(bmp)) { bmpConverted = FreeImage_ConvertTo32Bits(bmp); } else { bmpConverted = FreeImage_ConvertTo24Bits(bmp); } bmp = bmpConverted; } unsigned int width = FreeImage_GetWidth(bmp); unsigned int height = FreeImage_GetHeight(bmp); unsigned int bpp = FreeImage_GetBPP(bmp); // changed this bc we're not using PixelType template anywhere else... unsigned int channels = (bpp / sizeof( unsigned char )) / 8; unsigned int pitch = FreeImage_GetPitch(bmp); // ofPixels are top left, FIBITMAP is bottom left FreeImage_FlipVertical(bmp); unsigned char * bmpBits = FreeImage_GetBits(bmp); if(bmpBits != NULL) { pix.setFromAlignedPixels(bmpBits, width, height, channels, pitch); #ifdef TARGET_LITTLE_ENDIAN pix.swapRgb(); #endif gifFile.addFrame(pix, frameLeft, frameTop, disposal_method, frameDuration); } else { ofLogError() << "ofImage::putBmpIntoPixels() unable to set ofPixels from FIBITMAP"; } }
//--------------------------------------------------------------------- Codec::DecodeResult FreeImageCodec::decode(DataStreamPtr& input) const { // Set error handler FreeImage_SetOutputMessage(FreeImageLoadErrorHandler); // Buffer stream into memory (TODO: override IO functions instead?) MemoryDataStream memStream(input, true); FIMEMORY* fiMem = FreeImage_OpenMemory(memStream.getPtr(), static_cast<DWORD>(memStream.size())); FIBITMAP* fiBitmap = FreeImage_LoadFromMemory( (FREE_IMAGE_FORMAT)mFreeImageType, fiMem); if (!fiBitmap) { OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Error decoding image", "FreeImageCodec::decode"); } ImageData* imgData = OGRE_NEW ImageData(); MemoryDataStreamPtr output; imgData->depth = 1; // only 2D formats handled by this codec imgData->width = FreeImage_GetWidth(fiBitmap); imgData->height = FreeImage_GetHeight(fiBitmap); imgData->num_mipmaps = 0; // no mipmaps in non-DDS imgData->flags = 0; // Must derive format first, this may perform conversions FREE_IMAGE_TYPE imageType = FreeImage_GetImageType(fiBitmap); FREE_IMAGE_COLOR_TYPE colourType = FreeImage_GetColorType(fiBitmap); unsigned bpp = FreeImage_GetBPP(fiBitmap); switch(imageType) { case FIT_UNKNOWN: case FIT_COMPLEX: case FIT_UINT32: case FIT_INT32: case FIT_DOUBLE: default: OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Unknown or unsupported image format", "FreeImageCodec::decode"); break; case FIT_BITMAP: // Standard image type // Perform any colour conversions for greyscale if (colourType == FIC_MINISWHITE || colourType == FIC_MINISBLACK) { FIBITMAP* newBitmap = FreeImage_ConvertToGreyscale(fiBitmap); // free old bitmap and replace FreeImage_Unload(fiBitmap); fiBitmap = newBitmap; // get new formats bpp = FreeImage_GetBPP(fiBitmap); colourType = FreeImage_GetColorType(fiBitmap); } // Perform any colour conversions for RGB else if (bpp < 8 || colourType == FIC_PALETTE || colourType == FIC_CMYK) { FIBITMAP* newBitmap = NULL; if (FreeImage_IsTransparent(fiBitmap)) { // convert to 32 bit to preserve the transparency // (the alpha byte will be 0 if pixel is transparent) newBitmap = FreeImage_ConvertTo32Bits(fiBitmap); } else { // no transparency - only 3 bytes are needed newBitmap = FreeImage_ConvertTo24Bits(fiBitmap); } // free old bitmap and replace FreeImage_Unload(fiBitmap); fiBitmap = newBitmap; // get new formats bpp = FreeImage_GetBPP(fiBitmap); colourType = FreeImage_GetColorType(fiBitmap); } // by this stage, 8-bit is greyscale, 16/24/32 bit are RGB[A] switch(bpp) { case 8: imgData->format = PF_L8; break; case 16: // Determine 555 or 565 from green mask // cannot be 16-bit greyscale since that's FIT_UINT16 if(FreeImage_GetGreenMask(fiBitmap) == FI16_565_GREEN_MASK) { imgData->format = PF_R5G6B5; } else { // FreeImage doesn't support 4444 format so must be 1555 imgData->format = PF_A1R5G5B5; } break; case 24: // FreeImage differs per platform // PF_BYTE_BGR[A] for little endian (== PF_ARGB native) // PF_BYTE_RGB[A] for big endian (== PF_RGBA native) #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB imgData->format = PF_BYTE_RGB; #else imgData->format = PF_BYTE_BGR; #endif break; case 32: #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB imgData->format = PF_BYTE_RGBA; #else imgData->format = PF_BYTE_BGRA; #endif break; }; break; case FIT_UINT16: case FIT_INT16: // 16-bit greyscale imgData->format = PF_L16; break; case FIT_FLOAT: // Single-component floating point data imgData->format = PF_FLOAT32_R; break; case FIT_RGB16: imgData->format = PF_SHORT_RGB; break; case FIT_RGBA16: imgData->format = PF_SHORT_RGBA; break; case FIT_RGBF: imgData->format = PF_FLOAT32_RGB; break; case FIT_RGBAF: imgData->format = PF_FLOAT32_RGBA; break; }; unsigned char* srcData = FreeImage_GetBits(fiBitmap); unsigned srcPitch = FreeImage_GetPitch(fiBitmap); // Final data - invert image and trim pitch at the same time size_t dstPitch = imgData->width * PixelUtil::getNumElemBytes(imgData->format); imgData->size = dstPitch * imgData->height; // Bind output buffer output.bind(OGRE_NEW MemoryDataStream(imgData->size)); uchar* pSrc; uchar* pDst = output->getPtr(); for (size_t y = 0; y < imgData->height; ++y) { pSrc = srcData + (imgData->height - y - 1) * srcPitch; memcpy(pDst, pSrc, dstPitch); pDst += dstPitch; } FreeImage_Unload(fiBitmap); FreeImage_CloseMemory(fiMem); DecodeResult ret; ret.first = output; ret.second = CodecDataPtr(imgData); return ret; }
static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { if( data == NULL ) { return NULL; } GIFinfo *info = (GIFinfo *)data; if( page == -1 ) { page = 0; } if( page < 0 || page >= (int)info->image_descriptor_offsets.size() ) { return NULL; } FIBITMAP *dib = NULL; try { bool have_transparent = false, no_local_palette = false, interlaced = false; int disposal_method = GIF_DISPOSAL_LEAVE, delay_time = 0, transparent_color = 0; WORD left, top, width, height; BYTE packed, b; WORD w; //playback pages to generate what the user would see for this frame if( (flags & GIF_PLAYBACK) == GIF_PLAYBACK ) { //Logical Screen Descriptor io->seek_proc(handle, 6, SEEK_SET); WORD logicalwidth, logicalheight; io->read_proc(&logicalwidth, 2, 1, handle); io->read_proc(&logicalheight, 2, 1, handle); #ifdef FREEIMAGE_BIGENDIAN SwapShort(&logicalwidth); SwapShort(&logicalheight); #endif //set the background color with 0 alpha RGBQUAD background; if( info->global_color_table_offset != 0 && info->background_color < info->global_color_table_size ) { io->seek_proc(handle, info->global_color_table_offset + (info->background_color * 3), SEEK_SET); io->read_proc(&background.rgbRed, 1, 1, handle); io->read_proc(&background.rgbGreen, 1, 1, handle); io->read_proc(&background.rgbBlue, 1, 1, handle); } else { background.rgbRed = 0; background.rgbGreen = 0; background.rgbBlue = 0; } background.rgbReserved = 0; //allocate entire logical area dib = FreeImage_Allocate(logicalwidth, logicalheight, 32); if( dib == NULL ) { throw "DIB allocated failed"; } //fill with background color to start int x, y; RGBQUAD *scanline; for( y = 0; y < logicalheight; y++ ) { scanline = (RGBQUAD *)FreeImage_GetScanLine(dib, y); for( x = 0; x < logicalwidth; x++ ) { *scanline++ = background; } } //cache some info about each of the pages so we can avoid decoding as many of them as possible std::vector<PageInfo> pageinfo; int start = page, end = page; while( start >= 0 ) { //Graphic Control Extension io->seek_proc(handle, info->graphic_control_extension_offsets[start] + 1, SEEK_SET); io->read_proc(&packed, 1, 1, handle); have_transparent = (packed & GIF_PACKED_GCE_HAVETRANS) ? true : false; disposal_method = (packed & GIF_PACKED_GCE_DISPOSAL) >> 2; //Image Descriptor io->seek_proc(handle, info->image_descriptor_offsets[page], SEEK_SET); io->read_proc(&left, 2, 1, handle); io->read_proc(&top, 2, 1, handle); io->read_proc(&width, 2, 1, handle); io->read_proc(&height, 2, 1, handle); #ifdef FREEIMAGE_BIGENDIAN SwapShort(&left); SwapShort(&top); SwapShort(&width); SwapShort(&height); #endif pageinfo.push_back(PageInfo(disposal_method, left, top, width, height)); if( start != end ) { if( left == 0 && top == 0 && width == logicalwidth && height == logicalheight ) { if( disposal_method == GIF_DISPOSAL_BACKGROUND ) { pageinfo.pop_back(); start++; break; } else if( disposal_method != GIF_DISPOSAL_PREVIOUS ) { if( !have_transparent ) { break; } } } } start--; } if( start < 0 ) { start = 0; } //draw each page into the logical area for( page = start; page <= end; page++ ) { PageInfo &info = pageinfo[end - page]; //things we can skip having to decode if( page != end ) { if( info.disposal_method == GIF_DISPOSAL_PREVIOUS ) { continue; } if( info.disposal_method == GIF_DISPOSAL_BACKGROUND ) { for( y = 0; y < info.height; y++ ) { scanline = (RGBQUAD *)FreeImage_GetScanLine(dib, logicalheight - (y + info.top) - 1) + info.left; for( x = 0; x < info.width; x++ ) { *scanline++ = background; } } } } //decode page FIBITMAP *pagedib = Load(io, handle, page, GIF_LOAD256, data); if( pagedib != NULL ) { RGBQUAD *pal = FreeImage_GetPalette(pagedib); have_transparent = false; if( FreeImage_IsTransparent(pagedib) ) { int count = FreeImage_GetTransparencyCount(pagedib); BYTE *table = FreeImage_GetTransparencyTable(pagedib); for( int i = 0; i < count; i++ ) { if( table[i] == 0 ) { have_transparent = true; transparent_color = i; break; } } } //copy page data into logical buffer, with full alpha opaqueness for( y = 0; y < info.height; y++ ) { scanline = (RGBQUAD *)FreeImage_GetScanLine(dib, logicalheight - (y + info.top) - 1) + info.left; BYTE *pageline = FreeImage_GetScanLine(pagedib, info.height - y - 1); for( x = 0; x < info.width; x++ ) { if( !have_transparent || *pageline != transparent_color ) { *scanline = pal[*pageline]; scanline->rgbReserved = 255; } scanline++; pageline++; } } FreeImage_Unload(pagedib); } } return dib; } //get the actual frame image data for a single frame //Image Descriptor io->seek_proc(handle, info->image_descriptor_offsets[page], SEEK_SET); io->read_proc(&left, 2, 1, handle); io->read_proc(&top, 2, 1, handle); io->read_proc(&width, 2, 1, handle); io->read_proc(&height, 2, 1, handle); #ifdef FREEIMAGE_BIGENDIAN SwapShort(&left); SwapShort(&top); SwapShort(&width); SwapShort(&height); #endif io->read_proc(&packed, 1, 1, handle); interlaced = (packed & GIF_PACKED_ID_INTERLACED) ? true : false; no_local_palette = (packed & GIF_PACKED_ID_HAVELCT) ? false : true; int bpp = 8; if( (flags & GIF_LOAD256) == 0 ) { if( !no_local_palette ) { int size = 2 << (packed & GIF_PACKED_ID_LCTSIZE); if( size <= 2 ) bpp = 1; else if( size <= 16 ) bpp = 4; } else if( info->global_color_table_offset != 0 ) { if( info->global_color_table_size <= 2 ) bpp = 1; else if( info->global_color_table_size <= 16 ) bpp = 4; } } dib = FreeImage_Allocate(width, height, bpp); if( dib == NULL ) { throw "DIB allocated failed"; } FreeImage_SetMetadataEx(FIMD_ANIMATION, dib, "FrameLeft", ANIMTAG_FRAMELEFT, FIDT_SHORT, 1, 2, &left); FreeImage_SetMetadataEx(FIMD_ANIMATION, dib, "FrameTop", ANIMTAG_FRAMETOP, FIDT_SHORT, 1, 2, &top); b = no_local_palette ? 1 : 0; FreeImage_SetMetadataEx(FIMD_ANIMATION, dib, "NoLocalPalette", ANIMTAG_NOLOCALPALETTE, FIDT_BYTE, 1, 1, &b); b = interlaced ? 1 : 0; FreeImage_SetMetadataEx(FIMD_ANIMATION, dib, "Interlaced", ANIMTAG_INTERLACED, FIDT_BYTE, 1, 1, &b); //Palette RGBQUAD *pal = FreeImage_GetPalette(dib); if( !no_local_palette ) { int size = 2 << (packed & GIF_PACKED_ID_LCTSIZE); int i = 0; while( i < size ) { io->read_proc(&pal[i].rgbRed, 1, 1, handle); io->read_proc(&pal[i].rgbGreen, 1, 1, handle); io->read_proc(&pal[i].rgbBlue, 1, 1, handle); i++; } } else if( info->global_color_table_offset != 0 ) { long pos = io->tell_proc(handle); io->seek_proc(handle, info->global_color_table_offset, SEEK_SET); int i = 0; while( i < info->global_color_table_size ) { io->read_proc(&pal[i].rgbRed, 1, 1, handle); io->read_proc(&pal[i].rgbGreen, 1, 1, handle); io->read_proc(&pal[i].rgbBlue, 1, 1, handle); i++; } io->seek_proc(handle, pos, SEEK_SET); } else { //its legal to have no palette, but we're going to generate *something* for( int i = 0; i < 256; i++ ) { pal[i].rgbRed = i; pal[i].rgbGreen = i; pal[i].rgbBlue = i; } } //LZW Minimum Code Size io->read_proc(&b, 1, 1, handle); StringTable stringtable; stringtable.Initialize(b); //Image Data Sub-blocks int x = 0, xpos = 0, y = 0, shift = 8 - bpp, mask = (1 << bpp) - 1, interlacepass = 0; BYTE *scanline = FreeImage_GetScanLine(dib, height - 1); BYTE buf[1024]; io->read_proc(&b, 1, 1, handle); while( b ) { io->read_proc(stringtable.FillInputBuffer(b), b, 1, handle); int size = sizeof(buf); while( stringtable.Decompress(buf, &size) ) { for( int i = 0; i < size; i++ ) { scanline[xpos] |= (buf[i] & mask) << shift; if( shift > 0 ) { shift -= bpp; } else { xpos++; shift = 8 - bpp; } if( ++x >= width ) { if( interlaced ) { y += g_GifInterlaceIncrement[interlacepass]; if( y >= height && interlacepass < GIF_INTERLACE_PASSES ) { y = g_GifInterlaceOffset[++interlacepass]; } } else { y++; } if( y >= height ) { stringtable.Done(); break; } x = xpos = 0; shift = 8 - bpp; scanline = FreeImage_GetScanLine(dib, height - y - 1); } } size = sizeof(buf); } io->read_proc(&b, 1, 1, handle); } if( page == 0 ) { size_t idx; //Logical Screen Descriptor io->seek_proc(handle, 6, SEEK_SET); WORD logicalwidth, logicalheight; io->read_proc(&logicalwidth, 2, 1, handle); io->read_proc(&logicalheight, 2, 1, handle); #ifdef FREEIMAGE_BIGENDIAN SwapShort(&logicalwidth); SwapShort(&logicalheight); #endif FreeImage_SetMetadataEx(FIMD_ANIMATION, dib, "LogicalWidth", ANIMTAG_LOGICALWIDTH, FIDT_SHORT, 1, 2, &logicalwidth); FreeImage_SetMetadataEx(FIMD_ANIMATION, dib, "LogicalHeight", ANIMTAG_LOGICALHEIGHT, FIDT_SHORT, 1, 2, &logicalheight); //Global Color Table if( info->global_color_table_offset != 0 ) { RGBQUAD globalpalette[256]; io->seek_proc(handle, info->global_color_table_offset, SEEK_SET); int i = 0; while( i < info->global_color_table_size ) { io->read_proc(&globalpalette[i].rgbRed, 1, 1, handle); io->read_proc(&globalpalette[i].rgbGreen, 1, 1, handle); io->read_proc(&globalpalette[i].rgbBlue, 1, 1, handle); globalpalette[i].rgbReserved = 0; i++; } FreeImage_SetMetadataEx(FIMD_ANIMATION, dib, "GlobalPalette", ANIMTAG_GLOBALPALETTE, FIDT_PALETTE, info->global_color_table_size, info->global_color_table_size * 4, globalpalette); //background color if( info->background_color < info->global_color_table_size ) { FreeImage_SetBackgroundColor(dib, &globalpalette[info->background_color]); } } //Application Extension LONG loop = 1; //If no AE with a loop count is found, the default must be 1 for( idx = 0; idx < info->application_extension_offsets.size(); idx++ ) { io->seek_proc(handle, info->application_extension_offsets[idx], SEEK_SET); io->read_proc(&b, 1, 1, handle); if( b == 11 ) { //All AEs start with an 11 byte sub-block to determine what type of AE it is char buf[11]; io->read_proc(buf, 11, 1, handle); if( !memcmp(buf, "NETSCAPE2.0", 11) || !memcmp(buf, "ANIMEXTS1.0", 11) ) { //Not everybody recognizes ANIMEXTS1.0 but it is valid io->read_proc(&b, 1, 1, handle); if( b == 3 ) { //we're supposed to have a 3 byte sub-block now io->read_proc(&b, 1, 1, handle); //this should be 0x01 but isn't really important io->read_proc(&w, 2, 1, handle); #ifdef FREEIMAGE_BIGENDIAN SwapShort(&w); #endif loop = w; if( loop > 0 ) loop++; break; } } } } FreeImage_SetMetadataEx(FIMD_ANIMATION, dib, "Loop", ANIMTAG_LOOP, FIDT_LONG, 1, 4, &loop); //Comment Extension for( idx = 0; idx < info->comment_extension_offsets.size(); idx++ ) { io->seek_proc(handle, info->comment_extension_offsets[idx], SEEK_SET); std::string comment; char buf[255]; io->read_proc(&b, 1, 1, handle); while( b ) { io->read_proc(buf, b, 1, handle); comment.append(buf, b); io->read_proc(&b, 1, 1, handle); } comment.append(1, '\0'); sprintf(buf, "Comment%d", idx); FreeImage_SetMetadataEx(FIMD_COMMENTS, dib, buf, 1, FIDT_ASCII, comment.size(), comment.size(), comment.c_str()); } } //Graphic Control Extension if( info->graphic_control_extension_offsets[page] != 0 ) { io->seek_proc(handle, info->graphic_control_extension_offsets[page] + 1, SEEK_SET); io->read_proc(&packed, 1, 1, handle); io->read_proc(&w, 2, 1, handle); #ifdef FREEIMAGE_BIGENDIAN SwapShort(&w); #endif io->read_proc(&b, 1, 1, handle); have_transparent = (packed & GIF_PACKED_GCE_HAVETRANS) ? true : false; disposal_method = (packed & GIF_PACKED_GCE_DISPOSAL) >> 2; delay_time = w * 10; //convert cs to ms transparent_color = b; if( have_transparent ) { int size = 1 << bpp; if( transparent_color <= size ) { BYTE table[256]; memset(table, 0xFF, size); table[transparent_color] = 0; FreeImage_SetTransparencyTable(dib, table, size); } } }
//!!!be sure to release memory before return null ResHandler* WIPResourceManager::alloc(const char* filename, WIPResourceType type) { ResHandler* res = new ResHandler; switch (type) { case TEXT: { } break; case TEXTURE: { TextureData *data = new TextureData; //初始化FreeImage FreeImage_Initialise(TRUE); FIBITMAP* bmpConverted = NULL; FREE_IMAGE_FORMAT fif = FIF_UNKNOWN; fif = FreeImage_GetFileType(filename); if (fif == FIF_UNKNOWN) fif = FreeImage_GetFIFFromFilename(filename); if ((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif)) { FIBITMAP *dib = FreeImage_Load(fif, filename); if (!dib) { printf("[fatal error]: \"%s\" load error!\n", filename); delete data; delete_handler(res); return NULL; } // we are top left, FIBITMAP is bottom left FreeImage_FlipVertical(dib); //get infomation FREE_IMAGE_TYPE imgType = FreeImage_GetImageType(dib); FREE_IMAGE_COLOR_TYPE colorType = FreeImage_GetColorType(dib); unsigned int bpp = FreeImage_GetBPP(dib); data->bpp = bpp; data->color_type = colorType; data->image_type = imgType; data->channel = 4; int x, y; RGBQUAD m_rgb; //获取图片长宽 int width = (int)FreeImage_GetWidth(dib); int height = (int)FreeImage_GetHeight(dib); unsigned char* imgBuf = new unsigned char[width*height * 4]; bool is_tr = FreeImage_IsTransparent(dib); bool is_little = FreeImage_IsLittleEndian(); //获取图片数据 //按RGBA格式保存到数组中 for (y = 0; y<height; y++) { for (x = 0; x<width; x++) { //获取像素值 FreeImage_GetPixelColor(dib, x, y, &m_rgb); if (is_little) { imgBuf[y*width * 4 + x * 4 + 0] = m_rgb.rgbRed; imgBuf[y*width * 4 + x * 4 + 1] = m_rgb.rgbGreen; imgBuf[y*width * 4 + x * 4 + 2] = m_rgb.rgbBlue; //判断是否透明图片 //如果是就取alpha值保存 if (is_tr) imgBuf[y*width * 4 + x * 4 + 3] = m_rgb.rgbReserved; else imgBuf[y*width * 4 + x * 4 + 3] = 255; } else { //大端警告! //Big Endian Warnning! printf("Note:This is a Big endian!\n"); } } } data->width = width; data->height = height; data->size = height*width * 4; FreeImage_Unload(dib); res->file_name = filename; res->extra = data; res->nref = 1; res->ptr = imgBuf; res->size = width*height * 4; res->type = TEXTURE; _map[filename] = res; return res; } } break; case SOUND: { } default: return res; break; } delete_handler(res); return NULL; }
FIBITMAP * DLL_CALLCONV FreeImage_Rescale(FIBITMAP *src, int dst_width, int dst_height, FREE_IMAGE_FILTER filter) { FIBITMAP *dst = NULL; if (!src || (dst_width <= 0) || (dst_height <= 0)) { return NULL; } // select the filter CGenericFilter *pFilter = NULL; switch(filter) { case FILTER_BOX: pFilter = new CBoxFilter(); break; case FILTER_BICUBIC: pFilter = new CBicubicFilter(); break; case FILTER_BILINEAR: pFilter = new CBilinearFilter(); break; case FILTER_BSPLINE: pFilter = new CBSplineFilter(); break; case FILTER_CATMULLROM: pFilter = new CCatmullRomFilter(); break; case FILTER_LANCZOS3: pFilter = new CLanczos3Filter(); break; } CResizeEngine Engine(pFilter); // perform upsampling or downsampling if((FreeImage_GetBPP(src) == 4) || (FreeImage_GetColorType(src) == FIC_PALETTE)) { // special case for 4-bit images or color map indexed images ... if(FreeImage_IsTransparent(src) == FALSE) { FIBITMAP *src24 = NULL; FIBITMAP *dst24 = NULL; try { // transparent conversion to 24-bit (any transparency table will be destroyed) src24 = FreeImage_ConvertTo24Bits(src); if(!src24) throw(1); // perform upsampling or downsampling dst24 = Engine.scale(src24, dst_width, dst_height); if(!dst24) throw(1); // color quantize to 8-bit dst = FreeImage_ColorQuantize(dst24, FIQ_WUQUANT); // free and return FreeImage_Unload(src24); FreeImage_Unload(dst24); } catch(int) { if(src24) FreeImage_Unload(src24); if(dst24) FreeImage_Unload(dst24); } } else { FIBITMAP *src32 = NULL; try { // transparent conversion to 32-bit (keep transparency) src32 = FreeImage_ConvertTo32Bits(src); if(!src32) throw(1); // perform upsampling or downsampling dst = Engine.scale(src32, dst_width, dst_height); if(!dst) throw(1); // free and return FreeImage_Unload(src32); } catch(int) { if(src32) FreeImage_Unload(src32); if(dst) FreeImage_Unload(dst); } } } else if((FreeImage_GetBPP(src) == 16) && (FreeImage_GetImageType(src) == FIT_BITMAP)) { // convert 16-bit RGB to 24-bit FIBITMAP *src24 = NULL; try { // transparent conversion to 24-bit (any transparency table will be destroyed) src24 = FreeImage_ConvertTo24Bits(src); if(!src24) throw(1); // perform upsampling or downsampling dst = Engine.scale(src24, dst_width, dst_height); if(!dst) throw(1); // free and return FreeImage_Unload(src24); } catch(int) { if(src24) FreeImage_Unload(src24); if(dst) FreeImage_Unload(dst); } } else { // normal case : // 1- or 8-bit greyscale, 24- or 32-bit RGB(A) images // 16-bit greyscale, 48- or 64-bit RGB(A) images // 32-bit float, 96- or 128-bit RGB(A) float images dst = Engine.scale(src, dst_width, dst_height); } delete pFilter; return dst; }
Ref<Image> loadFreeImage(const FileName& fileName) { FIBITMAP* dib = NULL; FREE_IMAGE_FORMAT fif = FreeImage_GetFileType(fileName.c_str()); //------------------------------------------------- // Sonderfall - unser Schutzformat "vrh" laden // ZLib-compressed HDR-Image! //------------------------------------------------- std::string ext = std::strlwr(fileName.ext()); if( ext == "vrh" ) { fif = FIF_HDR; dib = loadVRH(fileName); } else { if(FreeImage_FIFSupportsReading(fif)) dib = FreeImage_Load(fif, fileName.c_str()); } if(!dib) return NULL; FREE_IMAGE_COLOR_TYPE fic = FreeImage_GetColorType(dib); if(fic != FIC_RGB && fic != FIC_RGBALPHA) return NULL; BYTE* pixels = FreeImage_GetBits(dib); unsigned int width = FreeImage_GetWidth(dib); unsigned int height = FreeImage_GetHeight(dib); if((pixels == 0) || (width == 0) || (height == 0)) return NULL; FREE_IMAGE_TYPE fit = FreeImage_GetImageType(dib); // special image handling for float-images (e.g. *.HDR) if(fit == FIT_RGBF) { Image* out = new Image3f(width, height, fileName); for(unsigned int y = 0; y < out->height; y++) { FIRGBF* bits = (FIRGBF*)FreeImage_GetScanLine(dib, y); unsigned int y_pos = y; // Mirror HDR-images! if(fif == FIF_HDR) y_pos = (height - 1) - y; for(unsigned int x = 0; x < out->width; x++) { unsigned int x_pos = x; Color4 c; c.r = bits[x].red; c.g = bits[x].green; c.b = bits[x].blue; out->set(x_pos, y_pos, c); } } return out; } //--------------------------------- // normal bitmap images // --> Texturen // --> Backplates //--------------------------------- if(fit == FIT_BITMAP) { //Image* out = new Image3c(width, height, fileName); Ref<Image> out = new Image4c(width, height, fileName); unsigned int bpp = FreeImage_GetBPP(dib); BOOL bHasAlpha = FreeImage_IsTransparent(dib); float rcpMaxRGB = 1.0f / 255.0f; float rcpGamma = 1.0f; // 1.4f; // TEST - nach HDRI Handbuch ( Texturen um Gamma Wert dunker machen ) for(unsigned int y = 0; y < out->height; y++) { BYTE* bits = (BYTE*)FreeImage_GetScanLine(dib, y); for(unsigned int x = 0; x < out->width; x++) { Color4 c(0, 0, 0, 1 ); if(bpp == 8) { c.r = bits[x]; c.g = bits[x]; c.b = bits[x]; } if(bpp == 24) { RGBTRIPLE& Value = ((RGBTRIPLE*)bits)[x]; c.r = ( ((float)Value.rgbtRed ) * rcpMaxRGB )* rcpGamma ; c.g = ( ((float)Value.rgbtGreen) * rcpMaxRGB )* rcpGamma ; c.b = ( ((float)Value.rgbtBlue ) * rcpMaxRGB )* rcpGamma ; } if(bpp == 32) { RGBQUAD& Value = ((RGBQUAD*)bits)[x]; if(bHasAlpha && Value.rgbReserved < 255) // Alpha-channel { // Color = Magenta c.r = (255.0f) * rcpMaxRGB; c.g = ( 0.0f) * rcpMaxRGB; c.b = (255.0f) * rcpMaxRGB; } else { c.r = ( ((float)Value.rgbRed ) * rcpMaxRGB)* rcpGamma ; c.g = ( ((float)Value.rgbGreen) * rcpMaxRGB)* rcpGamma ; c.b = ( ((float)Value.rgbBlue ) * rcpMaxRGB)* rcpGamma ; } } out->set(x, y, c); } } return out; } return NULL; }
const int GetTextureReference(String filename, GLint clampmode, GLint filtermode, bool optional) { bool cached = false; TextureCacheEntry* currentCacheEntry = NULL; //check cache to see if it's loaded already std::map<String,TextureCacheEntry>::iterator it = theTextureCache.find(filename); // See if we already have it in the cache. if (it != theTextureCache.end()) { //std::cout << "Found cached texture - " << filename.c_str() << std::endl; // If we found it and it's not dirty, bail out with the index. if (!it->second.dirty) { return it->second.textureIndex; } // We found it, but it's dirty. We'll reload the texture below. cached = true; currentCacheEntry = &(it->second); } const char *texFile = filename.c_str(); // get the image file type from FreeImage FREE_IMAGE_FORMAT fifmt = FreeImage_GetFileType(texFile, 0); if (fifmt == FIF_UNKNOWN) { fifmt = FreeImage_GetFIFFromFilename(texFile); } //actually load the image file FIBITMAP *dib = FreeImage_Load(fifmt, texFile, 0); if (dib != NULL) { GLuint texRef = 0; // Only generate an index if it's not cached. if (cached) texRef = currentCacheEntry->textureIndex; else glGenTextures(1, &texRef); glBindTexture(GL_TEXTURE_2D, texRef); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, clampmode); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clampmode); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtermode); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtermode); GLenum format; int numComponents; if (FreeImage_IsTransparent(dib)) { numComponents = 4; //NOTE: FreeImage loads in BGR[A] on little-endian and RGB[A] on big-endian // doesn't matter since we're only using x86/Windows, but this would need to be // ifdeffed if we wanted to support cross-platform stuffs. -- SJML format = GL_BGRA_EXT; } else { numComponents = 3; //NOTE: see above format = GL_BGR_EXT; dib = FreeImage_ConvertTo24Bits(dib); //want to ensure we don't have an alpha } BYTE* pixels = (BYTE*)FreeImage_GetBits(dib); gluBuild2DMipmaps( GL_TEXTURE_2D, numComponents, FreeImage_GetWidth(dib), FreeImage_GetHeight(dib), format, GL_UNSIGNED_BYTE, pixels ); FreeImage_Unload(dib); //std::cout << "Loading - " << texFile << std::endl; // If it was cached, clear the dirty flag so we don't try and load it again. if (cached) { currentCacheEntry->dirty = false; } // If we're not cached, add a new entry. else { TextureCacheEntry newEntry; newEntry.filename = filename; newEntry.clampMode = clampmode; newEntry.filterMode = filtermode; newEntry.textureIndex = texRef; newEntry.dirty = false; theTextureCache[filename] = newEntry; } return texRef; } else { if (!optional) { std::cout << "Failed to find - " << texFile << std::endl; } return -1; } }
//加载图片 //以RGBA格式存储图片 static bool LoadImg(const char* fname,GLint nID) { //初始化FreeImage FreeImage_Initialise(TRUE); //定义图片格式为未知 FREE_IMAGE_FORMAT fif = FIF_UNKNOWN; //获取图片格式 fif = FreeImage_GetFileType(fname,0); //根据获取格式读取图片数据 FIBITMAP* bitmap = FreeImage_Load(fif,fname,0); if(!bitmap) { printf("load error!\n"); return false; } int x,y; RGBQUAD m_rgb; //获取图片长宽 width = (int)FreeImage_GetWidth(bitmap); height = (int)FreeImage_GetHeight(bitmap); imgBuf = new unsigned char[width*height*4]; //获取图片数据 //按RGBA格式保存到数组中 for(y=0;y<height;y++) { for(x=0;x<width;x++) { //获取像素值 FreeImage_GetPixelColor(bitmap,x,y,&m_rgb); //将RGB值存入数组 imgBuf[y*width*4+x*4+0] = m_rgb.rgbRed; imgBuf[y*width*4+x*4+1] = m_rgb.rgbGreen; imgBuf[y*width*4+x*4+2] = m_rgb.rgbBlue; //判断是否透明图片 //如果是就取alpha值保存 if(FreeImage_IsTransparent(bitmap)) imgBuf[y*width*4+x*4+3] = m_rgb.rgbReserved; else imgBuf[y*width*4+x*4+3] = 255; } } //绑定纹理ID if(nID==0) { glGenTextures(1, &g_texture1); glBindTexture(GL_TEXTURE_2D, g_texture1); } else { glGenTextures(1, &g_texture2); glBindTexture(GL_TEXTURE_2D, g_texture2); } glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imgBuf); //释放FreeImage delete imgBuf; FreeImage_Unload(bitmap); return true; }
static BOOL DLL_CALLCONV Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) { png_structp png_ptr; png_infop info_ptr; png_colorp palette = NULL; png_uint_32 width, height; BOOL has_alpha_channel = FALSE; RGBQUAD *pal; // pointer to dib palette int bit_depth, pixel_depth; // pixel_depth = bit_depth * channels int palette_entries; int interlace_type; fi_ioStructure fio; fio.s_handle = handle; fio.s_io = io; if ((dib) && (handle)) { try { // create the chunk manage structure png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, error_handler, warning_handler); if (!png_ptr) { return FALSE; } // allocate/initialize the image information data. info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); return FALSE; } // Set error handling. REQUIRED if you aren't supplying your own // error handling functions in the png_create_write_struct() call. if (setjmp(png_jmpbuf(png_ptr))) { // if we get here, we had a problem reading the file png_destroy_write_struct(&png_ptr, &info_ptr); return FALSE; } // init the IO png_set_write_fn(png_ptr, &fio, _WriteProc, _FlushProc); // set physical resolution png_uint_32 res_x = (png_uint_32)FreeImage_GetDotsPerMeterX(dib); png_uint_32 res_y = (png_uint_32)FreeImage_GetDotsPerMeterY(dib); if ((res_x > 0) && (res_y > 0)) { png_set_pHYs(png_ptr, info_ptr, res_x, res_y, PNG_RESOLUTION_METER); } // Set the image information here. Width and height are up to 2^31, // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, // or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED width = FreeImage_GetWidth(dib); height = FreeImage_GetHeight(dib); pixel_depth = FreeImage_GetBPP(dib); BOOL bInterlaced = FALSE; if( (flags & PNG_INTERLACED) == PNG_INTERLACED) { interlace_type = PNG_INTERLACE_ADAM7; bInterlaced = TRUE; } else { interlace_type = PNG_INTERLACE_NONE; } // set the ZLIB compression level or default to PNG default compression level (ZLIB level = 6) int zlib_level = flags & 0x0F; if((zlib_level >= 1) && (zlib_level <= 9)) { png_set_compression_level(png_ptr, zlib_level); } else if((flags & PNG_Z_NO_COMPRESSION) == PNG_Z_NO_COMPRESSION) { png_set_compression_level(png_ptr, Z_NO_COMPRESSION); } // filtered strategy works better for high color images if(pixel_depth >= 16){ png_set_compression_strategy(png_ptr, Z_FILTERED); png_set_filter(png_ptr, 0, PNG_FILTER_NONE|PNG_FILTER_SUB|PNG_FILTER_PAETH); } else { png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY); } FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); if(image_type == FIT_BITMAP) { // standard image type bit_depth = (pixel_depth > 8) ? 8 : pixel_depth; } else { // 16-bit greyscale or 16-bit RGB(A) bit_depth = 16; } switch (FreeImage_GetColorType(dib)) { case FIC_MINISWHITE: // Invert monochrome files to have 0 as black and 1 as white (no break here) png_set_invert_mono(png_ptr); case FIC_MINISBLACK: png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_GRAY, interlace_type, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); break; case FIC_PALETTE: { png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_PALETTE, interlace_type, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); // set the palette palette_entries = 1 << bit_depth; palette = (png_colorp)png_malloc(png_ptr, palette_entries * sizeof (png_color)); pal = FreeImage_GetPalette(dib); for (int i = 0; i < palette_entries; i++) { palette[i].red = pal[i].rgbRed; palette[i].green = pal[i].rgbGreen; palette[i].blue = pal[i].rgbBlue; } png_set_PLTE(png_ptr, info_ptr, palette, palette_entries); // You must not free palette here, because png_set_PLTE only makes a link to // the palette that you malloced. Wait until you are about to destroy // the png structure. break; } case FIC_RGBALPHA : has_alpha_channel = TRUE; png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_RGBA, interlace_type, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR // flip BGR pixels to RGB if(image_type == FIT_BITMAP) { png_set_bgr(png_ptr); } #endif break; case FIC_RGB: png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_RGB, interlace_type, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR // flip BGR pixels to RGB if(image_type == FIT_BITMAP) { png_set_bgr(png_ptr); } #endif break; case FIC_CMYK: break; } // write possible ICC profile FIICCPROFILE *iccProfile = FreeImage_GetICCProfile(dib); if (iccProfile->size && iccProfile->data) { png_set_iCCP(png_ptr, info_ptr, "Embedded Profile", 0, (png_const_bytep)iccProfile->data, iccProfile->size); } // write metadata WriteMetadata(png_ptr, info_ptr, dib); // Optional gamma chunk is strongly suggested if you have any guess // as to the correct gamma of the image. // png_set_gAMA(png_ptr, info_ptr, gamma); // set the transparency table if (FreeImage_IsTransparent(dib) && (FreeImage_GetTransparencyCount(dib) > 0)) { png_set_tRNS(png_ptr, info_ptr, FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib), NULL); } // set the background color if(FreeImage_HasBackgroundColor(dib)) { png_color_16 image_background; RGBQUAD rgbBkColor; FreeImage_GetBackgroundColor(dib, &rgbBkColor); memset(&image_background, 0, sizeof(png_color_16)); image_background.blue = rgbBkColor.rgbBlue; image_background.green = rgbBkColor.rgbGreen; image_background.red = rgbBkColor.rgbRed; image_background.index = rgbBkColor.rgbReserved; png_set_bKGD(png_ptr, info_ptr, &image_background); } // Write the file header information. png_write_info(png_ptr, info_ptr); // write out the image data #ifndef FREEIMAGE_BIGENDIAN if (bit_depth == 16) { // turn on 16 bit byte swapping png_set_swap(png_ptr); } #endif int number_passes = 1; if (bInterlaced) { number_passes = png_set_interlace_handling(png_ptr); } if ((pixel_depth == 32) && (!has_alpha_channel)) { BYTE *buffer = (BYTE *)malloc(width * 3); // transparent conversion to 24-bit // the number of passes is either 1 for non-interlaced images, or 7 for interlaced images for (int pass = 0; pass < number_passes; pass++) { for (png_uint_32 k = 0; k < height; k++) { FreeImage_ConvertLine32To24(buffer, FreeImage_GetScanLine(dib, height - k - 1), width); png_write_row(png_ptr, buffer); } } free(buffer); } else { // the number of passes is either 1 for non-interlaced images, or 7 for interlaced images for (int pass = 0; pass < number_passes; pass++) { for (png_uint_32 k = 0; k < height; k++) { png_write_row(png_ptr, FreeImage_GetScanLine(dib, height - k - 1)); } } } // It is REQUIRED to call this to finish writing the rest of the file // Bug with png_flush png_write_end(png_ptr, info_ptr); // clean up after the write, and free any memory allocated if (palette) { png_free(png_ptr, palette); } png_destroy_write_struct(&png_ptr, &info_ptr); return TRUE; } catch (const char *text) { FreeImage_OutputMessageProc(s_format_id, text); } } return FALSE; }
void fipWinImage::drawEx(HDC hDC, RECT& rcDest, BOOL useFileBkg, RGBQUAD *appBkColor, FIBITMAP *bg) const { // Convert to a standard bitmap if needed if(_bHasChanged) { if(_bDeleteMe) { FreeImage_Unload(_display_dib); _display_dib = NULL; _bDeleteMe = FALSE; } FREE_IMAGE_TYPE image_type = getImageType(); if(image_type == FIT_BITMAP) { BOOL bHasBackground = FreeImage_HasBackgroundColor(_dib); BOOL bIsTransparent = FreeImage_IsTransparent(_dib); if(!bIsTransparent && (!bHasBackground || !useFileBkg)) { // Copy pointer _display_dib = _dib; } else { // Create the transparent / alpha blended image _display_dib = FreeImage_Composite(_dib, useFileBkg, appBkColor, bg); if(_display_dib) { // Remember to delete _display_dib _bDeleteMe = TRUE; } else { // Something failed: copy pointers _display_dib = _dib; } } } else { // Convert to a standard dib for display if(image_type == FIT_COMPLEX) { // Convert to type FIT_DOUBLE FIBITMAP *dib_double = FreeImage_GetComplexChannel(_dib, FICC_MAG); // Convert to a standard bitmap (linear scaling) _display_dib = FreeImage_ConvertToStandardType(dib_double, TRUE); // Free image of type FIT_DOUBLE FreeImage_Unload(dib_double); } else if((image_type == FIT_RGBF) || (image_type == FIT_RGB16)) { // Apply a tone mapping algorithm and convert to 24-bit _display_dib = FreeImage_ToneMapping(_dib, _tmo, _tmo_param_1, _tmo_param_2); } else if(image_type == FIT_RGBA16) { // Convert to 32-bit FIBITMAP *dib32 = FreeImage_ConvertTo32Bits(_dib); if(dib32) { // Create the transparent / alpha blended image _display_dib = FreeImage_Composite(dib32, useFileBkg, appBkColor, bg); FreeImage_Unload(dib32); } } else { // Other cases: convert to a standard bitmap (linear scaling) _display_dib = FreeImage_ConvertToStandardType(_dib, TRUE); } // Remember to delete _display_dib _bDeleteMe = TRUE; } _bHasChanged = FALSE; } // Draw the dib SetStretchBltMode(hDC, COLORONCOLOR); StretchDIBits(hDC, rcDest.left, rcDest.top, rcDest.right-rcDest.left, rcDest.bottom-rcDest.top, 0, 0, FreeImage_GetWidth(_display_dib), FreeImage_GetHeight(_display_dib), FreeImage_GetBits(_display_dib), FreeImage_GetInfo(_display_dib), DIB_RGB_COLORS, SRCCOPY); }
/** @brief Composite a foreground image against a background color or a background image. The equation for computing a composited sample value is:<br> output = alpha * foreground + (1-alpha) * background<br> where alpha and the input and output sample values are expressed as fractions in the range 0 to 1. For colour images, the computation is done separately for R, G, and B samples. @param fg Foreground image @param useFileBkg If TRUE and a file background is present, use it as the background color @param appBkColor If not equal to NULL, and useFileBkg is FALSE, use this color as the background color @param bg If not equal to NULL and useFileBkg is FALSE and appBkColor is NULL, use this as the background image @return Returns the composite image if successful, returns NULL otherwise @see FreeImage_IsTransparent, FreeImage_HasBackgroundColor */ FIBITMAP * DLL_CALLCONV FreeImage_Composite(FIBITMAP *fg, BOOL useFileBkg, RGBQUAD *appBkColor, FIBITMAP *bg) { if(!FreeImage_HasPixels(fg)) return NULL; int width = FreeImage_GetWidth(fg); int height = FreeImage_GetHeight(fg); int bpp = FreeImage_GetBPP(fg); if((bpp != 8) && (bpp != 32)) return NULL; if(bg) { int bg_width = FreeImage_GetWidth(bg); int bg_height = FreeImage_GetHeight(bg); int bg_bpp = FreeImage_GetBPP(bg); if((bg_width != width) || (bg_height != height) || (bg_bpp != 24)) return NULL; } int bytespp = (bpp == 8) ? 1 : 4; int x, y, c; BYTE alpha = 0, not_alpha; BYTE index; RGBQUAD fgc; // foreground color RGBQUAD bkc; // background color memset(&fgc, 0, sizeof(RGBQUAD)); memset(&bkc, 0, sizeof(RGBQUAD)); // allocate the composite image FIBITMAP *composite = FreeImage_Allocate(width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); if(!composite) return NULL; // get the palette RGBQUAD *pal = FreeImage_GetPalette(fg); // retrieve the alpha table from the foreground image BOOL bIsTransparent = FreeImage_IsTransparent(fg); BYTE *trns = FreeImage_GetTransparencyTable(fg); // retrieve the background color from the foreground image BOOL bHasBkColor = FALSE; if(useFileBkg && FreeImage_HasBackgroundColor(fg)) { FreeImage_GetBackgroundColor(fg, &bkc); bHasBkColor = TRUE; } else { // no file background color // use application background color ? if(appBkColor) { memcpy(&bkc, appBkColor, sizeof(RGBQUAD)); bHasBkColor = TRUE; } // use background image ? else if(bg) { bHasBkColor = FALSE; } } for(y = 0; y < height; y++) { // foreground BYTE *fg_bits = FreeImage_GetScanLine(fg, y); // background BYTE *bg_bits = FreeImage_GetScanLine(bg, y); // composite image BYTE *cp_bits = FreeImage_GetScanLine(composite, y); for(x = 0; x < width; x++) { // foreground color + alpha if(bpp == 8) { // get the foreground color index = fg_bits[0]; memcpy(&fgc, &pal[index], sizeof(RGBQUAD)); // get the alpha if(bIsTransparent) { alpha = trns[index]; } else { alpha = 255; } } else if(bpp == 32) { // get the foreground color fgc.rgbBlue = fg_bits[FI_RGBA_BLUE]; fgc.rgbGreen = fg_bits[FI_RGBA_GREEN]; fgc.rgbRed = fg_bits[FI_RGBA_RED]; // get the alpha alpha = fg_bits[FI_RGBA_ALPHA]; } // background color if(!bHasBkColor) { if(bg) { // get the background color from the background image bkc.rgbBlue = bg_bits[FI_RGBA_BLUE]; bkc.rgbGreen = bg_bits[FI_RGBA_GREEN]; bkc.rgbRed = bg_bits[FI_RGBA_RED]; } else { // use a checkerboard pattern c = (((y & 0x8) == 0) ^ ((x & 0x8) == 0)) * 192; c = c ? c : 255; bkc.rgbBlue = (BYTE)c; bkc.rgbGreen = (BYTE)c; bkc.rgbRed = (BYTE)c; } } // composition if(alpha == 0) { // output = background cp_bits[FI_RGBA_BLUE] = bkc.rgbBlue; cp_bits[FI_RGBA_GREEN] = bkc.rgbGreen; cp_bits[FI_RGBA_RED] = bkc.rgbRed; } else if(alpha == 255) { // output = foreground cp_bits[FI_RGBA_BLUE] = fgc.rgbBlue; cp_bits[FI_RGBA_GREEN] = fgc.rgbGreen; cp_bits[FI_RGBA_RED] = fgc.rgbRed; } else { // output = alpha * foreground + (1-alpha) * background not_alpha = (BYTE)~alpha; cp_bits[FI_RGBA_BLUE] = (BYTE)((alpha * (WORD)fgc.rgbBlue + not_alpha * (WORD)bkc.rgbBlue) >> 8); cp_bits[FI_RGBA_GREEN] = (BYTE)((alpha * (WORD)fgc.rgbGreen + not_alpha * (WORD)bkc.rgbGreen) >> 8); cp_bits[FI_RGBA_RED] = (BYTE)((alpha * (WORD)fgc.rgbRed + not_alpha * (WORD)bkc.rgbRed) >> 8); } fg_bits += bytespp; bg_bits += 3; cp_bits += 3; } } // copy metadata from src to dst FreeImage_CloneMetadata(composite, fg); return composite; }
/** * @return true if transparency is enabled, else false */ bool fipImage::isTransparent(){ return FreeImage_IsTransparent( pImageData ); }