/** Extract the luminance channel L from a RGBF image. Luminance is calculated from the sRGB model (RGB2XYZ matrix) using a D65 white point : L = ( 0.2126 * r ) + ( 0.7152 * g ) + ( 0.0722 * b ) Reference : A Standard Default Color Space for the Internet - sRGB. [online] http://www.w3.org/Graphics/Color/sRGB */ FIBITMAP* ConvertRGBFToY(FIBITMAP *src) { if(FreeImage_GetImageType(src) != FIT_RGBF) return FALSE; unsigned width = FreeImage_GetWidth(src); unsigned height = FreeImage_GetHeight(src); FIBITMAP *dst = FreeImage_AllocateT(FIT_FLOAT, width, height); if(!dst) return NULL; unsigned src_pitch = FreeImage_GetPitch(src); unsigned dst_pitch = FreeImage_GetPitch(dst); BYTE *src_bits = (BYTE*)FreeImage_GetBits(src); BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst); 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++) { float L = 0.2126F * src_pixel[x].red + 0.7152F * src_pixel[x].green + 0.0722F * src_pixel[x].blue; dst_pixel[x] = (L > 0) ? L : 0; } // next line src_bits += src_pitch; dst_bits += dst_pitch; } return dst; }
/** Red-black Gauss-Seidel relaxation for model problem. Updates the current value of the solution u[0..n-1][0..n-1], using the right-hand side function rhs[0..n-1][0..n-1]. */ static void fmg_relaxation(FIBITMAP *U, FIBITMAP *RHS, int n) { int row, col, ipass, isw, jsw; const float h = 1.0F / (n - 1); const float h2 = h*h; const int u_pitch = FreeImage_GetPitch(U) / sizeof(float); const int rhs_pitch = FreeImage_GetPitch(RHS) / sizeof(float); float *u_bits = (float*)FreeImage_GetBits(U); const float *rhs_bits = (float*)FreeImage_GetBits(RHS); for (ipass = 0, jsw = 1; ipass < 2; ipass++, jsw = 3-jsw) { // Red and black sweeps float *u_scan = u_bits + u_pitch; const float *rhs_scan = rhs_bits + rhs_pitch; for (row = 1, isw = jsw; row < n-1; row++, isw = 3-isw) { for (col = isw; col < n-1; col += 2) { // Gauss-Seidel formula // calculate U(row, col) = // 0.25 * [ U(row+1, col) + U(row-1, col) + U(row, col+1) + U(row, col-1) - h2 * RHS(row, col) ] float *u_center = u_scan + col; const float *rhs_center = rhs_scan + col; *u_center = *(u_center + u_pitch) + *(u_center - u_pitch) + *(u_center + 1) + *(u_center - 1); *u_center -= h2 * *rhs_center; *u_center *= 0.25F; } u_scan += u_pitch; rhs_scan += rhs_pitch; } } }
/////////////////////////////////////////////////////////////////////////// /// /// @fn bool glLoadTexture(const std::string& nomFichier, unsigned int& idTexture, /// bool genererTexture) /// /// Cette fonction crée une texture OpenGL à partir d'une image contenu /// dans un fichier. FreeImage est utilisée pour lire l'image, donc tous /// les formats reconnues par cette librairie devraient être supportés. /// /// @param[in] nomFichier : Le nom du fichier image à charger. /// @param[out] idTexture : L'identificateur de la texture créée. /// @param[in] genererTexture : Doit-on demander à OpenGL de générer un numéro /// de texture au préalable? /// /// @return Vrai si le chargement a réussi, faux autrement. /// /////////////////////////////////////////////////////////////////////////// bool glLoadTexture(const std::string& nomFichier, unsigned int& idTexture, bool genererTexture) { // Ce code de lecture générique d'un fichier provient de la // documentation de FreeImage FREE_IMAGE_FORMAT format = FIF_UNKNOWN; // check the file signature and deduce its format // (the second argument is currently not used by FreeImage) format = FreeImage_GetFileType(nomFichier.c_str(), 0); if(format == FIF_UNKNOWN) { // no signature ? // try to guess the file format from the file extension format = FreeImage_GetFIFFromFilename(nomFichier.c_str()); } // check that the plugin has reading capabilities ... if((format == FIF_UNKNOWN) || !FreeImage_FIFSupportsReading(format)) { utilitaire::afficherErreur( std::string("Format du fichier image \"") + std::string(nomFichier.c_str()) + std::string("\" non supporté") ); return false; } // ok, let's load the file FIBITMAP* dib = FreeImage_Load(format, nomFichier.c_str(), 0); if (dib == 0) { utilitaire::afficherErreur( std::string("Erreur à la lecture du fichier \"") + std::string(nomFichier.c_str()) + std::string("\"") ); return false; } FIBITMAP* dib32 = FreeImage_ConvertTo32Bits(dib); if (dib32 == 0) { utilitaire::afficherErreur( std::string("Incapable de convertir le fichier \"") + std::string(nomFichier.c_str()) + std::string("\" en 32 bpp.") ); FreeImage_Unload(dib); return false; } int pitch = FreeImage_GetPitch(dib32); glCreateTexture( FreeImage_GetBits(dib32), FreeImage_GetWidth(dib32), FreeImage_GetHeight(dib32), FreeImage_GetBPP(dib32), FreeImage_GetPitch(dib32), idTexture, genererTexture ); FreeImage_Unload(dib32); FreeImage_Unload(dib); return true; }
double ApplyCurve(FIBITMAP *src, FIBITMAP *dst, std::vector<cp> ctpts, int threadcount) { _mark(); unsigned spitch = FreeImage_GetPitch(src); unsigned dpitch = FreeImage_GetPitch(dst); unsigned w = FreeImage_GetWidth(src); unsigned h = FreeImage_GetHeight(src); BYTE * srcbits = FreeImage_GetBits(src); BYTE * dstbits = FreeImage_GetBits(dst); Curve c; BYTE LUT8[256]; WORD LUT16[65536]; c.setControlPoints(ctpts); int bpp = FreeImage_GetBPP(src); if (bpp == 24) { c.clampto(0.0,255.0); for (int x=0; x<256; x++) { LUT8[x] = (BYTE)floor(c.getpoint(x) + 0.5); } #pragma omp parallel for num_threads(threadcount) for(unsigned y = 0; y < h; y++) { for(unsigned x = 0; x < w; x++) { BYTE * bdstpix = (BYTE *) dstbits + dpitch*y + 3*x; BYTE *pixel = (BYTE *) (srcbits + spitch*y + 3*x); bdstpix[FI_RGBA_RED] = LUT8[pixel[FI_RGBA_RED]]; bdstpix[FI_RGBA_GREEN] = LUT8[pixel[FI_RGBA_GREEN]]; bdstpix[FI_RGBA_BLUE] = LUT8[pixel[FI_RGBA_BLUE]]; //bdstpix[FI_RGBA_RED] = ((BYTE *) LUT8)[pixel[FI_RGBA_RED]]; //bdstpix[FI_RGBA_GREEN] = ((BYTE *) LUT8)[pixel[FI_RGBA_GREEN]]; //bdstpix[FI_RGBA_BLUE] = ((BYTE *) LUT8)[pixel[FI_RGBA_BLUE]]; } } } if (bpp == 48) { c.scalepoints(256.0); c.clampto(0.0,65535.0); for (int x=0; x<65536; x++) { LUT16[x] = (WORD)floor(c.getpoint(x) + 0.5); } #pragma omp parallel for num_threads(threadcount) for(unsigned y = 0; y < h; y++) { for(unsigned x = 0; x < w; x++) { FIRGB16 * wdstpix = (FIRGB16 *) (dstbits + dpitch*y + 6*x); FIRGB16 * pixel = (FIRGB16 *) (srcbits + spitch*y + 6*x); wdstpix->red = LUT16[pixel->red]; wdstpix->green = LUT16[pixel->green]; wdstpix->blue = LUT16[pixel->blue]; //wdstpix->red = ((WORD *) LUT16)[pixel->red]; //wdstpix->green = ((WORD *) LUT16)[pixel->green]; //wdstpix->blue = ((WORD *) LUT16)[pixel->blue]; } } } return _duration(); }
double ApplyLUT(FIBITMAP *src, FIBITMAP *dst, char * LUT, int threadcount) { _mark(); unsigned spitch = FreeImage_GetPitch(src); unsigned dpitch = FreeImage_GetPitch(dst); unsigned w = FreeImage_GetWidth(src); unsigned h = FreeImage_GetHeight(src); BYTE * srcbits = FreeImage_GetBits(src); BYTE * dstbits = FreeImage_GetBits(dst); BYTE LUT8[256]; WORD LUT16[65536]; int bpp = FreeImage_GetBPP(src); if (bpp == 24) { for (int x=0; x<256; x++) { LUT8[x] = ((BYTE *) LUT)[x];; } #pragma omp parallel for num_threads(threadcount) for(unsigned y = 0; y < h; y++) { for(unsigned x = 0; x < w; x++) { BYTE * bdstpix = (BYTE *) (dstbits + dpitch*y + 3*x); BYTE * pixel = (BYTE *) (srcbits + spitch*y + 3*x); bdstpix[FI_RGBA_RED] = LUT8[pixel[FI_RGBA_RED]]; bdstpix[FI_RGBA_GREEN] = LUT8[pixel[FI_RGBA_GREEN]]; bdstpix[FI_RGBA_BLUE] = LUT8[pixel[FI_RGBA_BLUE]]; //bdstpix[FI_RGBA_RED] = ((BYTE *) LUT8)[pixel[FI_RGBA_RED]]; //bdstpix[FI_RGBA_GREEN] = ((BYTE *) LUT8)[pixel[FI_RGBA_GREEN]]; //bdstpix[FI_RGBA_BLUE] = ((BYTE *) LUT8)[pixel[FI_RGBA_BLUE]]; } } } if (bpp == 48) { for (int x=0; x<65536; x++) { LUT16[x] = ((WORD *)LUT)[x]; } #pragma omp parallel for num_threads(threadcount) for(unsigned y = 0; y < h-1; y++) { for(unsigned x = 0; x < w-1; x++) { FIRGB16 * wdstpix = (FIRGB16 *) (dstbits + dpitch*y + 6*x); FIRGB16 * pixel = (FIRGB16 *) (srcbits + spitch*y + 6*x); wdstpix->red = LUT16[pixel->red]; wdstpix->green = LUT16[pixel->green]; wdstpix->blue = LUT16[pixel->blue]; //wdstpix->red = ((WORD *) LUT16)[pixel->red]; //wdstpix->green = ((WORD *) LUT16)[pixel->green]; //wdstpix->blue = ((WORD *) LUT16)[pixel->blue]; } } } return _duration(); }
double ApplyLUT2LUMA(FIBITMAP *src, FIBITMAP *dst, char * LUT, int threadcount) { _mark(); unsigned spitch = FreeImage_GetPitch(src); unsigned dpitch = FreeImage_GetPitch(dst); unsigned w = FreeImage_GetWidth(src); unsigned h = FreeImage_GetHeight(src); BYTE * srcbits = FreeImage_GetBits(src); BYTE * dstbits = FreeImage_GetBits(dst); BYTE LUT8[256]; WORD LUT16[65536]; int bpp = FreeImage_GetBPP(src); if (bpp == 24) { for (int x=0; x<256; x++) { LUT8[x] = ((BYTE *) LUT)[x]; } #pragma omp parallel for num_threads(threadcount) for(unsigned y = 0; y < h; y++) { for(unsigned x = 0; x < w; x++) { BYTE * bdstpix = (BYTE *) (dstbits + dpitch*y + 3*x); BYTE * pixel = (BYTE *) (srcbits + spitch*y + 3*x); int lumaorig = (int) LUMA(pixel[FI_RGBA_RED],pixel[FI_RGBA_GREEN],pixel[FI_RGBA_BLUE]); int diff = lumaorig - LUT8[lumaorig]; bdstpix[FI_RGBA_RED] = std::min(std::max(bdstpix[FI_RGBA_RED] + diff,0),255); bdstpix[FI_RGBA_GREEN] = std::min(std::max(bdstpix[FI_RGBA_GREEN] + diff,0),255); bdstpix[FI_RGBA_BLUE] = std::min(std::max(bdstpix[FI_RGBA_BLUE] + diff,0),255); } } } if (bpp == 48) { for (int x=0; x<65536; x++) { LUT16[x] = ((WORD *)LUT)[x]; } #pragma omp parallel for num_threads(threadcount) for(unsigned y = 0; y < h-1; y++) { for(unsigned x = 0; x < w-1; x++) { FIRGB16 * wdstpix = (FIRGB16 *) (dstbits + dpitch*y + 6*x); FIRGB16 * pixel = (FIRGB16 *) (srcbits + spitch*y + 6*x); int lumaorig = (int) LUMA(pixel->red,pixel->green,pixel->blue); int diff = lumaorig - LUT16[lumaorig]; wdstpix->red = std::min(std::max(pixel->red + diff,0),65535); wdstpix->green = std::min(std::max(pixel->green + diff,0),65535); wdstpix->blue = std::min(std::max(pixel->blue + diff,0),65535); } } } return _duration(); }
double ApplyGray(FIBITMAP *src, FIBITMAP *dst, double redpct, double greenpct, double bluepct, int threadcount) { _mark(); int bpp = FreeImage_GetBPP(src); unsigned spitch = FreeImage_GetPitch(src); unsigned dpitch = FreeImage_GetPitch(dst); BYTE * srcbits = FreeImage_GetBits(src); BYTE * dstbits = FreeImage_GetBits(dst); switch(bpp) { case 48: #pragma omp parallel for num_threads(threadcount) for(unsigned y = 0; y < FreeImage_GetHeight(src); y++) { for(unsigned x = 0; x < FreeImage_GetWidth(src); x++) { FIRGB16 * wdstpix = (FIRGB16 *) (dstbits + dpitch*y + 6*x); FIRGB16 * pixel = (FIRGB16 *) (srcbits + spitch*y + 6*x); double G = floor((double) pixel->red*redpct + (double) pixel->green*greenpct + (double) pixel->blue*bluepct)+0.5; if (G>65535.0) G=65535.0; if (G<0.0) G=0.0; wdstpix->red = int(G); wdstpix->green = int(G); wdstpix->blue = int(G); } } break; case 24 : #pragma omp parallel for num_threads(threadcount) for(unsigned y = 0; y < FreeImage_GetHeight(src); y++) { for(unsigned x = 0; x < FreeImage_GetWidth(src); x++) { BYTE * bdstpix = (BYTE *) dstbits + dpitch*y + 3*x; BYTE *pixel = (BYTE *) (srcbits + spitch*y + 3*x); double G = floor((double) pixel[FI_RGBA_RED]*redpct + (double) pixel[FI_RGBA_GREEN]*greenpct + (double) pixel[FI_RGBA_BLUE]*bluepct)+0.5; if (G>255.0) G=255.0; if (G<0.0) G=0.0; bdstpix[FI_RGBA_RED] = int(G); bdstpix[FI_RGBA_GREEN] = int(G); bdstpix[FI_RGBA_BLUE]= int(G); } } break; } return _duration(); }
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; }
/** Returns minus the residual for the model problem. Input quantities are u[0..n-1][0..n-1] and rhs[0..n-1][0..n-1], while res[0..n-1][0..n-1] is returned. */ static void fmg_residual(FIBITMAP *RES, FIBITMAP *U, FIBITMAP *RHS, int n) { int row, col; const float h = 1.0F / (n-1); const float h2i = 1.0F / (h*h); const int res_pitch = FreeImage_GetPitch(RES) / sizeof(float); const int u_pitch = FreeImage_GetPitch(U) / sizeof(float); const int rhs_pitch = FreeImage_GetPitch(RHS) / sizeof(float); float *res_bits = (float*)FreeImage_GetBits(RES); const float *u_bits = (float*)FreeImage_GetBits(U); const float *rhs_bits = (float*)FreeImage_GetBits(RHS); // interior points { float *res_scan = res_bits + res_pitch; const float *u_scan = u_bits + u_pitch; const float *rhs_scan = rhs_bits + rhs_pitch; for (row = 1; row < n-1; row++) { for (col = 1; col < n-1; col++) { // calculate RES(row, col) = // -h2i * [ U(row+1, col) + U(row-1, col) + U(row, col+1) + U(row, col-1) - 4 * U(row, col) ] + RHS(row, col); float *res_center = res_scan + col; const float *u_center = u_scan + col; const float *rhs_center = rhs_scan + col; *res_center = *(u_center + u_pitch) + *(u_center - u_pitch) + *(u_center + 1) + *(u_center - 1) - 4 * *u_center; *res_center *= -h2i; *res_center += *rhs_center; } res_scan += res_pitch; u_scan += u_pitch; rhs_scan += rhs_pitch; } } // boundary points { memset(FreeImage_GetScanLine(RES, 0), 0, FreeImage_GetPitch(RES)); memset(FreeImage_GetScanLine(RES, n-1), 0, FreeImage_GetPitch(RES)); float *left = res_bits; float *right = res_bits + (n-1); for(int k = 0; k < n; k++) { *left = 0; *right = 0; left += res_pitch; right += res_pitch; } } }
void ImageLoader:: compatible() { // BITMAP数据是从下往上的, 需要翻转 FreeImage_FlipVertical(mDIB); // FreeImage是BGR顺序, 与NVTT要求的一致, 而PVRT需要RGB顺序, 两者都需要32bits数据 if (config.imageCompressionType != CT_DXTC) { // 将BGR改为RGB, 交换R channel和B channel const unsigned bytesperpixel = FreeImage_GetBPP(mDIB) / 8; const unsigned height = FreeImage_GetHeight(mDIB); const unsigned pitch = FreeImage_GetPitch(mDIB); const unsigned lineSize = FreeImage_GetLine(mDIB); BYTE* line = FreeImage_GetBits(mDIB); for (unsigned y = 0; y < height; ++y, line += pitch) { for (BYTE* pixel = line; pixel < line + lineSize; pixel += bytesperpixel) { INPLACESWAP(pixel[0], pixel[2]); } } } if (FreeImage_GetBPP(mDIB) != 32) { FIBITMAP* convertDIB = FreeImage_ConvertTo32Bits(mDIB); FreeImage_Unload(mDIB); mDIB = convertDIB; } }
FIBITMAP * CreateTemplete(FIBITMAP * hImage, unsigned ScreenWidth, unsigned ScreenHeight) // 创建空白PNG模版 { FIBITMAP * hPicTemplete; RGBQUAD * palMain ; RGBQUAD * palTemplete ; unsigned ImgPitchLocal ; BYTE * pBitLocal; unsigned x, y, n; hPicTemplete = FreeImage_Allocate(ScreenWidth, ScreenHeight, 8, 0, 0, 0); //创建目标图像 palMain = FreeImage_GetPalette(hImage); palTemplete = FreeImage_GetPalette(hPicTemplete); for (n = 0 ; n < 256 ; n++) { palTemplete[n].rgbRed = palMain[n].rgbRed ; palTemplete[n].rgbGreen = palMain[n].rgbGreen ; palTemplete[n].rgbBlue = palMain[n].rgbBlue ; } palTemplete[70].rgbRed = 255 ; palTemplete[70].rgbGreen = 255 ; palTemplete[70].rgbBlue = 255 ; // FreeImage_SetTransparent(hPicTemplete, false); // 所有像素颜色填充为 70 号索引 ImgPitchLocal = FreeImage_GetPitch(hPicTemplete) ; pBitLocal = FreeImage_GetBits(hPicTemplete); for (y = 0 ; y < ScreenHeight; y++) { for (x = 0; x < ScreenWidth ; x++) pBitLocal[x] = 70 ; pBitLocal += ImgPitchLocal ; // 下一行 } return hPicTemplete; }
Image *Image::New(FIBITMAP* dib) { NanScope(); Local<Value> arg = NanNew<Integer>(0); Local<Object> obj = NanNew<FunctionTemplate>(constructor_template)->GetFunction()->NewInstance(1, &arg); Image *image = ObjectWrap::Unwrap<Image>(obj); int w,h,pitch; FREE_IMAGE_TYPE type = FreeImage_GetImageType(dib); obj->SetInternalField(0, NanNew<External>(dib)); obj->Set(NanNew<String>("width"), NanNew<Integer>(w=FreeImage_GetWidth(dib))); obj->Set(NanNew<String>("height"), NanNew<Integer>(h=FreeImage_GetHeight(dib))); obj->Set(NanNew<String>("bpp"), NanNew<Integer>((int)FreeImage_GetBPP(dib))); obj->Set(NanNew<String>("pitch"), NanNew<Integer>(pitch=FreeImage_GetPitch(dib))); obj->Set(NanNew<String>("type"), NanNew<Integer>(type)); obj->Set(NanNew<String>("redMask"), NanNew<Integer>((int)FreeImage_GetRedMask(dib))); obj->Set(NanNew<String>("greenMask"), NanNew<Integer>((int)FreeImage_GetGreenMask(dib))); obj->Set(NanNew<String>("blueMask"), NanNew<Integer>((int)FreeImage_GetBlueMask(dib))); BYTE *bits = FreeImage_GetBits(dib); obj->Set(NanNew<String>("buffer"), NanNewBufferHandle((char*) bits, h * pitch)); return image; }
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); }
FreeImage::FreeImage( const FreeImage & freeImage, const Math::Vec2<Size> & newSize, Filter resampleFilter ) : BasicLoadable( freeImage ), fileName( freeImage.fileName ), #ifdef WIN32 fileNameW( freeImage.fileNameW ), #endif size( newSize ), invertY( freeImage.invertY ), loadingType( freeImage.loadingType ), BPP( freeImage.BPP ), loadingFormat( freeImage.loadingFormat ), resampleFilter( resampleFilter ) { if ( freeImage.isLoaded() ) { Math::Vec2<Size> toCopySize = freeImage.getSize(); if ( this -> size != toCopySize ) this -> freeImage = FreeImage_Rescale( freeImage.freeImage, this -> size.x, this -> size.y, ( FREE_IMAGE_FILTER ) this -> resampleFilter ); else this -> freeImage = FreeImage_Clone( freeImage.freeImage ); } else { this -> freeImage = freeImage.freeImage; //Probably NULL } if ( this -> freeImage ) this -> stride = FreeImage_GetPitch( this -> freeImage ); else this -> stride = 0; }
/** Invert only color components, skipping Alpha/Black (Can be useful as public/utility function) */ static BOOL invertColor(FIBITMAP* dib) { FREE_IMAGE_TYPE type = FreeImage_GetImageType(dib); const unsigned Bpp = FreeImage_GetBPP(dib)/8; if((type == FIT_BITMAP && Bpp == 4) || type == FIT_RGBA16) { const unsigned width = FreeImage_GetWidth(dib); const unsigned height = FreeImage_GetHeight(dib); BYTE *line_start = FreeImage_GetScanLine(dib, 0); const unsigned pitch = FreeImage_GetPitch(dib); const unsigned triBpp = Bpp - (Bpp == 4 ? 1 : 2); for(unsigned y = 0; y < height; y++) { BYTE *line = line_start; for(unsigned x = 0; x < width; x++) { for(unsigned b=0; b < triBpp; ++b) { line[b] = ~line[b]; } line += Bpp; } line_start += pitch; } return TRUE; } else { return FreeImage_Invert(dib); } }
/** Get the maximum, minimum and average luminance @param dib Source Y image to analyze @param maxLum Maximum luminance @param minLum Minimum luminance @param worldLum Average luminance (world adaptation luminance) @return Returns TRUE if successful, returns FALSE otherwise @see ConvertRGBFToY */ BOOL LuminanceFromY(FIBITMAP *dib, float *maxLum, float *minLum, float *worldLum) { if(FreeImage_GetImageType(dib) != FIT_FLOAT) return FALSE; unsigned width = FreeImage_GetWidth(dib); unsigned height = FreeImage_GetHeight(dib); unsigned pitch = FreeImage_GetPitch(dib); float max_lum = -1e20F, min_lum = 1e20F; double sum = 0; BYTE *bits = (BYTE*)FreeImage_GetBits(dib); for(unsigned y = 0; y < height; y++) { const float *pixel = (float*)bits; for(unsigned x = 0; x < width; x++) { const float Y = pixel[x]; max_lum = (max_lum < Y) ? Y : max_lum; // max Luminance in the scene min_lum = ((Y > 0) && (min_lum < Y)) ? min_lum : Y; // min Luminance in the scene sum += log(2.3e-5 + Y); // contrast constant in Tumblin paper } // next line bits += pitch; } // maximum luminance *maxLum = max_lum; // minimum luminance *minLum = min_lum; // average log luminance double avgLogLum = (sum / (width * height)); // world adaptation luminance *worldLum = (float)exp(avgLogLum); return TRUE; }
FIBITMAP* getBmpFromPixels(ofPixels_<PixelType> &pix){ PixelType* pixels = pix.getPixels(); unsigned int width = pix.getWidth(); unsigned int height = pix.getHeight(); unsigned int bpp = pix.getBitsPerPixel(); FREE_IMAGE_TYPE freeImageType = getFreeImageType(pix); FIBITMAP* bmp = FreeImage_AllocateT(freeImageType, width, height, bpp); unsigned char* bmpBits = FreeImage_GetBits(bmp); if(bmpBits != NULL) { int srcStride = width * pix.getBytesPerPixel(); int dstStride = FreeImage_GetPitch(bmp); unsigned char* src = (unsigned char*) pixels; unsigned char* dst = bmpBits; for(int i = 0; i < (int)height; i++) { memcpy(dst, src, dstStride); src += srcStride; dst += dstStride; } } else { ofLogError() << "ofImage::getBmpFromPixels() unable to get FIBITMAP from ofPixels"; } // ofPixels are top left, FIBITMAP is bottom left FreeImage_FlipVertical(bmp); return bmp; }
Image *Image::New(FIBITMAP* dib) { HandleScope scope; Local<Value> arg = Integer::NewFromUnsigned(0); Local<Object> obj = constructor_template->GetFunction()->NewInstance(1, &arg); Image *image = ObjectWrap::Unwrap<Image>(obj); image->dib = dib; int w,h,pitch; FREE_IMAGE_TYPE type = FreeImage_GetImageType(dib); obj->SetInternalField(0, External::New(dib)); obj->Set(JS_STR("width"), JS_INT(w=FreeImage_GetWidth(dib))); obj->Set(JS_STR("height"), JS_INT(h=FreeImage_GetHeight(dib))); obj->Set(JS_STR("bpp"), JS_INT((int)FreeImage_GetBPP(dib))); obj->Set(JS_STR("pitch"), JS_INT(pitch=FreeImage_GetPitch(dib))); obj->Set(JS_STR("type"), JS_INT(type)); obj->Set(JS_STR("redMask"), JS_INT((int)FreeImage_GetRedMask(dib))); obj->Set(JS_STR("greenMask"), JS_INT((int)FreeImage_GetGreenMask(dib))); obj->Set(JS_STR("blueMask"), JS_INT((int)FreeImage_GetBlueMask(dib))); BYTE *bits=FreeImage_GetBits(dib); node::Buffer *buf = node::Buffer::New((char*)bits,h*pitch); obj->Set(JS_STR("buffer"), buf->handle_); return image; }
/** Get the maximum, minimum and average luminance.<br> On input, pixel->red == Y, pixel->green == x, pixel->blue == y @param Yxy Source Yxy image to analyze @param maxLum Maximum luminance @param minLum Minimum luminance @param worldLum Average luminance (world adaptation luminance) @return Returns TRUE if successful, returns FALSE otherwise */ BOOL LuminanceFromYxy(FIBITMAP *Yxy, float *maxLum, float *minLum, float *worldLum) { if(FreeImage_GetImageType(Yxy) != FIT_RGBF) return FALSE; const unsigned width = FreeImage_GetWidth(Yxy); const unsigned height = FreeImage_GetHeight(Yxy); const unsigned pitch = FreeImage_GetPitch(Yxy); float max_lum = 0, min_lum = 0; double sum = 0; BYTE *bits = (BYTE*)FreeImage_GetBits(Yxy); for(unsigned y = 0; y < height; y++) { const FIRGBF *pixel = (FIRGBF*)bits; for(unsigned x = 0; x < width; x++) { const float Y = MAX(0.0F, pixel[x].red);// avoid negative values max_lum = (max_lum < Y) ? Y : max_lum; // max Luminance in the scene min_lum = (min_lum < Y) ? min_lum : Y; // min Luminance in the scene sum += log(2.3e-5F + Y); // contrast constant in Tumblin paper } // next line bits += pitch; } // maximum luminance *maxLum = max_lum; // minimum luminance *minLum = min_lum; // average log luminance double avgLogLum = (sum / (width * height)); // world adaptation luminance *worldLum = (float)exp(avgLogLum); return TRUE; }
/** Custom gamma correction based on the ITU-R BT.709 standard @param dib RGBF image to be corrected @param gammaval Gamma value (2.2 is a good default value) @return Returns TRUE if successful, returns FALSE otherwise */ static BOOL REC709GammaCorrection(FIBITMAP *dib, const float gammaval) { if(FreeImage_GetImageType(dib) != FIT_RGBF) return FALSE; float slope = 4.5F; float start = 0.018F; const float fgamma = (float)((0.45 / gammaval) * 2); if(gammaval >= 2.1F) { start = (float)(0.018 / ((gammaval - 2) * 7.5)); slope = (float)(4.5 * ((gammaval - 2) * 7.5)); } else if (gammaval <= 1.9F) { start = (float)(0.018 * ((2 - gammaval) * 7.5)); slope = (float)(4.5 / ((2 - gammaval) * 7.5)); } const unsigned width = FreeImage_GetWidth(dib); const unsigned height = FreeImage_GetHeight(dib); const unsigned pitch = FreeImage_GetPitch(dib); BYTE *bits = (BYTE*)FreeImage_GetBits(dib); for(unsigned y = 0; y < height; y++) { float *pixel = (float*)bits; for(unsigned x = 0; x < width; x++) { for(int i = 0; i < 3; i++) { *pixel = (*pixel <= start) ? *pixel * slope : (1.099F * pow(*pixel, fgamma) - 0.099F); pixel++; } } bits += pitch; } return TRUE; }
FreeImage & FreeImage::operator=( const FreeImage & image ) { this -> fileName = image.fileName; #ifdef WIN32 this -> fileNameW = image.fileNameW; #endif this -> size = size; this -> invertY = image.invertY; this -> loadingType = image.loadingType; this -> BPP = image.BPP; this -> loadingFormat = image.loadingFormat; this -> resampleFilter = image.resampleFilter; if ( image.isLoaded() ) { lock(); this -> freeImage = FreeImage_Clone( image.freeImage ); setLoaded( true ); unlock(); } else { this -> freeImage = image.freeImage; //Probably NULL setLoaded( false ); } if ( this -> freeImage ) this -> stride = FreeImage_GetPitch( this -> freeImage ); else this -> stride = 0; return *this; }
void FreeImage::loadFromDatas( unsigned char * datas, const Math::Vec2<Size> & size, Format format, bool datasInvertY ) { unload(); lock(); setLoading( true ); _updateFormat( format ); this -> size = size; this -> invertY = datasInvertY; this -> loadingType = LoadingType::EMPTY; this -> fileName.clear(); //we have no reason to keep a filepath now. #ifdef WIN32 this -> fileNameW.clear(); //we have no reason to keep a filepath now. #endif // WIN32 #ifdef WIN32 if ( format == Format::RGB || format == Format::RGBA ) { //because FreeImage do not care of MASK and use BGR on Windows size_t numPixels = this -> size.x * this -> size.y; size_t offsetPerPixel = ( this -> BPP / 8 ); unsigned char * newDatas = new unsigned char[offsetPerPixel * numPixels]; auto otherIt = datas; auto thisIt = newDatas; if ( format == Format::RGB ) { for ( size_t i = 0; i < numPixels; i++ ) { thisIt[0] = otherIt[2]; thisIt[1] = otherIt[1]; thisIt[2] = otherIt[0]; otherIt += offsetPerPixel; thisIt += offsetPerPixel; } } else if ( format == Format::RGBA ) { for ( size_t i = 0; i < numPixels; i++ ) { thisIt[0] = otherIt[2]; thisIt[1] = otherIt[1]; thisIt[2] = otherIt[0]; thisIt[3] = otherIt[3]; otherIt += offsetPerPixel; thisIt += offsetPerPixel; } } this -> freeImage = FreeImage_ConvertFromRawBits( newDatas, this -> size.x, this -> size.y, this -> size.x * ( this -> BPP / 8 ), this -> BPP, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, this -> invertY ); delete[] newDatas; } else { this -> freeImage = FreeImage_ConvertFromRawBits( datas, this -> size.x, this -> size.y, this -> size.x * ( this -> BPP / 8 ), this -> BPP, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, this -> invertY ); } #else this -> freeImage = FreeImage_ConvertFromRawBits( datas, this -> size.x, this -> size.y, this -> size.x * ( this -> BPP / 8 ), this -> BPP, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, this -> invertY ); #endif this -> stride = FreeImage_GetPitch( this -> freeImage ); setLoading( false ); setLoaded( true ); unlock(); }
/** Coarse-to-fine prolongation by bilinear interpolation. nf is the fine-grid dimension. The coarsegrid solution is input as uc[0..nc-1][0..nc-1], where nc = nf/2 + 1. The fine-grid solution is returned in uf[0..nf-1][0..nf-1]. */ static void fmg_prolongate(FIBITMAP *UF, FIBITMAP *UC, int nf) { int row_uc, row_uf, col_uc, col_uf; const int uf_pitch = FreeImage_GetPitch(UF) / sizeof(float); const int uc_pitch = FreeImage_GetPitch(UC) / sizeof(float); float *uf_bits = (float*)FreeImage_GetBits(UF); const float *uc_bits = (float*)FreeImage_GetBits(UC); // do elements that are copies { const int nc = nf/2 + 1; float *uf_scan = uf_bits; const float *uc_scan = uc_bits; for (row_uc = 0; row_uc < nc; row_uc++) { for (col_uc = 0, col_uf = 0; col_uc < nc; col_uc++, col_uf += 2) { // calculate UF(2*row_uc, col_uf) = UC(row_uc, col_uc); uf_scan[col_uf] = uc_scan[col_uc]; } uc_scan += uc_pitch; uf_scan += 2 * uf_pitch; } } // do odd-numbered columns, interpolating vertically { for(row_uf = 1; row_uf < nf-1; row_uf += 2) { float *uf_scan = uf_bits + row_uf * uf_pitch; for (col_uf = 0; col_uf < nf; col_uf += 2) { // calculate UF(row_uf, col_uf) = 0.5 * ( UF(row_uf+1, col_uf) + UF(row_uf-1, col_uf) ) uf_scan[col_uf] = 0.5F * ( *(uf_scan + uf_pitch + col_uf) + *(uf_scan - uf_pitch + col_uf) ); } } } // do even-numbered columns, interpolating horizontally { float *uf_scan = uf_bits; for(row_uf = 0; row_uf < nf; row_uf++) { for (col_uf = 1; col_uf < nf-1; col_uf += 2) { // calculate UF(row_uf, col_uf) = 0.5 * ( UF(row_uf, col_uf+1) + UF(row_uf, col_uf-1) ) uf_scan[col_uf] = 0.5F * ( uf_scan[col_uf + 1] + uf_scan[col_uf - 1] ); } uf_scan += uf_pitch; } } }
/** Does coarse-to-fine interpolation and adds result to uf. nf is the fine-grid dimension. The coarse-grid solution is input as uc[0..nc-1][0..nc-1], where nc = nf/2+1. The fine-grid solution is returned in uf[0..nf-1][0..nf-1]. res[0..nf-1][0..nf-1] is used for temporary storage. */ static void fmg_addint(FIBITMAP *UF, FIBITMAP *UC, FIBITMAP *RES, int nf) { fmg_prolongate(RES, UC, nf); const int uf_pitch = FreeImage_GetPitch(UF) / sizeof(float); const int res_pitch = FreeImage_GetPitch(RES) / sizeof(float); float *uf_bits = (float*)FreeImage_GetBits(UF); const float *res_bits = (float*)FreeImage_GetBits(RES); for(int row = 0; row < nf; row++) { for(int col = 0; col < nf; col++) { // calculate UF(row, col) = UF(row, col) + RES(row, col); uf_bits[col] += res_bits[col]; } uf_bits += uf_pitch; res_bits += res_pitch; } }
bool tpImageIO::readHDR(tpImageColorHDR& I, const char* path) { FREE_IMAGE_FORMAT fifmt = FreeImage_GetFileType(path, 0); if(fifmt == FIF_UNKNOWN) { std::cerr << "[Error] tpImageIO : Unknow type !" << std::endl; //TODO: Exceptions ? return false; } FIBITMAP *dib = FreeImage_Load(fifmt, path,0); if( dib == NULL ) { std::cerr << "[Error] tpImageIO : Impossible d'ouvrir l'image : " << path << std::endl; // TODO: Exceptions ? return false; } if(FreeImage_GetImageType(dib)!=FIT_RGBF) { std::cerr << "[Error] tpImageIO : Unknow type !" << std::endl; //TODO: Exceptions ? return false; } unsigned width = FreeImage_GetWidth(dib); unsigned height = FreeImage_GetHeight(dib); unsigned pitch = FreeImage_GetPitch(dib); I.resize(height,width); FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); // test pixel access avoiding scanline calculations // to speed-up the image processing if(image_type == FIT_RGBF) { BYTE *bits = (BYTE*)FreeImage_GetBits(dib); for(int y = 0; y < height; y++) { FIRGBF *pixel = (FIRGBF*)bits; for(int x = 0; x < width; x++) { I[y][x].r = pixel[x].red; I[y][x].g = pixel[x].green; I[y][x].b = pixel[x].blue; } // next line bits += pitch; } } FreeImage_Unload(dib); return true; }
HANDLE fipWinImage::copyToHandle() const { HANDLE hMem = NULL; if(_dib) { // Get equivalent DIB size long dib_size = sizeof(BITMAPINFOHEADER); dib_size += FreeImage_GetColorsUsed(_dib) * sizeof(RGBQUAD); dib_size += FreeImage_GetPitch(_dib) * FreeImage_GetHeight(_dib); // Allocate a DIB hMem = GlobalAlloc(GHND, dib_size); BYTE *dib = (BYTE*)GlobalLock(hMem); memset(dib, 0, dib_size); BYTE *p_dib = (BYTE*)dib; // Copy the BITMAPINFOHEADER BITMAPINFOHEADER *bih = FreeImage_GetInfoHeader(_dib); memcpy(p_dib, bih, sizeof(BITMAPINFOHEADER)); if(FreeImage_GetImageType(_dib) != FIT_BITMAP) { // this hack is used to store the bitmap type in the biCompression member of the BITMAPINFOHEADER SET_FREEIMAGE_MARKER((BITMAPINFOHEADER*)p_dib, _dib); } p_dib += sizeof(BITMAPINFOHEADER); // Copy the palette RGBQUAD *pal = FreeImage_GetPalette(_dib); memcpy(p_dib, pal, FreeImage_GetColorsUsed(_dib) * sizeof(RGBQUAD)); p_dib += FreeImage_GetColorsUsed(_dib) * sizeof(RGBQUAD); // Copy the bitmap BYTE *bits = FreeImage_GetBits(_dib); memcpy(p_dib, bits, FreeImage_GetPitch(_dib) * FreeImage_GetHeight(_dib)); GlobalUnlock(hMem); } return hMem; }
bool Image::load(const char* filename) { const uint32_t argb_r = 0xFF000000u; const uint32_t argb_g = 0x00FF0000u; const uint32_t argb_b = 0x0000FF00u; const uint32_t argb_a = 0x000000FFu; FREE_IMAGE_FORMAT format; FIBITMAP* bitmap; FIBITMAP* rgbamap; int32_t w, h; // Unload if image already loaded to protect from memory leak unload(); // Get filetype format = FreeImage_GetFileType(filename); if (format == FIF_UNKNOWN) { fprintf(stderr, "Failed to ascertain filetype of %s\n", filename); return false; } // Load image bitmap = FreeImage_Load(format, filename); if (bitmap == nullptr) { fprintf(stderr, "Failed to load %s\n", filename); return false; } // Get width and height w = FreeImage_GetWidth(bitmap); h = FreeImage_GetHeight(bitmap); // Convert to RGBA if not already rgbamap = FreeImage_ConvertTo32Bits(bitmap); int32_t scan_width = FreeImage_GetPitch(rgbamap); // Make copy int32_t size = h * scan_width; _pixels = malloc(size); FreeImage_ConvertToRawBits((BYTE*)_pixels, bitmap, scan_width, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, true); _width = w; _height = h; // Unload FreeImage bitmaps FreeImage_Unload(bitmap); FreeImage_Unload(rgbamap); return true; }
// Takes an image from the frame buffer and compresses it int writeFrame(FIMEMORY *fiBuffer, FIBITMAP *fiImage, unsigned char imageType) { /* char msg[1024]; sprintf_s(msg, 1024, "imageType: %i", imageType); MessageBox(NULL,msg,"ADES DEBUG", MB_OK); */ imageType = 2; int errStatus = 1; u_short imageWidth, imageHeight; unsigned width, height, pitch, line; BYTE *bits; // Package image using correct compression switch(imageType) { case 0: // Send a raw frame // Get image characteristics width = FreeImage_GetWidth(fiImage); height = FreeImage_GetHeight(fiImage); pitch = FreeImage_GetPitch(fiImage); line = FreeImage_GetLine(fiImage); // Write out width and height errStatus = FreeImage_SeekMemory(fiBuffer, 0, SEEK_SET); if (errStatus != 1) break; imageWidth = htons(width); errStatus = FreeImage_WriteMemory( &imageWidth, 2, 1, fiBuffer ); if (errStatus != 1) break; imageHeight = htons(height); errStatus = FreeImage_WriteMemory( &imageHeight, 2, 1, fiBuffer ); if (errStatus != 1) break; // Write out image (convert the bitmap to raw bits, top-left pixel first) bits = (BYTE*)malloc(height * pitch); FreeImage_ConvertToRawBits(bits, fiImage, pitch, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, TRUE); errStatus = FreeImage_WriteMemory( bits, height*pitch*sizeof(BYTE), 1, fiBuffer ); free(bits); if (errStatus != 1) break; break; default: // Send a jpg frame errStatus = FreeImage_SeekMemory(fiBuffer, 0, SEEK_SET); if (errStatus != 1) break; errStatus = FreeImage_SaveToMemory(FIF_JPEG, fiImage, fiBuffer, convertToJpegFlag(imageType)); if (errStatus != 1) break; break; } // Clean up and exit return errStatus; }
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 }
// Gets a new FreeImage bitmap if we haven't got one yet or the current one is too small. // On entry the background thread must not be scanning the bitmap - eg waiting. // The parameter 'clear' is the value to clear the bitmap to - effectively clears to // a grey of colour RGB(clear, clear, clear), or -1 to not clear. void CHexEditDoc::GetAerialBitmap(int clear /*= 0xC0*/) { // If we already have a bitmap make sure it is big enough if (dib_ != NULL) { int dib_size = FreeImage_GetPitch(dib_) * FreeImage_GetHeight(dib_); int dib_rows = int(length_/bpe_/MAX_WIDTH) + 2; if (dib_size >= MAX_WIDTH*dib_rows*3) { if (clear > -1) memset(FreeImage_GetBits(dib_), clear, dib_size); return; } // Not big enough so free it and reallocate (below) FIBITMAP *dib = dib_; dib_ = NULL; TRACE("+++ FreeImage_Unload(%d)\n", dib); FreeImage_Unload(dib); if (clear <= -1) clear = 0xC0; // if we get a new bitmap we must clear it } // TBD: TODO we need user options for default bpe and MAX_BMP (min 16Mb = 1 TByte file @ BPE 65536) bpe_ = 1; // Keep increasing bpe_ by powers of two until we get a small enough bitmap while (bpe_ <= 65536 && (length_*3)/bpe_ > theApp.aerial_max_) bpe_ = bpe_<<1; // Work out the number of bitmap rows we would need at the widest bitmap size int rows = int(length_/bpe_/MAX_WIDTH) + 2; // Round up to next row plus add one more row to allow for "reshaping" ASSERT((rows-2)*MAX_WIDTH < theApp.aerial_max_); dib_ = FreeImage_Allocate(MAX_WIDTH, rows, 24); dib_size_ = MAX_WIDTH*rows*3; // DIB size in bytes since we have 3 bytes per pixel and no pad bytes at the end of each scan line ASSERT(dib_size_ == FreeImage_GetPitch(dib_) * FreeImage_GetHeight(dib_)); TRACE("+++ FreeImage_Allocate %d at %p end %p\n", dib_, FreeImage_GetBits(dib_), FreeImage_GetBits(dib_)+dib_size_); if (clear > -1) memset(FreeImage_GetBits(dib_), clear, dib_size_); // Clear to a grey }