/** * Freeimage format to Indielib format. * @param pHandle the FIBITMAP that is used for calculation */ int FreeImageHelper::calculateINDFormat(FIBITMAP* pHandle) { FREE_IMAGE_TYPE imgType = FreeImage_GetImageType(pHandle); //Bitmap type (most common) if (FIT_BITMAP == imgType) { //Depending on the freeimage color type analysis, we determine our IND_ColorFormat FREE_IMAGE_COLOR_TYPE colorType = FreeImage_GetColorType(pHandle); if (FIC_MINISBLACK == colorType || FIC_MINISWHITE == colorType) { return IND_LUMINANCE; } else if (FIC_PALETTE == colorType) { return IND_COLOUR_INDEX; } else if (FIC_RGB == colorType) { //HACK: This is because when converting to 32 bits, even though there is alpha channel, //the color analysis function returns FIC_RGB, as alpha is opaque. We rely on that to know //if we have alpha channel so it's not good. if (FreeImage_GetBPP(pHandle) == 32) { return IND_RGBA; } else { return IND_RGB; } } else if (FIC_RGBALPHA == colorType) { return IND_RGBA; } } //TODO: OTHER IMAGE TYPES //Failure return IND_UNKNOWN; }
void FreeImageStack::loadImage(unsigned int iSlice, npp::ImageNPP_8u_C1 & rImage) const { NPP_ASSERT_MSG(iSlice < slices(), "Slice index exceeded number of slices in stack."); FIBITMAP * pBitmap = FreeImage_LockPage(pImageStack_, iSlice); NPP_ASSERT_NOT_NULL(pBitmap); // make sure this is an 8-bit single channel image NPP_DEBUG_ASSERT(FreeImage_GetColorType(pBitmap) == FIC_MINISBLACK); NPP_DEBUG_ASSERT(FreeImage_GetBPP(pBitmap) == 8); NPP_DEBUG_ASSERT(FreeImage_GetWidth(pBitmap) == nWidth_); NPP_DEBUG_ASSERT(FreeImage_GetHeight(pBitmap) == nHeight_); unsigned int nSrcPitch = FreeImage_GetPitch(pBitmap); unsigned char * pSrcData = FreeImage_GetBits(pBitmap); if (rImage.width() == nWidth_ && rImage.height() == nHeight_) { NPP_CHECK_CUDA(cudaMemcpy2D(rImage.data(), rImage.pitch(), pSrcData, nSrcPitch, nWidth_, nHeight_, cudaMemcpyHostToDevice)); } else { // create new NPP image npp::ImageNPP_8u_C1 oImage(nWidth_, nHeight_); // transfer slice data into new device image NPP_CHECK_CUDA(cudaMemcpy2D(oImage.data(), oImage.pitch(), pSrcData, nSrcPitch, nWidth_, nHeight_, cudaMemcpyHostToDevice)); // swap the result image with the reference passed into this method rImage.swap(oImage); } // release locked slice FreeImage_UnlockPage(pImageStack_, pBitmap, FALSE); }
FreeImageStack::FreeImageStack(const std::string & rFileName): sFileName_(rFileName) , pImageStack_(0) , nWidth_(0) , nHeight_(0) , pBitmap_32f_(0) , nMaxXY_(0) , nMaxOffset_(0) { // open the bitmap pImageStack_ = FreeImage_OpenMultiBitmap(FIF_TIFF, (sFileName_ + ".tif").c_str(), FALSE, // create new TRUE, // open read-only FALSE, // keep all slices in memory TIFF_DEFAULT); NPP_ASSERT_NOT_NULL(pImageStack_); NPP_ASSERT_NOT_NULL(slices()); FIBITMAP * pBitmap = FreeImage_LockPage(pImageStack_, 0); // store away the size of the first image // this information is later used to insure that all slices // accessed are of the same size. if they are not an exception // is thrown when such a deviating slice is being accessed nWidth_ = FreeImage_GetWidth(pBitmap); nHeight_ = FreeImage_GetHeight(pBitmap); NPP_ASSERT(FreeImage_GetColorType(pBitmap) == FIC_MINISBLACK); NPP_ASSERT(FreeImage_GetBPP(pBitmap) == 8); FreeImage_UnlockPage(pImageStack_, pBitmap, FALSE); }
/** @brief Inverts each pixel data. @param src Input image to be processed. @return Returns TRUE if successful, FALSE otherwise. */ BOOL DLL_CALLCONV FreeImage_Invert(FIBITMAP *src) { unsigned i, x, y, k; BYTE *bits; if (!src) return FALSE; int bpp = FreeImage_GetBPP(src); switch(bpp) { case 1 : case 4 : case 8 : { // if the dib has a colormap, just invert it // else, keep the linear grayscale if (FreeImage_GetColorType(src) == FIC_PALETTE) { RGBQUAD *pal = FreeImage_GetPalette(src); for(i = 0; i < FreeImage_GetColorsUsed(src); i++) { pal[i].rgbRed = 255 - pal[i].rgbRed; pal[i].rgbGreen = 255 - pal[i].rgbGreen; pal[i].rgbBlue = 255 - pal[i].rgbBlue; } } else { for(y = 0; y < FreeImage_GetHeight(src); y++) { bits = FreeImage_GetScanLine(src, y); for (x = 0; x < FreeImage_GetLine(src); x++) { bits[x] = ~bits[x]; } } } break; } case 24 : case 32 : { unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src); for(y = 0; y < FreeImage_GetHeight(src); y++) { bits = FreeImage_GetScanLine(src, y); for(x = 0; x < FreeImage_GetWidth(src); x++) { for(k = 0; k < bytespp; k++) { bits[k] = ~bits[k]; } bits += bytespp; } } break; } } return TRUE; }
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 }
const Texture* Texture::load(const std::string& fileName) { if (sTextureMap.find(fileName) != sTextureMap.end()) { unload(sTextureMap[fileName]); } const std::string path = sBasePath + fileName; FREE_IMAGE_FORMAT fif = FreeImage_GetFileType(path.c_str(), 0); if (fif == FIF_UNKNOWN) { fif = FreeImage_GetFIFFromFilename(path.c_str()); } if (fif == FIF_UNKNOWN) { return nullptr; } FIBITMAP* dib = nullptr; if (FreeImage_FIFSupportsReading(fif)) { dib = FreeImage_Load(fif, path.c_str()); } if (!dib) { return nullptr; } BYTE* bits = FreeImage_GetBits(dib); unsigned int width = FreeImage_GetWidth(dib); unsigned int height = FreeImage_GetHeight(dib); if (bits == 0 || width == 0 || height == 0) { return nullptr; } FREE_IMAGE_COLOR_TYPE colorType = FreeImage_GetColorType(dib); FREE_IMAGE_TYPE imageType = FreeImage_GetImageType(dib); GLenum glFormat = getGLFormat(colorType); Texture tex; tex.mName = fileName; glGenTextures(1, &tex.mId); assert(tex.mId); glBindTexture(GL_TEXTURE_2D, tex.mId); glTexImage2D(GL_TEXTURE_2D, 0, glFormat, width, height, 0, glFormat, GL_UNSIGNED_BYTE, bits); glGenerateMipmap(GL_TEXTURE_2D); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); sTextureMap[fileName] = tex; FreeImage_Unload(dib); return &sTextureMap[fileName]; }
BOOL DLL_CALLCONV FreeImage_IsTransparent(FIBITMAP *dib) { if(dib) { if(FreeImage_GetBPP(dib) == 32) { if(FreeImage_GetColorType(dib) == FIC_RGBALPHA) { return TRUE; } } else { return ((FREEIMAGEHEADER *)dib->data)->transparent ? TRUE : FALSE; } } return FALSE; }
std::ostream & operator <<(std::ostream &rOutputStream, const FIBITMAP &rBitmap) { unsigned int nImageWidth = FreeImage_GetWidth(const_cast<FIBITMAP *>(&rBitmap)); unsigned int nImageHeight = FreeImage_GetHeight(const_cast<FIBITMAP *>(&rBitmap)); unsigned int nPitch = FreeImage_GetPitch(const_cast<FIBITMAP *>(&rBitmap)); unsigned int nBPP = FreeImage_GetBPP(const_cast<FIBITMAP *>(&rBitmap)); FREE_IMAGE_COLOR_TYPE eType = FreeImage_GetColorType(const_cast<FIBITMAP *>(&rBitmap)); BITMAPINFO *pInfo = FreeImage_GetInfo(const_cast<FIBITMAP *>(&rBitmap)); rOutputStream << "Size (" << FreeImage_GetWidth(const_cast<FIBITMAP *>(&rBitmap)) << ", " << FreeImage_GetHeight(const_cast<FIBITMAP *>(&rBitmap)) << ")\n"; rOutputStream << "Pitch " << FreeImage_GetPitch(const_cast<FIBITMAP *>(&rBitmap)) << "\n"; rOutputStream << "Type "; switch (eType) { case FIC_MINISWHITE: rOutputStream << "FIC_MINISWHITE\n"; break; case FIC_MINISBLACK: rOutputStream << "FIC_MINISBLACK\n"; break; case FIC_RGB: rOutputStream << "FIC_RGB\n"; break; case FIC_PALETTE: rOutputStream << "FIC_PALETTE\n"; break; case FIC_RGBALPHA: rOutputStream << "FIC_RGBALPHA\n"; break; case FIC_CMYK: rOutputStream << "FIC_CMYK\n"; break; default: rOutputStream << "Unknown pixel format.\n"; } rOutputStream << "BPP " << nBPP << std::endl; return rOutputStream; }
Types::ColorTypes ImageLoaderFreeImage::colorDataType() const { Types::ColorTypes colorDatatype = Types::ColorTypeRGB; const FREE_IMAGE_COLOR_TYPE imageColorType = FreeImage_GetColorType(m_bitmap); if (imageColorType == FIC_MINISBLACK || imageColorType == FIC_MINISWHITE) { colorDatatype = bitsPerPixel() == 1 ? Types::ColorTypeMonochrome : Types::ColorTypeGreyscale; } else { colorDatatype = imageColorType == FIC_PALETTE ? Types::ColorTypePalette : imageColorType == FIC_RGB ? Types::ColorTypeRGB : imageColorType == FIC_RGBALPHA ? Types::ColorTypeRGBA : /* imageColorType == FIC_CMYK ? */ Types::ColorTypeCMYK; } return colorDatatype; }
//---------------------------------------------------- void putBmpIntoPixels(FIBITMAP * bmp, ofPixels &pix, bool swapForLittleEndian = true){ int width = FreeImage_GetWidth(bmp); int height = FreeImage_GetHeight(bmp); int bpp = FreeImage_GetBPP(bmp); FIBITMAP * bmpTemp = NULL; switch (bpp){ case 8: if (FreeImage_GetColorType(bmp) == FIC_PALETTE) { bmpTemp = FreeImage_ConvertTo24Bits(bmp); bmp = bmpTemp; bpp = FreeImage_GetBPP(bmp); } else { // do nothing we are grayscale } break; case 24: // do nothing we are color break; case 32: // do nothing we are colorAlpha break; default: bmpTemp = FreeImage_ConvertTo24Bits(bmp); bmp = bmpTemp; bpp = FreeImage_GetBPP(bmp); break; } int bytesPerPixel = bpp / 8; pix.allocate(width, height, bpp); FreeImage_ConvertToRawBits(pix.getPixels(), bmp, width*bytesPerPixel, bpp, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, true); // get bits if (bmpTemp != NULL) FreeImage_Unload(bmpTemp); #ifdef TARGET_LITTLE_ENDIAN if(swapForLittleEndian) pix.swapRgb(); #endif }
/** @brief Determines, whether a palletized image is visually greyscale or not. Unlike with FreeImage_GetColorType, which returns either FIC_MINISBLACK or FIC_MINISWHITE for a greyscale image with a linear ramp palette, the return value of this function does not depend on the palette's order, but only on the palette's individual colors. @param dib The image to be tested. @return Returns TRUE if the palette of the image specified contains only greyscales, FALSE otherwise. */ static BOOL IsVisualGreyscaleImage(FIBITMAP *dib) { switch (FreeImage_GetBPP(dib)) { case 1: case 4: case 8: { unsigned ncolors = FreeImage_GetColorsUsed(dib); RGBQUAD *rgb = FreeImage_GetPalette(dib); for (unsigned i = 0; i< ncolors; i++) { if ((rgb->rgbRed != rgb->rgbGreen) || (rgb->rgbRed != rgb->rgbBlue)) { return FALSE; } } return TRUE; } default: { return (FreeImage_GetColorType(dib) == FIC_MINISBLACK); } } }
/// Load a gray-scale image from disk. void loadImage(const std::string & rFileName, ImageCPU_8u_C1 & rImage) { // set your own FreeImage error handler FreeImage_SetOutputMessage(FreeImageErrorHandler); FREE_IMAGE_FORMAT eFormat = FreeImage_GetFileType(rFileName.c_str()); // no signature? try to guess the file format from the file extension if (eFormat == FIF_UNKNOWN) eFormat = FreeImage_GetFIFFromFilename(rFileName.c_str()); NPP_ASSERT(eFormat != FIF_UNKNOWN); // check that the plugin has reading capabilities ... FIBITMAP * pBitmap; if (FreeImage_FIFSupportsReading(eFormat)) pBitmap = FreeImage_Load(eFormat, rFileName.c_str()); NPP_ASSERT(pBitmap != 0); // make sure this is an 8-bit single channel image NPP_ASSERT(FreeImage_GetColorType(pBitmap) == FIC_MINISBLACK); NPP_ASSERT(FreeImage_GetBPP(pBitmap) == 8); // create an ImageCPU to receive the loaded image data ImageCPU_8u_C1 oImage(FreeImage_GetWidth(pBitmap), FreeImage_GetHeight(pBitmap)); // Copy the FreeImage data into the new ImageCPU unsigned int nSrcPitch = FreeImage_GetPitch(pBitmap); const Npp8u * pSrcLine = FreeImage_GetBits(pBitmap) + nSrcPitch * (FreeImage_GetHeight(pBitmap) -1); Npp8u * pDstLine = oImage.data(); unsigned int nDstPitch = oImage.pitch(); for (size_t iLine = 0; iLine < oImage.height(); ++iLine) { memcpy(pDstLine, pSrcLine, oImage.width() * sizeof(Npp8u)); pSrcLine -= nSrcPitch; pDstLine += nDstPitch; } // swap the user given image with our result image, effecively // moving our newly loaded image data into the user provided shell oImage.swap(rImage); }
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 DLL_CALLCONV FreeImage_IsTransparent(FIBITMAP *dib) { if(dib) { FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); switch(image_type) { case FIT_BITMAP: if(FreeImage_GetBPP(dib) == 32) { if(FreeImage_GetColorType(dib) == FIC_RGBALPHA) { return TRUE; } } else { return ((FREEIMAGEHEADER *)dib->data)->transparent ? TRUE : FALSE; } break; case FIT_RGBA16: case FIT_RGBAF: return TRUE; default: break; } } return FALSE; }
FREE_IMAGE_COLOR_TYPE fipImage::getColorType() const { return FreeImage_GetColorType(_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; }
static FIBITMAP * LoadOS21XBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bits_offset) { FIBITMAP *dib = NULL; try { BITMAPINFOOS2_1X_HEADER bios2_1x; io->read_proc(&bios2_1x, sizeof(BITMAPINFOOS2_1X_HEADER), 1, handle); #ifdef FREEIMAGE_BIGENDIAN SwapOS21XHeader(&bios2_1x); #endif // keep some general information about the bitmap int used_colors = 0; int width = bios2_1x.biWidth; int height = bios2_1x.biHeight; int bit_count = bios2_1x.biBitCount; int pitch = CalculatePitch(CalculateLine(width, bit_count)); switch (bit_count) { case 1 : case 4 : case 8 : { used_colors = CalculateUsedPaletteEntries(bit_count); // allocate enough memory to hold the bitmap (header, palette, pixels) and read the palette dib = FreeImage_Allocate(width, height, bit_count); if (dib == NULL) throw "DIB allocation failed"; BITMAPINFOHEADER *pInfoHeader = FreeImage_GetInfoHeader(dib); pInfoHeader->biXPelsPerMeter = 0; pInfoHeader->biYPelsPerMeter = 0; // load the palette RGBQUAD *pal = FreeImage_GetPalette(dib); for (int count = 0; count < used_colors; count++) { FILE_BGR bgr; io->read_proc(&bgr, sizeof(FILE_BGR), 1, handle); pal[count].rgbRed = bgr.r; pal[count].rgbGreen = bgr.g; pal[count].rgbBlue = bgr.b; } // Skip over the optional palette // A 24 or 32 bit DIB may contain a palette for faster color reduction io->seek_proc(handle, bitmap_bits_offset, SEEK_SET); // read the pixel data if (height > 0) { io->read_proc((void *)FreeImage_GetBits(dib), height * pitch, 1, handle); } else { for (int c = 0; c < abs(height); ++c) { io->read_proc((void *)FreeImage_GetScanLine(dib, height - c - 1), pitch, 1, handle); } } return dib; } case 16 : { dib = FreeImage_Allocate(width, height, bit_count, FI16_555_RED_MASK, FI16_555_GREEN_MASK, FI16_555_BLUE_MASK); if (dib == NULL) throw "DIB allocation failed"; BITMAPINFOHEADER *pInfoHeader = FreeImage_GetInfoHeader(dib); pInfoHeader->biXPelsPerMeter = 0; pInfoHeader->biYPelsPerMeter = 0; io->read_proc(FreeImage_GetBits(dib), height * pitch, 1, handle); #ifdef FREEIMAGE_BIGENDIAN for(int y = 0; y < FreeImage_GetHeight(dib); y++) { WORD *pixel = (WORD *)FreeImage_GetScanLine(dib, y); for(int x = 0; x < FreeImage_GetWidth(dib); x++) { SwapShort(pixel); pixel++; } } #endif return dib; } case 24 : case 32 : { if( bit_count == 32 ) { dib = FreeImage_Allocate(width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); } else { dib = FreeImage_Allocate(width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); } if (dib == NULL) throw "DIB allocation failed"; BITMAPINFOHEADER *pInfoHeader = FreeImage_GetInfoHeader(dib); pInfoHeader->biXPelsPerMeter = 0; pInfoHeader->biYPelsPerMeter = 0; // Skip over the optional palette // A 24 or 32 bit DIB may contain a palette for faster color reduction io->read_proc(FreeImage_GetBits(dib), height * pitch, 1, handle); #ifdef FREEIMAGE_BIGENDIAN for(int y = 0; y < FreeImage_GetHeight(dib); y++) { BYTE *pixel = FreeImage_GetScanLine(dib, y); for(int x = 0; x < FreeImage_GetWidth(dib); x++) { INPLACESWAP(pixel[0], pixel[2]); pixel += (bit_count>>3); } } #endif // check if the bitmap contains transparency, if so enable it in the header FreeImage_SetTransparent(dib, (FreeImage_GetColorType(dib) == FIC_RGBALPHA)); return dib; } } } catch(const char *message) { if(dib) FreeImage_Unload(dib); FreeImage_OutputMessageProc(s_format_id, message); } return NULL; }
static FIBITMAP * LoadOS22XBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bits_offset) { FIBITMAP *dib = NULL; try { // load the info header BITMAPINFOHEADER bih; io->read_proc(&bih, sizeof(BITMAPINFOHEADER), 1, handle); #ifdef FREEIMAGE_BIGENDIAN SwapInfoHeader(&bih); #endif // keep some general information about the bitmap int used_colors = bih.biClrUsed; int width = bih.biWidth; int height = bih.biHeight; int bit_count = bih.biBitCount; int compression = bih.biCompression; int pitch = CalculatePitch(CalculateLine(width, bit_count)); switch (bit_count) { case 1 : case 4 : case 8 : { if ((used_colors <= 0) || (used_colors > CalculateUsedPaletteEntries(bit_count))) used_colors = CalculateUsedPaletteEntries(bit_count); // allocate enough memory to hold the bitmap (header, palette, pixels) and read the palette dib = FreeImage_Allocate(width, height, bit_count); if (dib == NULL) throw "DIB allocation failed"; BITMAPINFOHEADER *pInfoHeader = FreeImage_GetInfoHeader(dib); pInfoHeader->biXPelsPerMeter = bih.biXPelsPerMeter; pInfoHeader->biYPelsPerMeter = bih.biYPelsPerMeter; // load the palette io->seek_proc(handle, sizeof(BITMAPFILEHEADER) + bih.biSize, SEEK_SET); RGBQUAD *pal = FreeImage_GetPalette(dib); for (int count = 0; count < used_colors; count++) { FILE_BGR bgr; io->read_proc(&bgr, sizeof(FILE_BGR), 1, handle); pal[count].rgbRed = bgr.r; pal[count].rgbGreen = bgr.g; pal[count].rgbBlue = bgr.b; } // seek to the actual pixel data. // this is needed because sometimes the palette is larger than the entries it contains predicts if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3))) io->seek_proc(handle, bitmap_bits_offset, SEEK_SET); // read the pixel data switch (compression) { case BI_RGB : if (height > 0) { io->read_proc((void *)FreeImage_GetBits(dib), height * pitch, 1, handle); } else { for (int c = 0; c < abs(height); ++c) { io->read_proc((void *)FreeImage_GetScanLine(dib, height - c - 1), pitch, 1, handle); } } return dib; case BI_RLE4 : { BYTE status_byte = 0; BYTE second_byte = 0; int scanline = 0; int bits = 0; BOOL low_nibble = FALSE; for (;;) { io->read_proc(&status_byte, sizeof(BYTE), 1, handle); switch (status_byte) { case RLE_COMMAND : io->read_proc(&status_byte, sizeof(BYTE), 1, handle); switch (status_byte) { case RLE_ENDOFLINE : bits = 0; scanline++; low_nibble = FALSE; break; case RLE_ENDOFBITMAP : return (FIBITMAP *)dib; case RLE_DELTA : { // read the delta values BYTE delta_x; BYTE delta_y; io->read_proc(&delta_x, sizeof(BYTE), 1, handle); io->read_proc(&delta_y, sizeof(BYTE), 1, handle); // apply them bits += delta_x / 2; scanline += delta_y; break; } default : io->read_proc(&second_byte, sizeof(BYTE), 1, handle); BYTE *sline = FreeImage_GetScanLine(dib, scanline); for (int i = 0; i < status_byte; i++) { if (low_nibble) { *(sline + bits) |= LOWNIBBLE(second_byte); if (i != status_byte - 1) io->read_proc(&second_byte, sizeof(BYTE), 1, handle); bits++; } else { *(sline + bits) |= HINIBBLE(second_byte); } low_nibble = !low_nibble; } if (((status_byte / 2) & 1 ) == 1) io->read_proc(&second_byte, sizeof(BYTE), 1, handle); break; }; break; default : { BYTE *sline = FreeImage_GetScanLine(dib, scanline); io->read_proc(&second_byte, sizeof(BYTE), 1, handle); for (unsigned i = 0; i < status_byte; i++) { if (low_nibble) { *(sline + bits) |= LOWNIBBLE(second_byte); bits++; } else { *(sline + bits) |= HINIBBLE(second_byte); } low_nibble = !low_nibble; } } break; }; } break; } case BI_RLE8 : { BYTE status_byte = 0; BYTE second_byte = 0; int scanline = 0; int bits = 0; for (;;) { io->read_proc(&status_byte, sizeof(BYTE), 1, handle); switch (status_byte) { case RLE_COMMAND : io->read_proc(&status_byte, sizeof(BYTE), 1, handle); switch (status_byte) { case RLE_ENDOFLINE : bits = 0; scanline++; break; case RLE_ENDOFBITMAP : return (FIBITMAP *)dib; case RLE_DELTA : { // read the delta values BYTE delta_x; BYTE delta_y; io->read_proc(&delta_x, sizeof(BYTE), 1, handle); io->read_proc(&delta_y, sizeof(BYTE), 1, handle); // apply them bits += delta_x; scanline += delta_y; break; } default : io->read_proc((void *)(FreeImage_GetScanLine(dib, scanline) + bits), sizeof(BYTE) * status_byte, 1, handle); // align run length to even number of bytes if ((status_byte & 1) == 1) io->read_proc(&second_byte, sizeof(BYTE), 1, handle); bits += status_byte; break; }; break; default : BYTE *sline = FreeImage_GetScanLine(dib, scanline); io->read_proc(&second_byte, sizeof(BYTE), 1, handle); for (unsigned i = 0; i < status_byte; i++) { *(sline + bits) = second_byte; bits++; } break; }; } break; } default : throw "compression type not supported"; } break; } case 16 : { if (bih.biCompression == 3) { DWORD bitfields[3]; io->read_proc(bitfields, 3 * sizeof(DWORD), 1, handle); dib = FreeImage_Allocate(width, height, bit_count, bitfields[0], bitfields[1], bitfields[2]); } else { dib = FreeImage_Allocate(width, height, bit_count, FI16_555_RED_MASK, FI16_555_GREEN_MASK, FI16_555_BLUE_MASK); } if (dib == NULL) throw "DIB allocation failed"; BITMAPINFOHEADER *pInfoHeader = FreeImage_GetInfoHeader(dib); pInfoHeader->biXPelsPerMeter = bih.biXPelsPerMeter; pInfoHeader->biYPelsPerMeter = bih.biYPelsPerMeter; if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3))) io->seek_proc(handle, bitmap_bits_offset, SEEK_SET); io->read_proc(FreeImage_GetBits(dib), height * pitch, 1, handle); #ifdef FREEIMAGE_BIGENDIAN for(int y = 0; y < FreeImage_GetHeight(dib); y++) { WORD *pixel = (WORD *)FreeImage_GetScanLine(dib, y); for(int x = 0; x < FreeImage_GetWidth(dib); x++) { SwapShort(pixel); pixel++; } } #endif return dib; } case 24 : case 32 : { if( bit_count == 32 ) { dib = FreeImage_Allocate(width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); } else { dib = FreeImage_Allocate(width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); } if (dib == NULL) throw "DIB allocation failed"; BITMAPINFOHEADER *pInfoHeader = FreeImage_GetInfoHeader(dib); pInfoHeader->biXPelsPerMeter = bih.biXPelsPerMeter; pInfoHeader->biYPelsPerMeter = bih.biYPelsPerMeter; // Skip over the optional palette // A 24 or 32 bit DIB may contain a palette for faster color reduction if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3))) io->seek_proc(handle, bitmap_bits_offset, SEEK_SET); // read in the bitmap bits io->read_proc(FreeImage_GetBits(dib), height * pitch, 1, handle); #ifdef FREEIMAGE_BIGENDIAN for(int y = 0; y < FreeImage_GetHeight(dib); y++) { BYTE *pixel = FreeImage_GetScanLine(dib, y); for(int x = 0; x < FreeImage_GetWidth(dib); x++) { INPLACESWAP(pixel[0], pixel[2]); pixel += (bit_count>>3); } } #endif // check if the bitmap contains transparency, if so enable it in the header FreeImage_SetTransparent(dib, (FreeImage_GetColorType(dib) == FIC_RGBALPHA)); return dib; } } } catch(const char *message) { if(dib) FreeImage_Unload(dib); FreeImage_OutputMessageProc(s_format_id, message); } return NULL; }
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; }
FIBITMAP * DLL_CALLCONV FreeImage_ConvertToFloat(FIBITMAP *dib) { FIBITMAP *src = NULL; FIBITMAP *dst = NULL; if(!FreeImage_HasPixels(dib)) return NULL; FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(dib); // check for allowed conversions switch(src_type) { case FIT_BITMAP: { // allow conversion from 8-bit if((FreeImage_GetBPP(dib) == 8) && (FreeImage_GetColorType(dib) == FIC_MINISBLACK)) { src = dib; } else { src = FreeImage_ConvertToGreyscale(dib); if(!src) return NULL; } break; } case FIT_UINT16: case FIT_RGB16: case FIT_RGBA16: case FIT_RGBF: case FIT_RGBAF: src = dib; break; case FIT_FLOAT: // float type : clone the src return FreeImage_Clone(dib); default: return NULL; } // allocate dst image const unsigned width = FreeImage_GetWidth(src); const unsigned height = FreeImage_GetHeight(src); dst = FreeImage_AllocateT(FIT_FLOAT, width, height); if(!dst) { if(src != dib) { FreeImage_Unload(src); } return NULL; } // copy metadata from src to dst FreeImage_CloneMetadata(dst, src); // convert from src type to float const unsigned src_pitch = FreeImage_GetPitch(src); const unsigned dst_pitch = FreeImage_GetPitch(dst); const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src); BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst); switch(src_type) { case FIT_BITMAP: { for(unsigned y = 0; y < height; y++) { const BYTE *src_pixel = (BYTE*)src_bits; float *dst_pixel = (float*)dst_bits; for(unsigned x = 0; x < width; x++) { // convert and scale to the range [0..1] dst_pixel[x] = (float)(src_pixel[x]) / 255; } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_UINT16: { for(unsigned y = 0; y < height; y++) { const WORD *src_pixel = (WORD*)src_bits; float *dst_pixel = (float*)dst_bits; for(unsigned x = 0; x < width; x++) { // convert and scale to the range [0..1] dst_pixel[x] = (float)(src_pixel[x]) / 65535; } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_RGB16: { for(unsigned y = 0; y < height; y++) { const FIRGB16 *src_pixel = (FIRGB16*)src_bits; float *dst_pixel = (float*)dst_bits; for(unsigned x = 0; x < width; x++) { // convert and scale to the range [0..1] dst_pixel[x] = LUMA_REC709(src_pixel[x].red, src_pixel[x].green, src_pixel[x].blue) / 65535.0F; } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_RGBA16: { for(unsigned y = 0; y < height; y++) { const FIRGBA16 *src_pixel = (FIRGBA16*)src_bits; float *dst_pixel = (float*)dst_bits; for(unsigned x = 0; x < width; x++) { // convert and scale to the range [0..1] dst_pixel[x] = LUMA_REC709(src_pixel[x].red, src_pixel[x].green, src_pixel[x].blue) / 65535.0F; } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_RGBF: { for(unsigned y = 0; y < height; y++) { const FIRGBF *src_pixel = (FIRGBF*)src_bits; float *dst_pixel = (float*)dst_bits; for(unsigned x = 0; x < width; x++) { // convert (assume pixel values are in the range [0..1]) dst_pixel[x] = LUMA_REC709(src_pixel[x].red, src_pixel[x].green, src_pixel[x].blue); } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_RGBAF: { for(unsigned y = 0; y < height; y++) { const FIRGBAF *src_pixel = (FIRGBAF*)src_bits; float *dst_pixel = (float*)dst_bits; for(unsigned x = 0; x < width; x++) { // convert (assume pixel values are in the range [0..1]) dst_pixel[x] = LUMA_REC709(src_pixel[x].red, src_pixel[x].green, src_pixel[x].blue); } src_bits += src_pitch; dst_bits += dst_pitch; } } break; } if(src != dib) { FreeImage_Unload(src); } return dst; }
static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { png_structp png_ptr = NULL; png_infop info_ptr; png_uint_32 width, height; png_colorp png_palette = NULL; int color_type, palette_entries = 0; int bit_depth, pixel_depth; // pixel_depth = bit_depth * channels FIBITMAP *dib = NULL; RGBQUAD *palette = NULL; // pointer to dib palette png_bytepp row_pointers = NULL; int i; fi_ioStructure fio; fio.s_handle = handle; fio.s_io = io; if (handle) { BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS; try { // check to see if the file is in fact a PNG file BYTE png_check[PNG_BYTES_TO_CHECK]; io->read_proc(png_check, PNG_BYTES_TO_CHECK, 1, handle); if (png_sig_cmp(png_check, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0) { return NULL; // Bad signature } // create the chunk manage structure png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, error_handler, warning_handler); if (!png_ptr) { return NULL; } // create the info structure info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return NULL; } // init the IO png_set_read_fn(png_ptr, &fio, _ReadProc); if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } // because we have already read the signature... png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); // read the IHDR chunk png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); pixel_depth = png_get_bit_depth(png_ptr, info_ptr) * png_get_channels(png_ptr, info_ptr); // get image data type (assume standard image type) FREE_IMAGE_TYPE image_type = FIT_BITMAP; if (bit_depth == 16) { if ((pixel_depth == 16) && (color_type == PNG_COLOR_TYPE_GRAY)) { image_type = FIT_UINT16; } else if ((pixel_depth == 48) && (color_type == PNG_COLOR_TYPE_RGB)) { image_type = FIT_RGB16; } else if ((pixel_depth == 64) && (color_type == PNG_COLOR_TYPE_RGB_ALPHA)) { image_type = FIT_RGBA16; } else { // tell libpng to strip 16 bit/color files down to 8 bits/color png_set_strip_16(png_ptr); bit_depth = 8; } } #ifndef FREEIMAGE_BIGENDIAN if((image_type == FIT_UINT16) || (image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) { // turn on 16 bit byte swapping png_set_swap(png_ptr); } #endif // set some additional flags switch(color_type) { case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR // flip the RGB pixels to BGR (or RGBA to BGRA) if(image_type == FIT_BITMAP) { png_set_bgr(png_ptr); } #endif break; case PNG_COLOR_TYPE_PALETTE: // expand palette images to the full 8 bits from 2 bits/pixel if (pixel_depth == 2) { png_set_packing(png_ptr); pixel_depth = 8; } break; case PNG_COLOR_TYPE_GRAY: // expand grayscale images to the full 8 bits from 2 bits/pixel // but *do not* expand fully transparent palette entries to a full alpha channel if (pixel_depth == 2) { png_set_expand_gray_1_2_4_to_8(png_ptr); pixel_depth = 8; } break; case PNG_COLOR_TYPE_GRAY_ALPHA: // expand 8-bit greyscale + 8-bit alpha to 32-bit png_set_gray_to_rgb(png_ptr); #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR // flip the RGBA pixels to BGRA png_set_bgr(png_ptr); #endif pixel_depth = 32; break; default: throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; } // unlike the example in the libpng documentation, we have *no* idea where // this file may have come from--so if it doesn't have a file gamma, don't // do any correction ("do no harm") if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) { double gamma = 0; double screen_gamma = 2.2; if (png_get_gAMA(png_ptr, info_ptr, &gamma) && ( flags & PNG_IGNOREGAMMA ) != PNG_IGNOREGAMMA) { png_set_gamma(png_ptr, screen_gamma, gamma); } } // all transformations have been registered; now update info_ptr data png_read_update_info(png_ptr, info_ptr); // color type may have changed, due to our transformations color_type = png_get_color_type(png_ptr,info_ptr); // create a DIB and write the bitmap header // set up the DIB palette, if needed switch (color_type) { case PNG_COLOR_TYPE_RGB: png_set_invert_alpha(png_ptr); if(image_type == FIT_BITMAP) { dib = FreeImage_AllocateHeader(header_only, width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); } else { dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth); } break; case PNG_COLOR_TYPE_RGB_ALPHA: if(image_type == FIT_BITMAP) { dib = FreeImage_AllocateHeader(header_only, width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); } else { dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth); } break; case PNG_COLOR_TYPE_PALETTE: dib = FreeImage_AllocateHeader(header_only, width, height, pixel_depth); png_get_PLTE(png_ptr,info_ptr, &png_palette, &palette_entries); palette_entries = MIN((unsigned)palette_entries, FreeImage_GetColorsUsed(dib)); palette = FreeImage_GetPalette(dib); // store the palette for (i = 0; i < palette_entries; i++) { palette[i].rgbRed = png_palette[i].red; palette[i].rgbGreen = png_palette[i].green; palette[i].rgbBlue = png_palette[i].blue; } break; case PNG_COLOR_TYPE_GRAY: dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth); if(pixel_depth <= 8) { palette = FreeImage_GetPalette(dib); palette_entries = 1 << pixel_depth; for (i = 0; i < palette_entries; i++) { palette[i].rgbRed = palette[i].rgbGreen = palette[i].rgbBlue = (BYTE)((i * 255) / (palette_entries - 1)); } } break; default: throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; } // store the transparency table if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { // array of alpha (transparency) entries for palette png_bytep trans_alpha = NULL; // number of transparent entries int num_trans = 0; // graylevel or color sample values of the single transparent color for non-paletted images png_color_16p trans_color = NULL; png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color); if((color_type == PNG_COLOR_TYPE_GRAY) && trans_color) { // single transparent color if (trans_color->gray < palette_entries) { BYTE table[256]; memset(table, 0xFF, palette_entries); table[trans_color->gray] = 0; FreeImage_SetTransparencyTable(dib, table, palette_entries); } } else if((color_type == PNG_COLOR_TYPE_PALETTE) && trans_alpha) { // transparency table FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans); } } // store the background color if (png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) { // Get the background color to draw transparent and alpha images over. // Note that even if the PNG file supplies a background, you are not required to // use it - you should use the (solid) application background if it has one. png_color_16p image_background = NULL; RGBQUAD rgbBkColor; if (png_get_bKGD(png_ptr, info_ptr, &image_background)) { rgbBkColor.rgbRed = (BYTE)image_background->red; rgbBkColor.rgbGreen = (BYTE)image_background->green; rgbBkColor.rgbBlue = (BYTE)image_background->blue; rgbBkColor.rgbReserved = 0; FreeImage_SetBackgroundColor(dib, &rgbBkColor); } } // get physical resolution if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) { png_uint_32 res_x, res_y; // we'll overload this var and use 0 to mean no phys data, // since if it's not in meters we can't use it anyway int res_unit_type = PNG_RESOLUTION_UNKNOWN; png_get_pHYs(png_ptr,info_ptr, &res_x, &res_y, &res_unit_type); if (res_unit_type == PNG_RESOLUTION_METER) { FreeImage_SetDotsPerMeterX(dib, res_x); FreeImage_SetDotsPerMeterY(dib, res_y); } } // get possible ICC profile if (png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP)) { png_charp profile_name = NULL; png_bytep profile_data = NULL; png_uint_32 profile_length = 0; int compression_type; png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &profile_length); // copy ICC profile data (must be done after FreeImage_AllocateHeader) FreeImage_CreateICCProfile(dib, profile_data, profile_length); } // --- header only mode => clean-up and return if (header_only) { // get possible metadata (it can be located both before and after the image data) ReadMetadata(png_ptr, info_ptr, dib); if (png_ptr) { // clean up after the read, and free any memory allocated - REQUIRED png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } return dib; } // set the individual row_pointers to point at the correct offsets row_pointers = (png_bytepp)malloc(height * sizeof(png_bytep)); if (!row_pointers) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); FreeImage_Unload(dib); return NULL; } // read in the bitmap bits via the pointer table // allow loading of PNG with minor errors (such as images with several IDAT chunks) for (png_uint_32 k = 0; k < height; k++) { row_pointers[height - 1 - k] = FreeImage_GetScanLine(dib, k); } png_set_benign_errors(png_ptr, 1); png_read_image(png_ptr, row_pointers); // check if the bitmap contains transparency, if so enable it in the header if (FreeImage_GetBPP(dib) == 32) { if (FreeImage_GetColorType(dib) == FIC_RGBALPHA) { FreeImage_SetTransparent(dib, TRUE); } else { FreeImage_SetTransparent(dib, FALSE); } } // cleanup if (row_pointers) { free(row_pointers); row_pointers = NULL; } // read the rest of the file, getting any additional chunks in info_ptr png_read_end(png_ptr, info_ptr); // get possible metadata (it can be located both before and after the image data) ReadMetadata(png_ptr, info_ptr, dib); if (png_ptr) { // clean up after the read, and free any memory allocated - REQUIRED png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } return dib; } catch (const char *text) { if (png_ptr) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } if (row_pointers) { free(row_pointers); } if (dib) { FreeImage_Unload(dib); } FreeImage_OutputMessageProc(s_format_id, text); return NULL; } } return NULL; }
BOOL fipImage::isGrayscale() const { return ((FreeImage_GetBPP(_dib) == 8) && (FreeImage_GetColorType(_dib) != FIC_PALETTE)); }
/** Write a FIBITMAP to a JNG stream @param format_id ID of the caller @param io Stream i/o functions @param dib Image to be saved @param handle Stream handle @param flags Saving flags @return Returns TRUE if successful, returns FALSE otherwise */ BOOL mng_WriteJNG(int format_id, FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int flags) { DWORD jng_width = 0; DWORD jng_height = 0; BYTE jng_color_type = 0; BYTE jng_image_sample_depth = 8; BYTE jng_image_compression_method = 8; // 8: ISO-10918-1 Huffman-coded baseline JPEG. BYTE jng_image_interlace_method = 0; BYTE jng_alpha_sample_depth = 0; BYTE jng_alpha_compression_method = 0; BYTE jng_alpha_filter_method = 0; BYTE jng_alpha_interlace_method = 0; BYTE buffer[16]; FIMEMORY *hJngMemory = NULL; FIMEMORY *hJpegMemory = NULL; FIMEMORY *hPngMemory = NULL; FIBITMAP *dib_rgb = NULL; FIBITMAP *dib_alpha = NULL; if(!dib || (FreeImage_GetImageType(dib) != FIT_BITMAP)) { return FALSE; } unsigned bpp = FreeImage_GetBPP(dib); switch(bpp) { case 8: if(FreeImage_GetColorType(dib) == FIC_MINISBLACK) { dib_rgb = dib; jng_color_type = MNG_COLORTYPE_JPEGGRAY; } else { // JPEG plugin will convert other types (FIC_MINISWHITE, FIC_PALETTE) to 24-bit on the fly //dib_rgb = FreeImage_ConvertTo24Bits(dib); dib_rgb = dib; jng_color_type = MNG_COLORTYPE_JPEGCOLOR; } break; case 24: dib_rgb = dib; jng_color_type = MNG_COLORTYPE_JPEGCOLOR; break; case 32: dib_rgb = FreeImage_ConvertTo24Bits(dib); jng_color_type = MNG_COLORTYPE_JPEGCOLORA; jng_alpha_sample_depth = 8; break; default: return FALSE; } jng_width = (DWORD)FreeImage_GetWidth(dib); jng_height = (DWORD)FreeImage_GetHeight(dib); try { hJngMemory = FreeImage_OpenMemory(); // --- write JNG file signature --- FreeImage_WriteMemory(g_jng_signature, 1, 8, hJngMemory); // --- write a JHDR chunk --- SwapLong(&jng_width); SwapLong(&jng_height); memcpy(&buffer[0], &jng_width, 4); memcpy(&buffer[4], &jng_height, 4); SwapLong(&jng_width); SwapLong(&jng_height); buffer[8] = jng_color_type; buffer[9] = jng_image_sample_depth; buffer[10] = jng_image_compression_method; buffer[11] = jng_image_interlace_method; buffer[12] = jng_alpha_sample_depth; buffer[13] = jng_alpha_compression_method; buffer[14] = jng_alpha_filter_method; buffer[15] = jng_alpha_interlace_method; mng_WriteChunk(mng_JHDR, &buffer[0], 16, hJngMemory); // --- write a sequence of JDAT chunks --- hJpegMemory = FreeImage_OpenMemory(); flags |= JPEG_BASELINE; if(!FreeImage_SaveToMemory(FIF_JPEG, dib_rgb, hJpegMemory, flags)) { throw (const char*)NULL; } if(dib_rgb != dib) { FreeImage_Unload(dib_rgb); dib_rgb = NULL; } { BYTE *jpeg_data = NULL; DWORD size_in_bytes = 0; // get a pointer to the stream buffer FreeImage_AcquireMemory(hJpegMemory, &jpeg_data, &size_in_bytes); // write chunks for(DWORD k = 0; k < size_in_bytes;) { DWORD bytes_left = size_in_bytes - k; DWORD chunk_size = MIN(JPEG_CHUNK_SIZE, bytes_left); mng_WriteChunk(mng_JDAT, &jpeg_data[k], chunk_size, hJngMemory); k += chunk_size; } } FreeImage_CloseMemory(hJpegMemory); hJpegMemory = NULL; // --- write alpha layer as a sequence of IDAT chunk --- if((bpp == 32) && (jng_color_type == MNG_COLORTYPE_JPEGCOLORA)) { dib_alpha = FreeImage_GetChannel(dib, FICC_ALPHA); hPngMemory = FreeImage_OpenMemory(); if(!FreeImage_SaveToMemory(FIF_PNG, dib_alpha, hPngMemory, PNG_DEFAULT)) { throw (const char*)NULL; } FreeImage_Unload(dib_alpha); dib_alpha = NULL; // get the IDAT chunk { BOOL bResult = FALSE; DWORD start_pos = 0; DWORD next_pos = 0; long offset = 8; do { // find the next IDAT chunk from 'offset' position bResult = mng_FindChunk(hPngMemory, mng_IDAT, offset, &start_pos, &next_pos); if(!bResult) break; BYTE *png_data = NULL; DWORD size_in_bytes = 0; // get a pointer to the stream buffer FreeImage_AcquireMemory(hPngMemory, &png_data, &size_in_bytes); // write the IDAT chunk mng_WriteChunk(mng_IDAT, &png_data[start_pos+8], next_pos - start_pos - 12, hJngMemory); offset = next_pos; } while(bResult); } FreeImage_CloseMemory(hPngMemory); hPngMemory = NULL; } // --- write a IEND chunk --- mng_WriteChunk(mng_IEND, NULL, 0, hJngMemory); // write the JNG on output stream { BYTE *jng_data = NULL; DWORD size_in_bytes = 0; FreeImage_AcquireMemory(hJngMemory, &jng_data, &size_in_bytes); io->write_proc(jng_data, 1, size_in_bytes, handle); } FreeImage_CloseMemory(hJngMemory); FreeImage_CloseMemory(hJpegMemory); FreeImage_CloseMemory(hPngMemory); return TRUE; } catch(const char *text) { FreeImage_CloseMemory(hJngMemory); FreeImage_CloseMemory(hJpegMemory); FreeImage_CloseMemory(hPngMemory); if(dib_rgb && (dib_rgb != dib)) { FreeImage_Unload(dib_rgb); } FreeImage_Unload(dib_alpha); if(text) { FreeImage_OutputMessageProc(format_id, text); } return FALSE; } }
unsigned int LoadTexture(const char* a_szTexture) { FIBITMAP* pBitmap = nullptr; // Determime File Type from File Signature FREE_IMAGE_FORMAT fif = FreeImage_GetFileType(a_szTexture, 0); // Success if (fif != FIF_UNKNOWN && FreeImage_FIFSupportsReading(fif)) { pBitmap = FreeImage_Load(fif, a_szTexture); } // Failure if (pBitmap == nullptr) { printf("Error: Failed to load image '%s'!\n", a_szTexture); return 0; } // Force the image to RGBA // Get size of pixel in bits unsigned int bpp = FreeImage_GetBPP(pBitmap); /* // How does this conversion to RGBA work? if( a_uiBPP != nullptr ) { *a_uiBPP = bpp/8; //RGBA has 8 bits per color channel... } */ // Get Color Type FREE_IMAGE_COLOR_TYPE fi_colourType = FreeImage_GetColorType(pBitmap); if (fi_colourType != FIC_RGBALPHA ) { FIBITMAP* ndib = FreeImage_ConvertTo32Bits(pBitmap); FreeImage_Unload(pBitmap); pBitmap = ndib; bpp = FreeImage_GetBPP(pBitmap); fi_colourType = FreeImage_GetColorType(pBitmap); } // get the pixel data BYTE* pData = FreeImage_GetBits(pBitmap); // try to determine data type of file (bytes/floats) FREE_IMAGE_TYPE fit = FreeImage_GetImageType(pBitmap); // VARIABLE = ( CONDITION TO EVALUATE ) ? IF_TRUE : IF_FALSE ; GLenum eType = (fit == FIT_RGBF || fit == FIT_FLOAT) ? GL_FLOAT:GL_UNSIGNED_BYTE; // Create variable to store OGL Tex ID GLuint textureID; // Generate OGL Tex ID glGenTextures( 1, &textureID ); // Bind Texture for Use by using the OGL Tex DI glBindTexture( GL_TEXTURE_2D, textureID ); // Texturing allows elements of an image array to be read by shaders. glTexImage2D( GL_TEXTURE_2D, // TARGET 0, // level of detail GL_RGBA, // color format FreeImage_GetWidth(pBitmap), // width FreeImage_GetHeight(pBitmap), // height 0, // border (must be 0) fi_colourType, // pixel data format - i.e. RGBA eType, // pixel data type pData); // data // specify default filtering and wrapping glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); // unbind texture glBindTexture( GL_TEXTURE_2D, 0 ); // delete data FreeImage_Unload(pBitmap); return textureID; }
bool FreeImage::onLoad() { switch ( this -> loadingType ) { case LoadingType::EMPTY: { this -> freeImage = FreeImage_Allocate( this -> size.x, this -> size.y, this -> BPP, 0, 0, 0 ); break; } case LoadingType::FILE: { // Check the file signature and deduce its format. #ifdef WIN32 FREE_IMAGE_FORMAT imageFormat = FreeImage_GetFileTypeU( fileNameW.toCString(), 0 ); #else FREE_IMAGE_FORMAT imageFormat = FreeImage_GetFileType( fileName.toCString(), 0 ); #endif // If still unknown, try to guess the file format from the file extension. if ( imageFormat == FIF_UNKNOWN ) { #ifdef WIN32 imageFormat = FreeImage_GetFIFFromFilenameU( fileNameW.toCString() ); #else imageFormat = FreeImage_GetFIFFromFilename( fileName.toCString() ); #endif } // If still unknown, return failure. if ( imageFormat == FIF_UNKNOWN ) { error( String( "Free Image was unable to detect the file format : " ) << fileName ); return false; } // Check that the plugin has reading capabilities and load the file. if ( FreeImage_FIFSupportsReading( imageFormat ) ) { #ifdef WIN32 this -> freeImage = FreeImage_LoadU( imageFormat, fileNameW.toCString() ); #else this -> freeImage = FreeImage_Load( imageFormat, fileName.toCString() ); #endif } if ( this -> freeImage == NULL ) { error( String( "Free Image was unable to load the picture : " ) << fileName ); return false; } if ( this -> size.x == 0 || this -> size.y == 0 ) { this -> size.x = FreeImage_GetWidth( this -> freeImage ); this -> size.y = FreeImage_GetHeight( this -> freeImage ); } if ( this -> loadingFormat == Format::UNDEFINED ) { switch ( FreeImage_GetColorType( this -> freeImage ) ) { case FIC_PALETTE: _updateFormat( Format::R ); break; case FIC_RGB: _updateFormat( Format::RGB ); break; default: _updateFormat( Format::RGBA ); break; } } log( this -> fileName << this -> size << " has been loaded successfully !" ); break; } } //if we have to flip vertically. if ( this -> invertY ) FreeImage_FlipVertical( this -> freeImage ); //Change BPP if ( this -> BPP != FreeImage_GetBPP( this -> freeImage ) ) _updateBPP(); //resize if ( this -> size != Math::Vec2<Size>( FreeImage_GetWidth( this -> freeImage ), FreeImage_GetHeight( this -> freeImage ) ) ) _updateSize(); this -> stride = FreeImage_GetPitch( this -> freeImage ); return true; }
FIBITMAP * DLL_CALLCONV FreeImage_ConvertToRGBF(FIBITMAP *dib) { FIBITMAP *src = NULL; FIBITMAP *dst = NULL; if(!FreeImage_HasPixels(dib)) return NULL; const FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(dib); // check for allowed conversions switch(src_type) { case FIT_BITMAP: { // allow conversion from 24- and 32-bit const FREE_IMAGE_COLOR_TYPE color_type = FreeImage_GetColorType(dib); if((color_type != FIC_RGB) && (color_type != FIC_RGBALPHA)) { src = FreeImage_ConvertTo24Bits(dib); if(!src) return NULL; } else { src = dib; } break; } case FIT_UINT16: // allow conversion from 16-bit src = dib; break; case FIT_RGB16: // allow conversion from 48-bit RGB src = dib; break; case FIT_RGBA16: // allow conversion from 64-bit RGBA (ignore the alpha channel) src = dib; break; case FIT_FLOAT: // allow conversion from 32-bit float src = dib; break; case FIT_RGBAF: // allow conversion from 128-bit RGBAF src = dib; break; case FIT_RGBF: // RGBF type : clone the src return FreeImage_Clone(dib); break; default: return NULL; } // allocate dst image const unsigned width = FreeImage_GetWidth(src); const unsigned height = FreeImage_GetHeight(src); dst = FreeImage_AllocateT(FIT_RGBF, width, height); if(!dst) { if(src != dib) { FreeImage_Unload(src); } return NULL; } // copy metadata from src to dst FreeImage_CloneMetadata(dst, src); // convert from src type to RGBF const unsigned src_pitch = FreeImage_GetPitch(src); const unsigned dst_pitch = FreeImage_GetPitch(dst); switch(src_type) { case FIT_BITMAP: { // calculate the number of bytes per pixel (3 for 24-bit or 4 for 32-bit) const unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src); const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src); BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst); for(unsigned y = 0; y < height; y++) { const BYTE *src_pixel = (BYTE*)src_bits; FIRGBF *dst_pixel = (FIRGBF*)dst_bits; for(unsigned x = 0; x < width; x++) { // convert and scale to the range [0..1] dst_pixel->red = (float)(src_pixel[FI_RGBA_RED]) / 255.0F; dst_pixel->green = (float)(src_pixel[FI_RGBA_GREEN]) / 255.0F; dst_pixel->blue = (float)(src_pixel[FI_RGBA_BLUE]) / 255.0F; src_pixel += bytespp; dst_pixel ++; } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_UINT16: { const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src); BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst); for(unsigned y = 0; y < height; y++) { const WORD *src_pixel = (WORD*)src_bits; FIRGBF *dst_pixel = (FIRGBF*)dst_bits; for(unsigned x = 0; x < width; x++) { // convert and scale to the range [0..1] const float dst_value = (float)src_pixel[x] / 65535.0F; dst_pixel[x].red = dst_value; dst_pixel[x].green = dst_value; dst_pixel[x].blue = dst_value; } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_RGB16: { const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src); BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst); for(unsigned y = 0; y < height; y++) { const FIRGB16 *src_pixel = (FIRGB16*) src_bits; FIRGBF *dst_pixel = (FIRGBF*) dst_bits; for(unsigned x = 0; x < width; x++) { // convert and scale to the range [0..1] dst_pixel[x].red = (float)(src_pixel[x].red) / 65535.0F; dst_pixel[x].green = (float)(src_pixel[x].green) / 65535.0F; dst_pixel[x].blue = (float)(src_pixel[x].blue) / 65535.0F; } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_RGBA16: { const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src); BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst); for(unsigned y = 0; y < height; y++) { const FIRGBA16 *src_pixel = (FIRGBA16*) src_bits; FIRGBF *dst_pixel = (FIRGBF*) dst_bits; for(unsigned x = 0; x < width; x++) { // convert and scale to the range [0..1] dst_pixel[x].red = (float)(src_pixel[x].red) / 65535.0F; dst_pixel[x].green = (float)(src_pixel[x].green) / 65535.0F; dst_pixel[x].blue = (float)(src_pixel[x].blue) / 65535.0F; } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_FLOAT: { const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src); BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst); for(unsigned y = 0; y < height; y++) { const float *src_pixel = (float*) src_bits; FIRGBF *dst_pixel = (FIRGBF*) dst_bits; for(unsigned x = 0; x < width; x++) { // convert by copying greyscale channel to each R, G, B channels // assume float values are in [0..1] const float value = CLAMP(src_pixel[x], 0.0F, 1.0F); dst_pixel[x].red = value; dst_pixel[x].green = value; dst_pixel[x].blue = value; } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_RGBAF: { const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src); BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst); for(unsigned y = 0; y < height; y++) { const FIRGBAF *src_pixel = (FIRGBAF*) src_bits; FIRGBF *dst_pixel = (FIRGBF*) dst_bits; for(unsigned x = 0; x < width; x++) { // convert and skip alpha channel dst_pixel[x].red = CLAMP(src_pixel[x].red, 0.0F, 1.0F); dst_pixel[x].green = CLAMP(src_pixel[x].green, 0.0F, 1.0F); dst_pixel[x].blue = CLAMP(src_pixel[x].blue, 0.0F, 1.0F); } src_bits += src_pitch; dst_bits += dst_pitch; } } break; } if(src != dib) { FreeImage_Unload(src); } return dst; }
static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_uint_32 width, height; int color_type; int bit_depth; int pixel_depth = 0; // pixel_depth = bit_depth * channels FIBITMAP *dib = NULL; png_bytepp row_pointers = NULL; fi_ioStructure fio; fio.s_handle = handle; fio.s_io = io; if (handle) { BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS; try { // check to see if the file is in fact a PNG file BYTE png_check[PNG_BYTES_TO_CHECK]; io->read_proc(png_check, PNG_BYTES_TO_CHECK, 1, handle); if (png_sig_cmp(png_check, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0) { return NULL; // Bad signature } // create the chunk manage structure png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, error_handler, warning_handler); if (!png_ptr) { return NULL; } // create the info structure info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return NULL; } // init the IO png_set_read_fn(png_ptr, &fio, _ReadProc); if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } // because we have already read the signature... png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); // read the IHDR chunk png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); // configure the decoder FREE_IMAGE_TYPE image_type = FIT_BITMAP; if(!ConfigureDecoder(png_ptr, info_ptr, flags, &image_type)) { throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; } // update image info color_type = png_get_color_type(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); pixel_depth = bit_depth * png_get_channels(png_ptr, info_ptr); // create a dib and write the bitmap header // set up the dib palette, if needed switch (color_type) { case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); break; case PNG_COLOR_TYPE_PALETTE: dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); if(dib) { png_colorp png_palette = NULL; int palette_entries = 0; png_get_PLTE(png_ptr,info_ptr, &png_palette, &palette_entries); palette_entries = MIN((unsigned)palette_entries, FreeImage_GetColorsUsed(dib)); // store the palette RGBQUAD *palette = FreeImage_GetPalette(dib); for(int i = 0; i < palette_entries; i++) { palette[i].rgbRed = png_palette[i].red; palette[i].rgbGreen = png_palette[i].green; palette[i].rgbBlue = png_palette[i].blue; } } break; case PNG_COLOR_TYPE_GRAY: dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); if(dib && (pixel_depth <= 8)) { RGBQUAD *palette = FreeImage_GetPalette(dib); const int palette_entries = 1 << pixel_depth; for(int i = 0; i < palette_entries; i++) { palette[i].rgbRed = palette[i].rgbGreen = palette[i].rgbBlue = (BYTE)((i * 255) / (palette_entries - 1)); } } break; default: throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; } if(!dib) { throw FI_MSG_ERROR_DIB_MEMORY; } // store the transparency table if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { // array of alpha (transparency) entries for palette png_bytep trans_alpha = NULL; // number of transparent entries int num_trans = 0; // graylevel or color sample values of the single transparent color for non-paletted images png_color_16p trans_color = NULL; png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color); if((color_type == PNG_COLOR_TYPE_GRAY) && trans_color) { // single transparent color if (trans_color->gray < 256) { BYTE table[256]; memset(table, 0xFF, 256); table[trans_color->gray] = 0; FreeImage_SetTransparencyTable(dib, table, 256); } // check for a full transparency table, too else if ((trans_alpha) && (pixel_depth <= 8)) { FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans); } } else if((color_type == PNG_COLOR_TYPE_PALETTE) && trans_alpha) { // transparency table FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans); } } // store the background color (only supported for FIT_BITMAP types) if ((image_type == FIT_BITMAP) && png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) { // Get the background color to draw transparent and alpha images over. // Note that even if the PNG file supplies a background, you are not required to // use it - you should use the (solid) application background if it has one. png_color_16p image_background = NULL; RGBQUAD rgbBkColor; if (png_get_bKGD(png_ptr, info_ptr, &image_background)) { rgbBkColor.rgbRed = (BYTE)image_background->red; rgbBkColor.rgbGreen = (BYTE)image_background->green; rgbBkColor.rgbBlue = (BYTE)image_background->blue; rgbBkColor.rgbReserved = 0; FreeImage_SetBackgroundColor(dib, &rgbBkColor); } } // get physical resolution if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) { png_uint_32 res_x, res_y; // we'll overload this var and use 0 to mean no phys data, // since if it's not in meters we can't use it anyway int res_unit_type = PNG_RESOLUTION_UNKNOWN; png_get_pHYs(png_ptr,info_ptr, &res_x, &res_y, &res_unit_type); if (res_unit_type == PNG_RESOLUTION_METER) { FreeImage_SetDotsPerMeterX(dib, res_x); FreeImage_SetDotsPerMeterY(dib, res_y); } } // get possible ICC profile if (png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP)) { png_charp profile_name = NULL; png_bytep profile_data = NULL; png_uint_32 profile_length = 0; int compression_type; png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &profile_length); // copy ICC profile data (must be done after FreeImage_AllocateHeader) FreeImage_CreateICCProfile(dib, profile_data, profile_length); } // --- header only mode => clean-up and return if (header_only) { // get possible metadata (it can be located both before and after the image data) ReadMetadata(png_ptr, info_ptr, dib); if (png_ptr) { // clean up after the read, and free any memory allocated - REQUIRED png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } return dib; } // set the individual row_pointers to point at the correct offsets row_pointers = (png_bytepp)malloc(height * sizeof(png_bytep)); if (!row_pointers) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); FreeImage_Unload(dib); return NULL; } // read in the bitmap bits via the pointer table // allow loading of PNG with minor errors (such as images with several IDAT chunks) for (png_uint_32 k = 0; k < height; k++) { row_pointers[height - 1 - k] = FreeImage_GetScanLine(dib, k); } png_set_benign_errors(png_ptr, 1); png_read_image(png_ptr, row_pointers); // check if the bitmap contains transparency, if so enable it in the header if (FreeImage_GetBPP(dib) == 32) { if (FreeImage_GetColorType(dib) == FIC_RGBALPHA) { FreeImage_SetTransparent(dib, TRUE); } else { FreeImage_SetTransparent(dib, FALSE); } } // cleanup if (row_pointers) { free(row_pointers); row_pointers = NULL; } // read the rest of the file, getting any additional chunks in info_ptr png_read_end(png_ptr, info_ptr); // get possible metadata (it can be located both before and after the image data) ReadMetadata(png_ptr, info_ptr, dib); if (png_ptr) { // clean up after the read, and free any memory allocated - REQUIRED png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } return dib; } catch (const char *text) { if (png_ptr) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } if (row_pointers) { free(row_pointers); } if (dib) { FreeImage_Unload(dib); } FreeImage_OutputMessageProc(s_format_id, text); return NULL; } } return NULL; }
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; }
unsigned int AIE::LoadTexture(const char* a_szTexture, unsigned int a_uiFormat /* = GL_RGBA */, unsigned int* a_uiWidth /* = nullptr */, unsigned int* a_uiHeight /* = nullptr */, unsigned int* a_uiBPP /* = nullptr*/) { FIBITMAP* pBitmap = nullptr; // check the file signature and deduce its format and load it FREE_IMAGE_FORMAT fif = FreeImage_GetFileType(a_szTexture, 0); if (fif != FIF_UNKNOWN && FreeImage_FIFSupportsReading(fif)) { pBitmap = FreeImage_Load(fif, a_szTexture); } if (pBitmap == nullptr) { printf("Error: Failed to load image '%s'!\n", a_szTexture); return 0; } // optionally get the image width and height if (a_uiWidth != nullptr) *a_uiWidth = FreeImage_GetWidth(pBitmap); if (a_uiHeight != nullptr) *a_uiHeight = FreeImage_GetHeight(pBitmap); // force the image to RGBA unsigned int bpp = FreeImage_GetBPP(pBitmap); if( a_uiBPP != nullptr ) *a_uiBPP = bpp/8; FREE_IMAGE_COLOR_TYPE fi_colourType = FreeImage_GetColorType(pBitmap); if (fi_colourType != FIC_RGBALPHA ) { FIBITMAP* ndib = FreeImage_ConvertTo32Bits(pBitmap); FreeImage_Unload(pBitmap); pBitmap = ndib; bpp = FreeImage_GetBPP(pBitmap); fi_colourType = FreeImage_GetColorType(pBitmap); } // get the pixel data BYTE* pData = FreeImage_GetBits(pBitmap); // try to determine data type of file (bytes/floats) FREE_IMAGE_TYPE fit = FreeImage_GetImageType(pBitmap); GLenum eType = (fit == FIT_RGBF || fit == FIT_FLOAT) ? GL_FLOAT : GL_UNSIGNED_BYTE; // create GL texture GLuint textureID; glGenTextures( 1, &textureID ); glBindTexture( GL_TEXTURE_2D, textureID ); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, FreeImage_GetWidth(pBitmap), FreeImage_GetHeight(pBitmap), 0, a_uiFormat, eType, pData); // specify default filtering and wrapping glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); // unbind texture glBindTexture( GL_TEXTURE_2D, 0 ); // delete data FreeImage_Unload(pBitmap); return textureID; }