/** Performs a 5 by 5 gaussian filtering using two 1D convolutions, followed by a subsampling by 2. @param dib Input image @return Returns a blurred image of size SIZE(dib)/2 @see GaussianPyramid */ static FIBITMAP* GaussianLevel5x5(FIBITMAP *dib) { FIBITMAP *h_dib = NULL, *v_dib = NULL, *dst = NULL; float *src_pixel, *dst_pixel; try { const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); if(image_type != FIT_FLOAT) throw(1); const unsigned width = FreeImage_GetWidth(dib); const unsigned height = FreeImage_GetHeight(dib); h_dib = FreeImage_AllocateT(image_type, width, height); v_dib = FreeImage_AllocateT(image_type, width, height); if(!h_dib || !v_dib) throw(1); const unsigned pitch = FreeImage_GetPitch(dib) / sizeof(float); // horizontal convolution dib -> h_dib src_pixel = (float*)FreeImage_GetBits(dib); dst_pixel = (float*)FreeImage_GetBits(h_dib); for(unsigned y = 0; y < height; y++) { // work on line y for(unsigned x = 2; x < width - 2; x++) { dst_pixel[x] = src_pixel[x-2] + src_pixel[x+2] + 4 * (src_pixel[x-1] + src_pixel[x+1]) + 6 * src_pixel[x]; dst_pixel[x] /= 16; } // boundary mirroring dst_pixel[0] = (2 * src_pixel[2] + 8 * src_pixel[1] + 6 * src_pixel[0]) / 16; dst_pixel[1] = (src_pixel[3] + 4 * (src_pixel[0] + src_pixel[2]) + 7 * src_pixel[1]) / 16; dst_pixel[width-2] = (src_pixel[width-4] + 5 * src_pixel[width-1] + 4 * src_pixel[width-3] + 6 * src_pixel[width-2]) / 16; dst_pixel[width-1] = (src_pixel[width-3] + 5 * src_pixel[width-2] + 10 * src_pixel[width-1]) / 16; // next line src_pixel += pitch; dst_pixel += pitch; } // vertical convolution h_dib -> v_dib src_pixel = (float*)FreeImage_GetBits(h_dib); dst_pixel = (float*)FreeImage_GetBits(v_dib); for(unsigned x = 0; x < width; x++) { // work on column x for(unsigned y = 2; y < height - 2; y++) { const unsigned index = y*pitch + x; dst_pixel[index] = src_pixel[index-2*pitch] + src_pixel[index+2*pitch] + 4 * (src_pixel[index-pitch] + src_pixel[index+pitch]) + 6 * src_pixel[index]; dst_pixel[index] /= 16; } // boundary mirroring dst_pixel[x] = (2 * src_pixel[x+2*pitch] + 8 * src_pixel[x+pitch] + 6 * src_pixel[x]) / 16; dst_pixel[x+pitch] = (src_pixel[x+3*pitch] + 4 * (src_pixel[x] + src_pixel[x+2*pitch]) + 7 * src_pixel[x+pitch]) / 16; dst_pixel[(height-2)*pitch+x] = (src_pixel[(height-4)*pitch+x] + 5 * src_pixel[(height-1)*pitch+x] + 4 * src_pixel[(height-3)*pitch+x] + 6 * src_pixel[(height-2)*pitch+x]) / 16; dst_pixel[(height-1)*pitch+x] = (src_pixel[(height-3)*pitch+x] + 5 * src_pixel[(height-2)*pitch+x] + 10 * src_pixel[(height-1)*pitch+x]) / 16; } FreeImage_Unload(h_dib); h_dib = NULL; // perform downsampling dst = FreeImage_Rescale(v_dib, width/2, height/2, FILTER_BILINEAR); FreeImage_Unload(v_dib); return dst; } catch(int) { if(h_dib) FreeImage_Unload(h_dib); if(v_dib) FreeImage_Unload(v_dib); if(dst) FreeImage_Unload(dst); return NULL; } }
FIBITMAP * DLL_CALLCONV FreeImage_MakeThumbnail(FIBITMAP *dib, int max_pixel_size, BOOL convert) { FIBITMAP *thumbnail = NULL; int new_width, new_height; if(!FreeImage_HasPixels(dib) || (max_pixel_size <= 0)) return NULL; int width = FreeImage_GetWidth(dib); int height = FreeImage_GetHeight(dib); if(max_pixel_size == 0) max_pixel_size = 1; if((width < max_pixel_size) && (height < max_pixel_size)) { // image is smaller than the requested thumbnail return FreeImage_Clone(dib); } if(width > height) { new_width = max_pixel_size; // change image height with the same ratio double ratio = ((double)new_width / (double)width); new_height = (int)(height * ratio + 0.5); if(new_height == 0) new_height = 1; } else { new_height = max_pixel_size; // change image width with the same ratio double ratio = ((double)new_height / (double)height); new_width = (int)(width * ratio + 0.5); if(new_width == 0) new_width = 1; } const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); // perform downsampling using a bilinear interpolation switch(image_type) { case FIT_BITMAP: case FIT_UINT16: case FIT_RGB16: case FIT_RGBA16: case FIT_FLOAT: case FIT_RGBF: case FIT_RGBAF: { FREE_IMAGE_FILTER filter = FILTER_BILINEAR; thumbnail = FreeImage_Rescale(dib, new_width, new_height, filter); } break; case FIT_INT16: case FIT_UINT32: case FIT_INT32: case FIT_DOUBLE: case FIT_COMPLEX: default: // cannot rescale this kind of image thumbnail = NULL; break; } if((thumbnail != NULL) && (image_type != FIT_BITMAP) && convert) { // convert to a standard bitmap FIBITMAP *bitmap = NULL; switch((int)image_type) { case FIT_UINT16: bitmap = FreeImage_ConvertTo8Bits(thumbnail); break; case FIT_RGB16: bitmap = FreeImage_ConvertTo24Bits(thumbnail); break; case FIT_RGBA16: bitmap = FreeImage_ConvertTo32Bits(thumbnail); break; case FIT_FLOAT: bitmap = FreeImage_ConvertToStandardType(thumbnail, TRUE); break; case FIT_RGBF: bitmap = FreeImage_ToneMapping(thumbnail, FITMO_DRAGO03); break; case FIT_RGBAF: // no way to keep the transparency yet ... FIBITMAP *rgbf = FreeImage_ConvertToRGBF(thumbnail); bitmap = FreeImage_ToneMapping(rgbf, FITMO_DRAGO03); FreeImage_Unload(rgbf); break; } if(bitmap != NULL) { FreeImage_Unload(thumbnail); thumbnail = bitmap; } } // copy metadata from src to dst FreeImage_CloneMetadata(thumbnail, dib); return thumbnail; }
void clBitmap::Rescale( int NewW, int NewH ) { FreeImage_Rescale( clPtr<clBitmap>( this ), NewW, NewH ); }
/** Compute the gradient attenuation function PHI(x, y) @param gradients Gradient pyramid (nlevels levels) @param avgGrad Average gradient on each level (array of size nlevels) @param nlevels Number of levels @param alpha Parameter alpha in the paper @param beta Parameter beta in the paper @return Returns the attenuation matrix Phi if successful, returns NULL otherwise */ static FIBITMAP* PhiMatrix(FIBITMAP **gradients, float *avgGrad, int nlevels, float alpha, float beta) { float *src_pixel, *dst_pixel; FIBITMAP **phi = NULL; try { phi = (FIBITMAP**)malloc(nlevels * sizeof(FIBITMAP*)); if(!phi) throw(1); memset(phi, 0, nlevels * sizeof(FIBITMAP*)); for(int k = nlevels-1; k >= 0; k--) { // compute phi(k) FIBITMAP *Gk = gradients[k]; const unsigned width = FreeImage_GetWidth(Gk); const unsigned height = FreeImage_GetHeight(Gk); const unsigned pitch = FreeImage_GetPitch(Gk) / sizeof(float); // parameter alpha is 0.1 times the average gradient magnitude // also, note the factor of 2**k in the denominator; // that is there to correct for the fact that an average gradient avgGrad(H) over 2**k pixels // in the original image will appear as a gradient grad(Hk) = 2**k*avgGrad(H) over a single pixel in Hk. float ALPHA = alpha * avgGrad[k] * (float)((int)1 << k); if(ALPHA == 0) ALPHA = EPSILON; phi[k] = FreeImage_AllocateT(FIT_FLOAT, width, height); if(!phi[k]) throw(1); src_pixel = (float*)FreeImage_GetBits(Gk); dst_pixel = (float*)FreeImage_GetBits(phi[k]); for(unsigned y = 0; y < height; y++) { for(unsigned x = 0; x < width; x++) { // compute (alpha / grad) * (grad / alpha) ** beta const float v = src_pixel[x] / ALPHA; const float value = (float)pow((float)v, (float)(beta-1)); dst_pixel[x] = (value > 1) ? 1 : value; } // next line src_pixel += pitch; dst_pixel += pitch; } if(k < nlevels-1) { // compute PHI(k) = L( PHI(k+1) ) * phi(k) FIBITMAP *L = FreeImage_Rescale(phi[k+1], width, height, FILTER_BILINEAR); if(!L) throw(1); src_pixel = (float*)FreeImage_GetBits(L); dst_pixel = (float*)FreeImage_GetBits(phi[k]); for(unsigned y = 0; y < height; y++) { for(unsigned x = 0; x < width; x++) { dst_pixel[x] *= src_pixel[x]; } // next line src_pixel += pitch; dst_pixel += pitch; } FreeImage_Unload(L); // PHI(k+1) is no longer needed FreeImage_Unload(phi[k+1]); phi[k+1] = NULL; } // next level } // get the final result and return FIBITMAP *dst = phi[0]; free(phi); return dst; } catch(int) { if(phi) { for(int k = nlevels-1; k >= 0; k--) { if(phi[k]) FreeImage_Unload(phi[k]); } free(phi); } return NULL; } }
void FreeImage::_updateSize() { FIBITMAP * resizedImage = FreeImage_Rescale( this -> freeImage, this -> size.x, this -> size.y, ( FREE_IMAGE_FILTER ) this -> resampleFilter ); FreeImage_Unload( freeImage ); freeImage = resizedImage; this -> stride = FreeImage_GetPitch( this -> freeImage ); }
MOboolean moTextureBuffer::LoadImage( moText p_ImageName, moBitmap* pImage, int indeximage ) { MOboolean res = false; FIBITMAP* _pImage = (FIBITMAP*)pImage; FIBITMAP* pImageResult = NULL; FIBITMAP* pImageCropped = NULL; FIBITMAP* pImageScaled = NULL; /* if ( m_width!=FreeImage_GetWidth(_pImage) || m_height!=FreeImage_GetHeight(_pImage) ) { //CROP MODE pImageCropped = FreeImage_Copy( _pImage, m_XSource , m_YSource , m_XSource + m_SourceWidth , m_YSource+m_SourceHeight ); pImageResult = pImageCropped; } else */ pImageResult = _pImage; int w, h; if ( ( FreeImage_GetWidth(_pImage) % 4 ) != 0 || ( FreeImage_GetHeight(_pImage) % 4) == 0 ) { w = FreeImage_GetWidth(_pImage) / 4; w = w * 4; h = FreeImage_GetHeight(_pImage) / 4; h = h * 4; pImageScaled = FreeImage_Rescale( pImageResult, w, h, FILTER_BICUBIC ); if (pImageScaled) { //FreeImage_Unload(pImageResult); pImageResult = pImageScaled; } } FreeImage_AdjustContrast( pImageResult, 0 ); FreeImage_AdjustBrightness( pImageResult, 0 ); //RESCALE: NOTE NECESARRY HERE //quizas podamos definir un máximo para el tamaño tanto ancho como alto //o como proporción //forzar proporcion y esas cosas.... /* if ( m_width != m_SourceWidth || m_height != m_SourceHeight ) { //FILTER_BOX Box, pulse, Fourier window, 1st order (constant) B-Spline //FILTER_BILINEAR Bilinear filter //FILTER_BSPLINE 4th order (cubic) B-Spline //FILTER_BICUBIC Mitchell and Netravali's two-param cubic filter //FILTER_CATMULLROM Catmull-Rom spline, Overhauser spline //FILTER_LANCZOS3 pImageScaled = FreeImage_Rescale( pImageResult, m_width, m_height, FILTER_BICUBIC ); if (pImageScaled) { FreeImage_Unload(pImageResult); pImageResult = pImageScaled; } } */ moTextureMemory* pTextureMemory = NULL; int idx = m_pResourceManager->GetTextureMan()->AddTexture( MO_TYPE_TEXTUREMEMORY, p_ImageName ); if (idx>-1) { pTextureMemory = (moTextureMemory*) m_pResourceManager->GetTextureMan()->GetTexture(idx); if (pTextureMemory) { if (pTextureMemory->BuildFromBitmap( pImageResult, m_BufferFormat )) { m_Frames.Add(pTextureMemory); int contrastlevel = pTextureMemory->GetContrast() / 2000; int luminancelevel = (int)((float)pTextureMemory->GetLuminance() / (float)2.56 ) - 1; MODebug2->Message( moText("moTextureBuffer::LoadImage success : ") + (moText)pTextureMemory->GetName()); #ifdef _DEBUG MODebug2->Message( moText("moTextureBuffer::LoadImage success : ") + (moText)pTextureMemory->GetName() + moText(" width:") + IntToStr(pTextureMemory->GetWidth()) + moText(" height:") + IntToStr(pTextureMemory->GetHeight()) + moText(" luminance:") + IntToStr(pTextureMemory->GetLuminance()) + moText(" luminancelevel:") + IntToStr(luminancelevel) + + moText(" contrast:") + IntToStr(pTextureMemory->GetContrast()) + moText(" contrastlevel:") + IntToStr(contrastlevel) ); #endif contrastlevel = 0; if (luminancelevel>=100) { MODebug2->Error( moText("moTextureBuffer::LoadImage Error: luminance out of bound:")+ IntToStr(pTextureMemory->GetLuminance()) ); } else { if (max_luminance<luminancelevel) { max_luminance = luminancelevel; } else if (min_luminance>luminancelevel) { min_luminance = luminancelevel; } } if (contrastlevel>=10) { MODebug2->Error( moText("moTextureBuffer::LoadImage Error: contrast out of bound:")+ IntToStr(pTextureMemory->GetContrast()) ); } if (0<=luminancelevel && luminancelevel<100 && 0<=contrastlevel && contrastlevel<10) { m_pBufferLevels[luminancelevel][contrastlevel].Add( pTextureMemory ); int icc = momin( m_pBufferLevels[luminancelevel][contrastlevel].Count(), 99 ); LevelDiagram[ (luminancelevel + icc*100)*3 ] = 250; LevelDiagram[ (luminancelevel+1 + icc*100)*3 ] = 250; LevelDiagram[ (luminancelevel+2 + icc*100)*3 ] = 250; } res = true; } else { res = false; MODebug2->Error( moText("moTextureBuffer::LoadImage Error loading image:")+(moText)pTextureMemory->GetName()); } } } if (pImageResult!=_pImage) FreeImage_Unload(pImageResult); //m_nFrames = m_Frames.Count(); //m_fFramesPerSecond = 25.0; return (res); }
static struct graphics_image_priv * image_new(struct graphics_priv *gr, struct graphics_image_methods *meth, char *path, int *w, int *h, struct point *hot, int rotation) { #if USE_FREEIMAGE FIBITMAP *image; RGBQUAD aPixel; unsigned char *data; int width, height, i, j; struct graphics_image_priv *gi; //check if image already exists in hashmap struct graphics_image_priv *curr_elem = g_hash_table_lookup(hImageData, path); if (curr_elem == &image_error) { //found but couldn't be loaded return NULL; } else if (curr_elem) { //found and OK -> use hastable entry *w = curr_elem->w; *h = curr_elem->h; hot->x = curr_elem->w / 2 - 1; hot->y = curr_elem->h / 2 - 1; return curr_elem; } else { if (strlen(path) < 4) { g_hash_table_insert(hImageData, g_strdup(path), &image_error); return NULL; } char *ext_str = path + strlen(path) - 3; if (strstr(ext_str, "png") || strstr(path, "PNG")) { if ((image = FreeImage_Load(FIF_PNG, path, 0)) == NULL) { g_hash_table_insert(hImageData, g_strdup(path), &image_error); return NULL; } } else if (strstr(ext_str, "xpm") || strstr(path, "XPM")) { if ((image = FreeImage_Load(FIF_XPM, path, 0)) == NULL) { g_hash_table_insert(hImageData, g_strdup(path), &image_error); return NULL; } } else if (strstr(ext_str, "svg") || strstr(path, "SVG")) { char path_new[256]; snprintf(path_new, strlen(path) - 3, "%s", path); strcat(path_new, "_48_48.png"); if ((image = FreeImage_Load(FIF_PNG, path_new, 0)) == NULL) { g_hash_table_insert(hImageData, g_strdup(path), &image_error); return NULL; } } else { g_hash_table_insert(hImageData, g_strdup(path), &image_error); return NULL; } if (FreeImage_GetBPP(image) == 64) { FIBITMAP *image2; image2 = FreeImage_ConvertTo32Bits(image); FreeImage_Unload(image); image = image2; } #if FREEIMAGE_MAJOR_VERSION*100+FREEIMAGE_MINOR_VERSION >= 313 if (rotation) { FIBITMAP *image2; image2 = FreeImage_Rotate(image, rotation, NULL); image = image2; } #endif gi = g_new0(struct graphics_image_priv, 1); width = FreeImage_GetWidth(image); height = FreeImage_GetHeight(image); if ((*w != width || *h != height) && 0 < *w && 0 < *h) { FIBITMAP *image2; image2 = FreeImage_Rescale(image, *w, *h, NULL); FreeImage_Unload(image); image = image2; width = *w; height = *h; } data = (unsigned char *) malloc(width * height * 4); RGBQUAD *palette = NULL; if (FreeImage_GetBPP(image) == 8) { palette = FreeImage_GetPalette(image); } for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { unsigned char idx; if (FreeImage_GetBPP(image) == 8) { FreeImage_GetPixelIndex(image, j, height - i - 1, &idx); data[4 * width * i + 4 * j + 0] = palette[idx].rgbRed; data[4 * width * i + 4 * j + 1] = palette[idx].rgbGreen; data[4 * width * i + 4 * j + 2] = palette[idx].rgbBlue; data[4 * width * i + 4 * j + 3] = 255; } else if (FreeImage_GetBPP(image) == 16 || FreeImage_GetBPP(image) == 24 || FreeImage_GetBPP(image) == 32) { FreeImage_GetPixelColor(image, j, height - i - 1, &aPixel); int transparent = (aPixel.rgbRed == 0 && aPixel.rgbBlue == 0 && aPixel.rgbGreen == 0); data[4 * width * i + 4 * j + 0] = transparent ? 0 : (aPixel. rgbRed); data[4 * width * i + 4 * j + 1] = (aPixel.rgbGreen); data[4 * width * i + 4 * j + 2] = transparent ? 0 : (aPixel. rgbBlue); data[4 * width * i + 4 * j + 3] = transparent ? 0 : 255; } } } FreeImage_Unload(image); *w = width; *h = height; gi->w = width; gi->h = height; gi->hot_x = width / 2 - 1; gi->hot_y = height / 2 - 1; hot->x = width / 2 - 1; hot->y = height / 2 - 1; gi->data = data; gi->path = path; //add to hashtable g_hash_table_insert(hImageData, g_strdup(path), gi); return gi; } #else return NULL; #endif }
bool ImageLoader:: load(const std::string& imageName, bool isNormalMap) { // 载入图片 FREE_IMAGE_FORMAT fif = FreeImage_GetFileType(imageName.c_str()); if((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif)) { if (mDIB) FreeImage_Unload(mDIB); mDIB = FreeImage_Load(fif, imageName.c_str()); mFormat = fif; bool needScale = !oiram::fequal(config.imageScale, 1.0f); unsigned int newWidth = width(), newHeight = height(), newBpp = bpp(); bool imagePowerOfTwo = config.imagePowerOfTwo; unsigned int imageMaxSize = config.imageMaxSize; // PVRTCII支持non-POT; ETC1和ETC2必须是POT, 最大尺寸限定在2048, 而且必须是正方形 if (config.imageCompressionType == CT_ETC1 || config.imageCompressionType == CT_ETC2) { imagePowerOfTwo = true; imageMaxSize = 2048; } // DXTC/PVRTC/ETCI有最小尺寸限制 switch (config.imageCompressionType) { case CT_DXTC: if (newWidth < DXT_MIN_TEXWIDTH) { newWidth = DXT_MIN_TEXWIDTH; needScale = true; } if (newHeight < DXT_MIN_TEXHEIGHT) { newHeight = DXT_MIN_TEXHEIGHT; needScale = true; } // DXTC的尺寸必须是4的倍数 { unsigned int multiplesOfFourWidth = nearestMultiplesOfFour(newWidth), multiplesOfFourHeight = nearestMultiplesOfFour(newHeight); if (newWidth != multiplesOfFourWidth) { newWidth = multiplesOfFourWidth; needScale = true; } if (newHeight != multiplesOfFourHeight) { newHeight = multiplesOfFourHeight; needScale = true; } } break; case CT_ETC1: case CT_ETC2: if (newWidth < ETC_MIN_TEXWIDTH) { newWidth = ETC_MIN_TEXWIDTH; needScale = true; } if (newHeight < ETC_MIN_TEXHEIGHT) { newHeight = ETC_MIN_TEXHEIGHT; needScale = true; } break; case CT_PVRTC2_4BPP: if (newWidth < PVRTC4_MIN_TEXWIDTH) { newWidth = PVRTC4_MIN_TEXWIDTH; needScale = true; } if (newHeight < PVRTC4_MIN_TEXHEIGHT) { newHeight = PVRTC4_MIN_TEXHEIGHT; needScale = true; } break; } // 超出最大尺寸则按比例缩放 if (imageMaxSize > 0 && (newWidth > imageMaxSize || newHeight > imageMaxSize)) { if (newWidth > newHeight) { float scale = static_cast<float>(newWidth) / newHeight; newWidth = imageMaxSize; newHeight = static_cast<unsigned int>(newWidth / scale); } else { float scale = static_cast<float>(newHeight) / newWidth; newHeight = imageMaxSize; newWidth = static_cast<unsigned int>(newHeight / scale); } needScale = true; } newWidth = static_cast<unsigned int>(newWidth * config.imageScale); newHeight = static_cast<unsigned int>(newHeight * config.imageScale); if (imagePowerOfTwo) { unsigned int potWidth = nearestPowerOfTwo(newWidth), potHeight = nearestPowerOfTwo(newHeight); if (newWidth != potWidth || newHeight != potHeight) { newWidth = potWidth; newHeight = potHeight; needScale = true; } } if (needScale) { FIBITMAP* rescaleDIB = FreeImage_Rescale(mDIB, newWidth, newHeight, FILTER_LANCZOS3); FreeImage_Unload(mDIB); mDIB = rescaleDIB; } return true; } return false; }
void task_glow_precalc() { FIMULTIBITMAP* anim = inputanim; float thresh=0.5; float gain=2.0; float blur=1.5; int frameskip=1; sscanf(args[1].c_str(), "%f", &thresh); sscanf(args[2].c_str(), "%f", &gain); sscanf(args[3].c_str(), "%f", &blur); sscanf(args[4].c_str(), "%i", &frameskip); int frameCount = FreeImage_GetPageCount(anim); vector<double> fb; for (int frame=0; frame<frameCount/frameskip; frame++) { FIBITMAP* fiBitmap = FreeImage_LockPage(anim, frame*frameskip); FIBITMAP* grayBitmap = FreeImage_ConvertToGreyscale(fiBitmap); FreeImage_UnlockPage(anim, fiBitmap, FALSE); int width = FreeImage_GetWidth(grayBitmap); int height = FreeImage_GetHeight(grayBitmap); // put into an array of doubles (phew) fb.resize(width*height); for (int y=0; y<height; y++) { BYTE* src = FreeImage_GetScanLine(grayBitmap, y); double* dst = &fb[y*width]; for (int x=0; x<width; x++) { *dst++ = *src++ * (1.0/255); } } // threshold for (int i=0; i<(int)fb.size(); i++) { double& v = fb[i]; v = (v-thresh)*gain; if (v<0) v=0; } // blur Blur(fb, width, height, blur); // put it back into greyBitmap for (int y=0; y<height; y++) { BYTE* dst = FreeImage_GetScanLine(grayBitmap, y); double* src = &fb[y*width]; for (int x=0; x<width; x++) { double v = *src++ * 256; if (v<0) v=0; if (v>255) v=255; *dst++ = int(v); } } // downsample it to glowgrid FIBITMAP* smallBitmap = FreeImage_Rescale(grayBitmap, GLOWGRID_W, GLOWGRID_H, FILTER_BSPLINE); // print result (should use 4bpp not 8?) for (int y=0; y<GLOWGRID_H; y++) { BYTE* src = FreeImage_GetScanLine(smallBitmap, y); for (int x=0; x<GLOWGRID_W; x++) { putchar( *src++ ); } } } }
/// 图片另存为 Bool FreeImageImage::saveToFile(ImageFileFormat eFileFormat, PCStr pszFileName, Rect* pRectClip, Point* pResize) { if (!isLoaded()) return False; FREE_IMAGE_FORMAT eFreeImageFormat; switch (eFileFormat) { case IFF_BMP: eFreeImageFormat = FIF_BMP; break; case IFF_PNG: eFreeImageFormat = FIF_PNG; break; case IFF_JPG: eFreeImageFormat = FIF_JPEG; break; default: return False; } Point ptLeftTop(0, 0); Point ptSize(_ptImgSize.x, _ptImgSize.y); // 有裁减矩形 if (pRectClip) { ptLeftTop.setPoint(pRectClip->x1, pRectClip->y1); ptSize = pRectClip->getSize(); if (ptLeftTop.x + ptSize.x > _ptImgSize.x || ptLeftTop.y + ptSize.y > _ptImgSize.y) return False; } FIBITMAP* pFIBitmap = FreeImage_Allocate(ptSize.x, ptSize.y, 32, 8, 8, 8); for(Int y = 0; y < ptSize.y; ++y) { // 需要考虑到 图片倒转 Int nSrcFlipY = _ptImgSize.y - y - 1 - ptLeftTop.y; Int nDstFlipY = ptSize.y - y - 1; Color* pColorSrc = &_pImgData[_ptImgSize.x * nSrcFlipY + ptLeftTop.x]; Color* pColorDst = (Color*)FreeImage_GetScanLine(pFIBitmap, nDstFlipY); memcpy(pColorDst, pColorSrc, sizeof(Color) * ptSize.x); } if (pResize) { if (0 == pResize->x && 0 < pResize->y) pResize->x = (Int16)((Real)pResize->y / (Real)ptSize.y * (Real)ptSize.x); if (0 == pResize->y && 0 < pResize->x) pResize->y = (Int16)((Real)pResize->x / (Real)ptSize.x * (Real)ptSize.y); pFIBitmap = FreeImage_Rescale(pFIBitmap, pResize->x, pResize->y, FILTER_BILINEAR); } Bool isSuccess = FreeImage_Save(eFreeImageFormat, pFIBitmap, pszFileName, PNG_DEFAULT); FreeImage_Unload(pFIBitmap); return isSuccess; }
static INT_PTR serviceBmpFilterResizeBitmap(WPARAM wParam,LPARAM lParam) { BITMAP bminfo; int width, height; int xOrig, yOrig, widthOrig, heightOrig; ResizeBitmap *info = (ResizeBitmap *) wParam; if (info == NULL || info->size != sizeof(ResizeBitmap) || info->hBmp == NULL || info->max_width < 0 || info->max_height < 0 || (info->fit & ~RESIZEBITMAP_FLAG_DONT_GROW) < RESIZEBITMAP_STRETCH || (info->fit & ~RESIZEBITMAP_FLAG_DONT_GROW) > RESIZEBITMAP_MAKE_SQUARE) return 0; // Well, lets do it // Calc final size GetObject(info->hBmp, sizeof(bminfo), &bminfo); width = info->max_width == 0 ? bminfo.bmWidth : info->max_width; height = info->max_height == 0 ? bminfo.bmHeight : info->max_height; xOrig = 0; yOrig = 0; widthOrig = bminfo.bmWidth; heightOrig = bminfo.bmHeight; if (widthOrig == 0 || heightOrig == 0) return 0; switch(info->fit & ~RESIZEBITMAP_FLAG_DONT_GROW) { case RESIZEBITMAP_STRETCH: { // Do nothing break; } case RESIZEBITMAP_KEEP_PROPORTIONS: { if (height * widthOrig / heightOrig <= width) { if (info->fit & RESIZEBITMAP_FLAG_DONT_GROW) height = min(height, bminfo.bmHeight); width = height * widthOrig / heightOrig; } else { if (info->fit & RESIZEBITMAP_FLAG_DONT_GROW) width = min(width, bminfo.bmWidth); height = width * heightOrig / widthOrig; } break; } case RESIZEBITMAP_MAKE_SQUARE: { if (info->fit & RESIZEBITMAP_FLAG_DONT_GROW) { width = min(width, bminfo.bmWidth); height = min(height, bminfo.bmHeight); } width = height = min(width, height); // Do not break. Use crop calcs to make size } case RESIZEBITMAP_CROP: { if (heightOrig * width / height >= widthOrig) { heightOrig = widthOrig * height / width; yOrig = (bminfo.bmHeight - heightOrig) / 2; } else { widthOrig = heightOrig * width / height; xOrig = (bminfo.bmWidth - widthOrig) / 2; } break; } } if ((width == bminfo.bmWidth && height == bminfo.bmHeight) || ((info->fit & RESIZEBITMAP_FLAG_DONT_GROW) && !(info->fit & RESIZEBITMAP_MAKE_SQUARE) && width > bminfo.bmWidth && height > bminfo.bmHeight)) { // Do nothing return (INT_PTR)info->hBmp; } else { FIBITMAP *dib = FreeImage_CreateDIBFromHBITMAP(info->hBmp); if (dib == NULL) return NULL; FIBITMAP *dib_tmp; if (xOrig > 0 || yOrig > 0) dib_tmp = FreeImage_Copy(dib, xOrig, yOrig, xOrig + widthOrig, yOrig + heightOrig); else dib_tmp = dib; if (dib_tmp == NULL) { FreeImage_Unload(dib); return NULL; } FIBITMAP *dib_new = FreeImage_Rescale(dib_tmp, width, height, FILTER_CATMULLROM); HBITMAP bitmap_new = FreeImage_CreateHBITMAPFromDIB(dib_new); if (dib_new != dib_tmp) FreeImage_Unload(dib_new); if (dib_tmp != dib) FreeImage_Unload(dib_tmp); FreeImage_Unload(dib); return (INT_PTR)bitmap_new; } }
void poImage::resize(float w, float h) { FIBITMAP *img = FreeImage_Rescale(bitmap, w, h, FILTER_CATMULLROM); FreeImage_Unload(bitmap); bitmap = img; }
const QImage ImageLoaderFreeImage::imageAsRGB(const QSize &size) const { const QSize resultSize = size.isValid() ? size : sizePixels(); const bool isRGB24 = colorDataType() == Types::ColorTypeRGB && bitsPerPixel() == 24; const bool isARGB32 = colorDataType() == Types::ColorTypeRGBA && bitsPerPixel() == 32; QImage result(resultSize, isARGB32 ? QImage::Format_ARGB32 : QImage::Format_RGB32); const int width = resultSize.width(); const int height = resultSize.height(); const QSize sizePixels = this->sizePixels(); FIBITMAP* originalImage = m_bitmap; FIBITMAP* temp24BPPImage = NULL; FIBITMAP* scaledImage = NULL; if (!(isRGB24 || isARGB32)) { if (colorDataType() == Types::ColorTypeCMYK) { const bool isCmykJpeg = isJpeg(); // Value range inverted temp24BPPImage = FreeImage_Allocate(sizePixels.width(), sizePixels.height(), 24); const unsigned int columnsCount = sizePixels.width(); const unsigned int scanlinesCount = sizePixels.height(); for (unsigned int scanline = 0; scanline < scanlinesCount; scanline++) { const BYTE* const cmykBits = FreeImage_GetScanLine(m_bitmap, scanline); tagRGBTRIPLE* const rgbBits = (tagRGBTRIPLE *)FreeImage_GetScanLine(temp24BPPImage, scanline); for (unsigned int column = 0; column < columnsCount; column++) { const unsigned int cmykColumn = column * 4; const QColor rgbColor = isCmykJpeg ? QColor::fromCmyk(255 - cmykBits[cmykColumn], 255 - cmykBits[cmykColumn + 1], 255 - cmykBits[cmykColumn + 2], 255 - cmykBits[cmykColumn + 3]) : QColor::fromCmyk(cmykBits[cmykColumn], cmykBits[cmykColumn + 1], cmykBits[cmykColumn + 2], cmykBits[cmykColumn + 3]); rgbBits[column].rgbtRed = (BYTE)rgbColor.red(); rgbBits[column].rgbtGreen = (BYTE)rgbColor.green(); rgbBits[column].rgbtBlue = (BYTE)rgbColor.blue(); } } } else { temp24BPPImage = FreeImage_ConvertTo24Bits(originalImage); } originalImage = temp24BPPImage; } if (resultSize != sizePixels) { scaledImage = FreeImage_Rescale(originalImage, width, height, FILTER_BOX); originalImage = scaledImage; } for (int scanline = 0; scanline < height; scanline++) { QRgb *targetData = (QRgb*)result.scanLine(scanline); if (isARGB32) { const tagRGBQUAD *sourceRgba = (tagRGBQUAD*)FreeImage_GetScanLine(originalImage, height - scanline - 1); for (int column = 0; column < width; column++) { *targetData++ = qRgba(sourceRgba->rgbRed, sourceRgba->rgbGreen, sourceRgba->rgbBlue, sourceRgba->rgbReserved); sourceRgba++; } } else { const tagRGBTRIPLE *sourceRgb = (tagRGBTRIPLE*)FreeImage_GetScanLine(originalImage, height - scanline - 1); for (int column = 0; column < width; column++) { *targetData++ = qRgb(sourceRgb->rgbtRed, sourceRgb->rgbtGreen, sourceRgb->rgbtBlue); sourceRgb++; } } } if (temp24BPPImage) FreeImage_Unload(temp24BPPImage); if (scaledImage) FreeImage_Unload(scaledImage); return result; }