int DLL_CALLCONV
FIA_ReplaceColourPlanesHSV (FIBITMAP **src, FIBITMAP *H, FIBITMAP *S, FIBITMAP *V)
{
	// HSV source images must all be the same size
	FIBITMAP *R=NULL, *G=NULL, *B=NULL;
	int x, y;
	double h, s, v;

	// Check we have valid images
	if (!FreeImage_HasPixels(H) || !FIA_Is8Bit(H) ||
		!FreeImage_HasPixels(S) || !FIA_Is8Bit(S) ||
		!FreeImage_HasPixels(V) || !FIA_Is8Bit(V)) {
			return FIA_ERROR;
	}

	// alloc RGB to something the same size as the source images
	R = FreeImage_Clone(H);
	G = FreeImage_Clone(H);
	B = FreeImage_Clone(H);
 
	// Convert the HSV values to RGB and store
	for(y = 0; y < FreeImage_GetHeight(H); y++) {
		BYTE *src_h = FreeImage_GetScanLine(H, y);
		BYTE *src_s = FreeImage_GetScanLine(S, y);
		BYTE *src_v = FreeImage_GetScanLine(V, y);
		BYTE *dst_r = FreeImage_GetScanLine(R, y);
		BYTE *dst_g = FreeImage_GetScanLine(G, y);
		BYTE *dst_b = FreeImage_GetScanLine(B, y);
		
		for(x = 0; x < FreeImage_GetWidth(H); x++) {

			// Red, Green and Blue are between 0 and 255
			// Hue varies between 0 and 360
			// Satuation between 0 and 1
			// Value between 0 and 1

			h = ((double)(*src_h))/255.0 * 360.0;
			s = ((double)(*src_s))/255.0;
			v = ((double)(*src_v))/255.0;

			FIA_HSVToRGB (h, s, v, dst_r, dst_g, dst_b);

			// jump to next pixel
			src_h ++;
			src_s ++;
			src_v ++;
			dst_r ++;
			dst_g ++;
			dst_b ++;
		 }
	}

	FIA_ReplaceColourPlanes (src, R, G, B);

	FreeImage_Unload(R);
	FreeImage_Unload(G);
	FreeImage_Unload(B);

	return FIA_SUCCESS;
}
int DLL_CALLCONV
FIA_ReplaceColourPlanes (FIBITMAP **src, FIBITMAP *R, FIBITMAP *G, FIBITMAP *B)
{

	if (FreeImage_HasPixels(R) && FIA_Is8Bit(R)) {
		if (*src==NULL)
			*src = FreeImage_Allocate (FreeImage_GetWidth(R), FreeImage_GetHeight(R), 24);
		FIA_SetGreyLevelPalette (R);
		FreeImage_SetChannel(*src, R, FICC_RED);
	}
	
	if (FreeImage_HasPixels(G) && FIA_Is8Bit(G)) {
		if (*src==NULL)
			*src = FreeImage_Allocate (FreeImage_GetWidth(G), FreeImage_GetHeight(G), 24);
		FIA_SetGreyLevelPalette (G);
		FreeImage_SetChannel(*src, G, FICC_GREEN);
	}
	
	if (FreeImage_HasPixels(B) && FIA_Is8Bit(B)) {
		if (*src==NULL)
			*src = FreeImage_Allocate (FreeImage_GetWidth(B), FreeImage_GetHeight(B), 24);
		FIA_SetGreyLevelPalette (B);
		FreeImage_SetChannel(*src, B, FICC_BLUE);
	}
		
	return FIA_SUCCESS;
}
Example #3
0
/**
Pre-multiplies a 32-bit image's red-, green- and blue channels with it's alpha channel 
for to be used with e.g. the Windows GDI function AlphaBlend(). 
The transformation changes the red-, green- and blue channels according to the following equation:  
channel(x, y) = channel(x, y) * alpha_channel(x, y) / 255  
@param dib Input/Output dib to be premultiplied
@return Returns TRUE on success, FALSE otherwise (e.g. when the bitdepth of the source dib cannot be handled). 
*/
BOOL DLL_CALLCONV 
FreeImage_PreMultiplyWithAlpha(FIBITMAP *dib) {
	if (!FreeImage_HasPixels(dib)) return FALSE;
	
	if ((FreeImage_GetBPP(dib) != 32) || (FreeImage_GetImageType(dib) != FIT_BITMAP)) {
		return FALSE;
	}

	int width = FreeImage_GetWidth(dib);
	int height = FreeImage_GetHeight(dib);

	for(int y = 0; y < height; y++) {
		BYTE *bits = FreeImage_GetScanLine(dib, y);
		for (int x = 0; x < width; x++, bits += 4) {
			const BYTE alpha = bits[FI_RGBA_ALPHA];
			// slightly faster: care for two special cases
			if(alpha == 0x00) {
				// special case for alpha == 0x00
				// color * 0x00 / 0xFF = 0x00
				bits[FI_RGBA_BLUE] = 0x00;
				bits[FI_RGBA_GREEN] = 0x00;
				bits[FI_RGBA_RED] = 0x00;
			} else if(alpha == 0xFF) {
				// nothing to do for alpha == 0xFF
				// color * 0xFF / 0xFF = color
				continue;
			} else {
				bits[FI_RGBA_BLUE] = (BYTE)( (alpha * (WORD)bits[FI_RGBA_BLUE] + 127) / 255 );
				bits[FI_RGBA_GREEN] = (BYTE)( (alpha * (WORD)bits[FI_RGBA_GREEN] + 127) / 255 );
				bits[FI_RGBA_RED] = (BYTE)( (alpha * (WORD)bits[FI_RGBA_RED] + 127) / 255 );
			}
		}
	}
	return TRUE;
}
Example #4
0
/**
Apply the global/local tone mapping operator to a RGBF image and convert to 24-bit RGB<br>
User parameters control intensity, contrast, and level of adaptation
@param src Input RGBF image
@param intensity Overall intensity in range [-8:8] : default to 0
@param contrast Contrast in range [0.3:1) : default to 0
@param adaptation Adaptation in range [0:1] : default to 1
@param color_correction Color correction in range [0:1] : default to 0
@return Returns a 24-bit RGB image if successful, returns NULL otherwise
*/
FIBITMAP* DLL_CALLCONV 
FreeImage_TmoReinhard05Ex(FIBITMAP *src, double intensity, double contrast, double adaptation, double color_correction) {
	if(!FreeImage_HasPixels(src)) return NULL;

	// working RGBF variable
	FIBITMAP *dib = NULL, *Y = NULL;

	dib = FreeImage_ConvertToRGBF(src);
	if(!dib) return NULL;

	// get the Luminance channel
	Y = ConvertRGBFToY(dib);
	if(!Y) {
		FreeImage_Unload(dib);
		return NULL;
	}

	// perform the tone mapping
	ToneMappingReinhard05(dib, Y, (float)intensity, (float)contrast, (float)adaptation, (float)color_correction);
	// not needed anymore
	FreeImage_Unload(Y);
	// clamp image highest values to display white, then convert to 24-bit RGB
	FIBITMAP *dst = ClampConvertRGBFTo24(dib);

	// clean-up and return
	FreeImage_Unload(dib);

	// copy metadata from src to dst
	FreeImage_CloneMetadata(dst, src);

	return dst;
}
Example #5
0
/**
 * Clears the image to the chosen color. Returns 0 if there is no image loaded.
 * For ::IND_LUMINANCE image type, the 'color' value is taken from the pA parameter. Other parameters are ignored
 * @param pR						Byte R (Red).
 * @param pG						Byte G (Green).
 * @param pB						Byte B (Blue).
 * @param pA						Byte A (Transparency).
 */
bool IND_Image::clear(BYTE pR, BYTE pG, BYTE pB, BYTE pA) {
	// No image loaded
	if (!isImageLoaded() || !FreeImage_HasPixels(getFreeImageHandle())) 
		return false;

	FIBITMAP* dib = getFreeImageHandle();
	FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
	int bpp (getBpp());
	int bytespp = bpp/8;
	int colorFormat =  getFormatInt();

	//Interprets differently depending on image type
	switch(image_type) {
		case FIT_BITMAP:
			//LOOP - Y coords
			for(unsigned y = 0; y < FreeImage_GetHeight(dib); y++) {
				BYTE *bits = FreeImage_GetScanLine(dib, y);
				//LOOP - X coords
				for(unsigned x = 0; x < FreeImage_GetWidth(dib); x++) {
					// Set pixel color to total transparency, if color matches given colorkey
					
					//RGBx color format
					if(IND_COLOUR_INDEX != colorFormat && IND_LUMINANCE != colorFormat) {
						bits[FI_RGBA_RED] = pR;
						bits[FI_RGBA_GREEN] = pG;
						bits[FI_RGBA_BLUE] = pB;
					} else if (IND_COLOUR_INDEX == colorFormat) {
						//TODO
					} else if (IND_LUMINANCE == colorFormat) {
						assert (8 == bpp); //The bpp for IND_LUMINANCE should be 8 for this image type
						*bits = pA;
		}
					 
					if (IND_RGBA == colorFormat) {
						bits[FI_RGBA_ALPHA] = pA;
	}

					// jump to next pixel
					bits += bytespp;
				}//LOOP END
			}//LOOP END
		break;

		//TODO: OTHER IMAGE TYPES
		default:
		break;
	}
	return true;
}
Example #6
0
BOOL DLL_CALLCONV
FreeImage_SetThumbnail(FIBITMAP *dib, FIBITMAP *thumbnail) {
	if(dib == NULL) {
		return FALSE;
	}
	FIBITMAP *currentThumbnail = ((FREEIMAGEHEADER *)dib->data)->thumbnail;
	if(currentThumbnail == thumbnail) {
		return TRUE;
	}
	FreeImage_Unload(currentThumbnail);

	((FREEIMAGEHEADER *)dib->data)->thumbnail = FreeImage_HasPixels(thumbnail) ? FreeImage_Clone(thumbnail) : NULL;

	return TRUE;
}
Example #7
0
/**
 * Puts a pixel in the position and color specified as parameters (in RGBA). Returns 0 if there is no image loaded.
 * If the image format (see ::IND_ColorFormat) doesn't have alpha value (pA) this parameter can be omitted.
 * In the special case of ::IND_LUMINANCE type images, the pixel color must be specified in pA, and other params (pR, pG, pB) are ignored.
 * @param pX						X coordinate.
 * @param pY						Y coordinate.
 * @param pR						Byte R (Red).
 * @param pG						Byte G (Green).
 * @param pB						Byte B (Blue).
 * @param pA						Byte A (Transparency).
 */
bool IND_Image::putPixel(int pX, int pY, BYTE pR, BYTE pG, BYTE pB, BYTE pA) {
	// No image loaded
	if (!isImageLoaded() || !FreeImage_HasPixels(getFreeImageHandle()))  return false;

	// Out of range
	if (pX >= getWidth())	return false;
	if (pY >= getHeight())	return false;
	if (pX < 0)		return false;
	if (pY < 0)		return false;

	FIBITMAP* dib = getFreeImageHandle();
	FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
	int bpp (getBpp());
	int bytespp = bpp/8;
	int colorFormat =  getFormatInt();

	//Interprets differently depending on image type
	switch(image_type) {
		case FIT_BITMAP: {
			//Point to requested y coord
			BYTE *bits = FreeImage_GetScanLine(dib, pY);
			//Point to requested x coord
			bits += (bytespp * pX);
					
			//RGBx color format
			if(IND_COLOUR_INDEX != colorFormat && IND_LUMINANCE != colorFormat) {
				bits[FI_RGBA_RED] = pR;
				bits[FI_RGBA_GREEN] = pG;
				bits[FI_RGBA_BLUE] = pB;
			} else if (IND_COLOUR_INDEX == colorFormat) {
				//TODO
			} else if (IND_LUMINANCE == colorFormat) {
				assert (8 == bpp); //The bpp for IND_LUMINANCE should be 8 for this image type
				*bits = pA;
	}
					 
			if (IND_RGBA == colorFormat) {
				bits[FI_RGBA_ALPHA] = pA;
	}
		break;
	}
		//TODO: OTHER IMAGE TYPES
		default:
			break;	
	}

	return true;
}
Example #8
0
FIBITMAP * DLL_CALLCONV 
FreeImage_Rescale(FIBITMAP *src, int dst_width, int dst_height, FREE_IMAGE_FILTER filter) {
	FIBITMAP *dst = NULL;

	if (!FreeImage_HasPixels(src) || (dst_width <= 0) || (dst_height <= 0) || (FreeImage_GetWidth(src) <= 0) || (FreeImage_GetHeight(src) <= 0)) {
		return NULL;
	}

	// select the filter
	CGenericFilter *pFilter = NULL;
	switch (filter) {
		case FILTER_BOX:
			pFilter = new(std::nothrow) CBoxFilter();
			break;
		case FILTER_BICUBIC:
			pFilter = new(std::nothrow) CBicubicFilter();
			break;
		case FILTER_BILINEAR:
			pFilter = new(std::nothrow) CBilinearFilter();
			break;
		case FILTER_BSPLINE:
			pFilter = new(std::nothrow) CBSplineFilter();
			break;
		case FILTER_CATMULLROM:
			pFilter = new(std::nothrow) CCatmullRomFilter();
			break;
		case FILTER_LANCZOS3:
			pFilter = new(std::nothrow) CLanczos3Filter();
			break;
	}

	if (!pFilter) {
		return NULL;
	}

	CResizeEngine Engine(pFilter);

	dst = Engine.scale(src, dst_width, dst_height, 0, 0,
			FreeImage_GetWidth(src), FreeImage_GetHeight(src));

	delete pFilter;

	// copy metadata from src to dst
	FreeImage_CloneMetadata(dst, src);
	
	return dst;
}
Example #9
0
/** @brief Adjusts the contrast of a 8, 24 or 32-bit image by a certain amount.

@param src Input image to be processed.
@param percentage Where -100 <= percentage <= 100<br>
A value 0 means no change, less than 0 will decrease the contrast 
and greater than 0 will increase the contrast of the image.
@return Returns TRUE if successful, FALSE otherwise.
*/
BOOL DLL_CALLCONV 
FreeImage_AdjustContrast(FIBITMAP *src, double percentage) {
	BYTE LUT[256];		// Lookup table
	double value;

	if(!FreeImage_HasPixels(src))
		return FALSE;
	
	// Build the lookup table
	const double scale = (100 + percentage) / 100;
	for(int i = 0; i < 256; i++) {
		value = 128 + (i - 128) * scale;
		value = MAX(0.0, MIN(value, 255.0));
		LUT[i] = (BYTE)floor(value + 0.5);
	}
	return FreeImage_AdjustCurve(src, LUT, FICC_RGB);
}
Example #10
0
BYTE * DLL_CALLCONV
FreeImage_GetBits(FIBITMAP *dib) {
	if(!FreeImage_HasPixels(dib)) {
		return NULL;
	}

	if(((FREEIMAGEHEADER *)dib->data)->external_bits) {
		return ((FREEIMAGEHEADER *)dib->data)->external_bits;
	}

	// returns the pixels aligned on a FIBITMAP_ALIGNMENT bytes alignment boundary
	size_t lp = (size_t)FreeImage_GetInfoHeader(dib);
	lp += sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * FreeImage_GetColorsUsed(dib);
	lp += FreeImage_HasRGBMasks(dib) ? sizeof(DWORD) * 3 : 0;
	lp += (lp % FIBITMAP_ALIGNMENT ? FIBITMAP_ALIGNMENT - lp % FIBITMAP_ALIGNMENT : 0);
	return (BYTE *)lp;
}
Example #11
0
/** @brief Adjusts an image's brightness, contrast and gamma as well as it may
 optionally invert the image within a single operation.
 
 This function adjusts an image's brightness, contrast and gamma as well as it
 may optionally invert the image within a single operation. If more than one of
 these image display properties need to be adjusted, using this function should
 be preferred over calling each adjustment function separately. That's
 particularly true for huge images or if performance is an issue.
 
 This function relies on FreeImage_GetAdjustColorsLookupTable(), which creates a
 single lookup table, that combines all adjustment operations requested.
 
 Furthermore, the lookup table created by FreeImage_GetAdjustColorsLookupTable()
 does not depend on the order, in which each single adjustment operation is
 performed. Due to rounding and byte casting issues, it actually matters in which
 order individual adjustment operations are performed. Both of the following
 snippets most likely produce different results:
 
 // snippet 1: contrast, brightness
 FreeImage_AdjustContrast(dib, 15.0);
 FreeImage_AdjustBrightness(dib, 50.0); 
 
 // snippet 2: brightness, contrast
 FreeImage_AdjustBrightness(dib, 50.0);
 FreeImage_AdjustContrast(dib, 15.0);
 
 Better and even faster would be snippet 3:
 
 // snippet 3:
 FreeImage_AdjustColors(dib, 50.0, 15.0, 1.0, FALSE);
 
 @param dib Input/output image to be processed.
 @param brightness Percentage brightness value where -100 <= brightness <= 100<br>
 A value of 0 means no change, less than 0 will make the image darker and greater
 than 0 will make the image brighter.
 @param contrast Percentage contrast value where -100 <= contrast <= 100<br>
 A value of 0 means no change, less than 0 will decrease the contrast
 and greater than 0 will increase the contrast of the image.
 @param gamma Gamma value to be used for gamma correction. A value of 1.0 leaves
 the image alone, less than one darkens it, and greater than one lightens it.<br>
 This parameter must not be zero or smaller than zero. If so, it will be ignored
 and no gamma correction will be performed on the image.
 @param invert If set to TRUE, the image will be inverted.
 @return Returns TRUE on success, FALSE otherwise (e.g. when the bitdeph of the
 source dib cannot be handled).
 */
BOOL DLL_CALLCONV
FreeImage_AdjustColors(FIBITMAP *dib, double brightness, double contrast, double gamma, BOOL invert) {
	BYTE LUT[256];

	if (!FreeImage_HasPixels(dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP)) {
		return FALSE;
	}

	int bpp = FreeImage_GetBPP(dib);
	if ((bpp != 8) && (bpp != 24) && (bpp != 32)) {
		return FALSE;
	}

	if (FreeImage_GetAdjustColorsLookupTable(LUT, brightness, contrast, gamma, invert)) {
		return FreeImage_AdjustCurve(dib, LUT, FICC_RGB);
	}
	return FALSE;
}
Example #12
0
/** @brief Performs gamma correction on a 8, 24 or 32-bit image.

@param src Input image to be processed.
@param gamma Gamma value to use. A value of 1.0 leaves the image alone, 
less than one darkens it, and greater than one lightens it.
@return Returns TRUE if successful, FALSE otherwise.
*/
BOOL DLL_CALLCONV 
FreeImage_AdjustGamma(FIBITMAP *src, double gamma) {
	BYTE LUT[256];		// Lookup table

	if(!FreeImage_HasPixels(src) || (gamma <= 0))
		return FALSE;
	
	// Build the lookup table

	double exponent = 1 / gamma;
	double v = 255.0 * (double)pow((double)255, -exponent);
	for(int i = 0; i < 256; i++) {
		double color = (double)pow((double)i, exponent) * v;
		if(color > 255)
			color = 255;
		LUT[i] = (BYTE)floor(color + 0.5);
	}

	// Apply the gamma correction
	return FreeImage_AdjustCurve(src, LUT, FICC_RGB);
}
/**
Poisson solver based on a multigrid algorithm. 
This routine solves a Poisson equation, remap result pixels to [0..1] and returns the solution. 
NB: The input image is first stored inside a square image whose size is (2^j + 1)x(2^j + 1) for some integer j, 
where j is such that 2^j is the nearest larger dimension corresponding to MAX(image width, image height). 
@param Laplacian Laplacian image
@param ncycle Number of cycles in the multigrid algorithm (usually 2 or 3)
@return Returns the solved PDE equations if successful, returns NULL otherwise
*/
FIBITMAP* DLL_CALLCONV 
FreeImage_MultigridPoissonSolver(FIBITMAP *Laplacian, int ncycle) {
	if(!FreeImage_HasPixels(Laplacian)) return NULL;

	int width = FreeImage_GetWidth(Laplacian);
	int height = FreeImage_GetHeight(Laplacian);

	// get nearest larger dimension length that is acceptable by the algorithm
	int n = MAX(width, height);
	int size = 0;
	while((n >>= 1) > 0) size++;
	if((1 << size) < MAX(width, height)) {
		size++;
	}
	// size must be of the form 2^j + 1 for some integer j
	size = 1 + (1 << size);

	// allocate a temporary square image I
	FIBITMAP *I = FreeImage_AllocateT(FIT_FLOAT, size, size);
	if(!I) return NULL;

	// copy Laplacian into I and shift pixels to create a boundary
	FreeImage_Paste(I, Laplacian, 1, 1, 255);

	// solve the PDE equation
	fmg_mglin(I, size, ncycle);

	// shift pixels back
	FIBITMAP *U = FreeImage_Copy(I, 1, 1, width + 1, height + 1);
	FreeImage_Unload(I);

	// remap pixels to [0..1]
	NormalizeY(U, 0, 1);

	// copy metadata from src to dst
	FreeImage_CloneMetadata(U, Laplacian);

	// return the integrated image
	return U;
}
Example #14
0
/**
Performs a tone mapping on a 48-bit RGB or a 96-bit RGBF image and returns a 24-bit image. 
The meaning of the parameters depends on the choosen algorithm. 
When both parameters are set to zero, a default set of parameters is used. 
@param dib Input RGB/RGBF image
@param tmo Tone mapping operator
@param first_param First parameter of the algorithm
@param second_param Second parameter of the algorithm
return Returns a 24-bit tone mapped image if successful, returns NULL otherwise
*/ 
FIBITMAP * DLL_CALLCONV
FreeImage_ToneMapping(FIBITMAP *dib, FREE_IMAGE_TMO tmo, double first_param, double second_param) {
	if(FreeImage_HasPixels(dib)) {
		switch(tmo) {
			// Adaptive logarithmic mapping (F. Drago, 2003)
			case FITMO_DRAGO03:
				if((first_param == 0) && (second_param == 0)) {
					// use default values (gamma = 2.2, exposure = 0)
					return FreeImage_TmoDrago03(dib, 2.2, 0);
				} else {
					// use user's value
					return FreeImage_TmoDrago03(dib, first_param, second_param);
				}
				break;
			// Dynamic range reduction inspired by photoreceptor phhysiology (E. Reinhard, 2005)
			case FITMO_REINHARD05:
				if((first_param == 0) && (second_param == 0)) {
					// use default values by setting intensity to 0 and contrast to 0
					return FreeImage_TmoReinhard05(dib, 0, 0);
				} else {
					// use user's value
					return FreeImage_TmoReinhard05(dib, first_param, second_param);
				}
				break;
			// Gradient Domain HDR Compression (R. Fattal, 2002)
			case FITMO_FATTAL02:
				if((first_param == 0) && (second_param == 0)) {
					// use default values by setting color saturation to 0.5 and attenuation to 0.85
					return FreeImage_TmoFattal02(dib, 0.5, 0.85);
				} else {
					// use user's value
					return FreeImage_TmoFattal02(dib, first_param, second_param);
				}
				break;
		}
	}

	return NULL;
}
Example #15
0
/**
 * Sets the alpha value of all pixels of the specified color to transparent. This is know as "color key". Returns 0 if
 * there is no image loaded.
 * If you call this method on an image not having 32 bpp and ::IND_RGBA format, it will be converted first to that format.
 * It is recommended that you use this method with IND_RGBA color format images and 32 bpp.
 * The method returns true if image could be converted and alpha channel set correctly, false otherwise.
 * @param pR						Byte R (Red).
 * @param pG						Byte G (Green).
 * @param pB						Byte B (Blue).
 */
bool IND_Image::setAlpha(BYTE pR, BYTE pG, BYTE pB) {
	// No image loaded
	if (!isImageLoaded() || !FreeImage_HasPixels(getFreeImageHandle()))  return false;
	
	bool success = true;

	// We add alpha channel if the image hasn't.
	if (getFormatInt() != IND_RGBA) {
		int targetbpp (32);
		if (IND_RGB == getFormatInt()) {
			targetbpp = (getBpp()* 4 )/ 3;
	}

		success = convert(IND_RGBA,targetbpp);
	} 

	if (success) {
	setAlphaChannel(pR, pG, pB);
	}

	return success;
}
/**
Apply the Adaptive Logarithmic Mapping operator to a HDR image and convert to 24-bit RGB
@param src Input RGB16 or RGB[A]F image
@param gamma Gamma correction (gamma > 0). 1 means no correction, 2.2 in the original paper.
@param exposure Exposure parameter (0 means no correction, 0 in the original paper)
@return Returns a 24-bit RGB image if successful, returns NULL otherwise
*/
FIBITMAP* DLL_CALLCONV
FreeImage_TmoDrago03(FIBITMAP *src, double gamma, double exposure) {
    float maxLum, minLum, avgLum;

    if(!FreeImage_HasPixels(src)) return NULL;

    // working RGBF variable
    FIBITMAP *dib = NULL;

    dib = FreeImage_ConvertToRGBF(src);
    if(!dib) return NULL;

    // default algorithm parameters
    const float biasParam = 0.85F;
    const float expoParam = (float)pow(2.0, exposure); //default exposure is 1, 2^0

    // convert to Yxy
    ConvertInPlaceRGBFToYxy(dib);
    // get the luminance
    LuminanceFromYxy(dib, &maxLum, &minLum, &avgLum);
    // perform the tone mapping
    ToneMappingDrago03(dib, maxLum, avgLum, biasParam, expoParam);
    // convert back to RGBF
    ConvertInPlaceYxyToRGBF(dib);
    if(gamma != 1) {
        // perform gamma correction
        REC709GammaCorrection(dib, (float)gamma);
    }
    // clamp image highest values to display white, then convert to 24-bit RGB
    FIBITMAP *dst = ClampConvertRGBFTo24(dib);

    // clean-up and return
    FreeImage_Unload(dib);

    // copy metadata from src to dst
    FreeImage_CloneMetadata(dst, src);

    return dst;
}
Example #17
0
/**
 * Inverts the alpha values (transparency) of the image. Returns 0 if there is no image loaded.
 * Note!: if image type is ::IND_LUMINANCE, it does nothing. Use ::IND_Image::negative() instead.
 */
bool IND_Image::invertAlpha() {
	// No image loaded
	if (!isImageLoaded() || !FreeImage_HasPixels(getFreeImageHandle())) 
		return false;

	int bpp (getBpp());
	int bytespp = bpp/8;
	FIBITMAP* dib = getFreeImageHandle();
	FREE_IMAGE_TYPE imgType = FreeImage_GetImageType(dib);
	
	switch (imgType) {
		case FIT_BITMAP: {
			//TODO: IND_COLOUR_INDEX
			if(getFormatInt() == IND_RGBA) {
			//LOOP - Y coords
			for(unsigned y = 0; y < FreeImage_GetHeight(dib); y++) {
				BYTE *bits = FreeImage_GetScanLine(dib, y);
				//LOOP - X coords
				for(unsigned x = 0; x < FreeImage_GetWidth(dib); x++) {
					// Invert the alpha value in a per-pixel basis
					BYTE alpha = bits[FI_RGBA_ALPHA];
					BYTE max = 255;
					bits[FI_RGBA_ALPHA] = max - alpha;
					// jump to next pixel
					bits += bytespp;
				}//LOOP END
			}//LOOP END
			}
			break;
		}
		//TODO: OTHER IMAGE TYPES
		default:
			break;
	}

	return true;
}
Example #18
0
/** @brief Fills an image with the specified color.

 This function sets all pixels of an image to the color provided through the color
 parameter. Since this should work for all image types supported by FreeImage, the
 pointer color must point to a memory location, which is at least as large as the
 image's color value, if this size is greater than 4 bytes. As the color is specified
 by an RGBQUAD structure for all images of type FIT_BITMAP (including all palletized
 images), the smallest possible size of this memory is the size of the RGBQUAD structure,
 which uses 4 bytes.

 So, color must point to a double, if the image to be filled is of type FIT_DOUBLE and
 point to a RGBF structure if the image is of type FIT_RGBF and so on.

 However, the fill color is always specified through a RGBQUAD structure for all images
 of type FIT_BITMAP. So, for 32- and 24-bit images, the red, green and blue members of
 the RGBQUAD structure are directly used for the image's red, green and blue channel
 respectively. Although alpha transparent RGBQUAD colors are supported, the alpha channel
 of a 32-bit image never gets modified by this function. A fill color with an alpha value
 smaller than 255 gets blended with the image's actual background color, which is determined
 from the image's bottom-left pixel. So, currently using alpha enabled colors, assumes the
 image to be unicolor before the fill operation. However, the RGBQUAD's rgbReserved member is
 only taken into account, if option FI_COLOR_IS_RGBA_COLOR has been specified.

 For 16-bit images, the red-, green- and blue components of the specified color are
 transparently translated into either the 16-bit 555 or 565 representation. This depends
 on the image's actual red- green- and blue masks.

 Special attention must be payed for palletized images. Generally, the RGB color specified
 is looked up in the image's palette. The found palette index is then used to fill the image.
 There are some option flags, that affect this lookup process:

 no option specified       (0x00)   Uses the color, that is nearest to the specified color.
                                    This is the default behavior and should always find a
                                    color in the palette. However, the visual result may
                                    far from what was expected and mainly depends on the
                                    image's palette.

 FI_COLOR_FIND_EQUAL_COLOR (0x02)	Searches the image's palette for the specified color
                                    but only uses the returned palette index, if the specified
                                    color exactly matches the palette entry. Of course,
                                    depending on the image's actual palette entries, this
                                    operation may fail. In this case, the function falls back
                                    to option FI_COLOR_ALPHA_IS_INDEX and uses the RGBQUAD's
                                    rgbReserved member (or its low nibble for 4-bit images
                                    or its least significant bit (LSB) for 1-bit images) as
                                    the palette index used for the fill operation.

 FI_COLOR_ALPHA_IS_INDEX   (0x04)   Does not perform any color lookup from the palette, but
                                    uses the RGBQUAD's alpha channel member rgbReserved as
                                    the palette index to be used for the fill operation.
                                    However, for 4-bit images, only the low nibble of the
                                    rgbReserved member are used and for 1-bit images, only
                                    the least significant bit (LSB) is used.

 This function fails if any of dib and color is NULL.

 @param dib The image to be filled.
 @param color A pointer to the color value to be used for filling the image. The
 memory pointed to by this pointer is always assumed to be at least as large as the
 image's color value, but never smaller than the size of an RGBQUAD structure.
 @param options Options that affect the color search process for palletized images.
 @return Returns TRUE on success, FALSE otherwise. This function fails if any of
 dib and color is NULL.
 */
BOOL DLL_CALLCONV
FreeImage_FillBackground(FIBITMAP *dib, const void *color, int options) {

	if (!FreeImage_HasPixels(dib)) {
		return FALSE;
	}
	
	if (!color) {
		return FALSE;
	}

	// handle FIT_BITMAP images with FreeImage_FillBackground()
	if (FreeImage_GetImageType(dib) == FIT_BITMAP) {
		return FillBackgroundBitmap(dib, (RGBQUAD *)color, options);
	}
	
	// first, construct the first scanline (bottom line)
	unsigned bytespp = (FreeImage_GetBPP(dib) / 8);
	BYTE *src_bits = FreeImage_GetScanLine(dib, 0);
	BYTE *dst_bits = src_bits;
	for (unsigned x = 0; x < FreeImage_GetWidth(dib); x++) {
		memcpy(dst_bits, color, bytespp);
		dst_bits += bytespp;
	}

	// then, copy the first scanline into all following scanlines
	unsigned height = FreeImage_GetHeight(dib);
	unsigned pitch = FreeImage_GetPitch(dib);
	unsigned bytes = FreeImage_GetLine(dib);
	dst_bits = src_bits + pitch;
	for (unsigned y = 1; y < height; y++) {
		memcpy(dst_bits, src_bits, bytes);
		dst_bits += pitch;
	}
	return TRUE;
}
Example #19
0
FIBITMAP* DLL_CALLCONV
FreeImage_ConvertToType(FIBITMAP *src, FREE_IMAGE_TYPE dst_type, BOOL scale_linear) {
	FIBITMAP *dst = NULL;

	if(!FreeImage_HasPixels(src)) return NULL;

	// convert from src_type to dst_type

	const FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(src);

	if(src_type == dst_type) {
		return FreeImage_Clone(src);
	}

	const unsigned src_bpp = FreeImage_GetBPP(src);

	switch(src_type) {
		case FIT_BITMAP:
			switch(dst_type) {
				case FIT_UINT16:
					dst = FreeImage_ConvertToUINT16(src);
					break;
				case FIT_INT16:
					dst = (src_bpp == 8) ? convertByteToShort.convert(src, dst_type) : NULL;
					break;
				case FIT_UINT32:
					dst = (src_bpp == 8) ? convertByteToULong.convert(src, dst_type) : NULL;
					break;
				case FIT_INT32:
					dst = (src_bpp == 8) ? convertByteToLong.convert(src, dst_type) : NULL;
					break;
				case FIT_FLOAT:
					dst = FreeImage_ConvertToFloat(src);
					break;
				case FIT_DOUBLE:
					dst = (src_bpp == 8) ? convertByteToDouble.convert(src, dst_type) : NULL;
					break;
				case FIT_COMPLEX:
					dst = (src_bpp == 8) ? convertByteToComplex.convert(src) : NULL;
					break;
				case FIT_RGB16:
					dst = FreeImage_ConvertToRGB16(src);
					break;
				case FIT_RGBA16:
					dst = FreeImage_ConvertToRGBA16(src);
					break;
				case FIT_RGBF:
					dst = FreeImage_ConvertToRGBF(src);
					break;
				case FIT_RGBAF:
					dst = FreeImage_ConvertToRGBAF(src);
					break;
			}
			break;
		case FIT_UINT16:
			switch(dst_type) {
				case FIT_BITMAP:
					dst = FreeImage_ConvertToStandardType(src, scale_linear);
					break;
				case FIT_INT16:
					break;
				case FIT_UINT32:
					break;
				case FIT_INT32:
					break;
				case FIT_FLOAT:
					dst = FreeImage_ConvertToFloat(src);
					break;
				case FIT_DOUBLE:
					dst = convertUShortToDouble.convert(src, dst_type);
					break;
				case FIT_COMPLEX:
					dst = convertUShortToComplex.convert(src);
					break;
				case FIT_RGB16:
					dst = FreeImage_ConvertToRGB16(src);
					break;
				case FIT_RGBA16:
					dst = FreeImage_ConvertToRGBA16(src);
					break;
				case FIT_RGBF:
					dst = FreeImage_ConvertToRGBF(src);
					break;
				case FIT_RGBAF:
					dst = FreeImage_ConvertToRGBAF(src);
					break;
			}
			break;
		case FIT_INT16:
			switch(dst_type) {
				case FIT_BITMAP:
					dst = FreeImage_ConvertToStandardType(src, scale_linear);
					break;
				case FIT_UINT16:
					break;
				case FIT_UINT32:
					break;
				case FIT_INT32:
					break;
				case FIT_FLOAT:
					dst = convertShortToFloat.convert(src, dst_type);
					break;
				case FIT_DOUBLE:
					dst = convertShortToDouble.convert(src, dst_type);
					break;
				case FIT_COMPLEX:
					dst = convertShortToComplex.convert(src);
					break;
				case FIT_RGB16:
					break;
				case FIT_RGBA16:
					break;
				case FIT_RGBF:
					break;
				case FIT_RGBAF:
					break;
			}
			break;
		case FIT_UINT32:
			switch(dst_type) {
				case FIT_BITMAP:
					dst = FreeImage_ConvertToStandardType(src, scale_linear);
					break;
				case FIT_UINT16:
					break;
				case FIT_INT16:
					break;
				case FIT_INT32:
					break;
				case FIT_FLOAT:
					dst = convertULongToFloat.convert(src, dst_type);
					break;
				case FIT_DOUBLE:
					dst = convertULongToDouble.convert(src, dst_type);
					break;
				case FIT_COMPLEX:
					dst = convertULongToComplex.convert(src);
					break;
				case FIT_RGB16:
					break;
				case FIT_RGBA16:
					break;
				case FIT_RGBF:
					break;
				case FIT_RGBAF:
					break;
			}
			break;
		case FIT_INT32:
			switch(dst_type) {
				case FIT_BITMAP:
					dst = FreeImage_ConvertToStandardType(src, scale_linear);
					break;
				case FIT_UINT16:
					break;
				case FIT_INT16:
					break;
				case FIT_UINT32:
					break;
				case FIT_FLOAT:
					dst = convertLongToFloat.convert(src, dst_type);
					break;
				case FIT_DOUBLE:
					dst = convertLongToDouble.convert(src, dst_type);
					break;
				case FIT_COMPLEX:
					dst = convertLongToComplex.convert(src);
					break;
				case FIT_RGB16:
					break;
				case FIT_RGBA16:
					break;
				case FIT_RGBF:
					break;
				case FIT_RGBAF:
					break;
			}
			break;
		case FIT_FLOAT:
			switch(dst_type) {
				case FIT_BITMAP:
					dst = FreeImage_ConvertToStandardType(src, scale_linear);
					break;
				case FIT_UINT16:
					break;
				case FIT_INT16:
					break;
				case FIT_UINT32:
					break;
				case FIT_INT32:
					break;
				case FIT_DOUBLE:
					dst = convertFloatToDouble.convert(src, dst_type);
					break;
				case FIT_COMPLEX:
					dst = convertFloatToComplex.convert(src);
					break;
				case FIT_RGB16:
					break;
				case FIT_RGBA16:
					break;
				case FIT_RGBF:
					dst = FreeImage_ConvertToRGBF(src);
					break;
				case FIT_RGBAF:
					dst = FreeImage_ConvertToRGBAF(src);
					break;
			}
			break;
		case FIT_DOUBLE:
			switch(dst_type) {
				case FIT_BITMAP:
					dst = FreeImage_ConvertToStandardType(src, scale_linear);
					break;
				case FIT_UINT16:
					break;
				case FIT_INT16:
					break;
				case FIT_UINT32:
					break;
				case FIT_INT32:
					break;
				case FIT_FLOAT:
					break;
				case FIT_COMPLEX:
					dst = convertDoubleToComplex.convert(src);
					break;
				case FIT_RGB16:
					break;
				case FIT_RGBA16:
					break;
				case FIT_RGBF:
					break;
				case FIT_RGBAF:
					break;
			}
			break;
		case FIT_COMPLEX:
			switch(dst_type) {
				case FIT_BITMAP:
					break;
				case FIT_UINT16:
					break;
				case FIT_INT16:
					break;
				case FIT_UINT32:
					break;
				case FIT_INT32:
					break;
				case FIT_FLOAT:
					break;
				case FIT_DOUBLE:
					break;
				case FIT_RGB16:
					break;
				case FIT_RGBA16:
					break;
				case FIT_RGBF:
					break;
				case FIT_RGBAF:
					break;
			}
			break;
		case FIT_RGB16:
			switch(dst_type) {
				case FIT_BITMAP:
					dst = FreeImage_ConvertTo24Bits(src);
					break;
				case FIT_UINT16:
					dst = FreeImage_ConvertToUINT16(src);
					break;
				case FIT_INT16:
					break;
				case FIT_UINT32:
					break;
				case FIT_INT32:
					break;
				case FIT_FLOAT:
					dst = FreeImage_ConvertToFloat(src);
					break;
				case FIT_DOUBLE:
					break;
				case FIT_COMPLEX:
					break;
				case FIT_RGBA16:
					dst = FreeImage_ConvertToRGBA16(src);
					break;
				case FIT_RGBF:
					dst = FreeImage_ConvertToRGBF(src);
					break;
				case FIT_RGBAF:
					dst = FreeImage_ConvertToRGBAF(src);
					break;
			}
			break;
		case FIT_RGBA16:
			switch(dst_type) {
				case FIT_BITMAP:
					dst = FreeImage_ConvertTo32Bits(src);
					break;
				case FIT_UINT16:
					dst = FreeImage_ConvertToUINT16(src);
					break;
				case FIT_INT16:
					break;
				case FIT_UINT32:
					break;
				case FIT_INT32:
					break;
				case FIT_FLOAT:
					dst = FreeImage_ConvertToFloat(src);
					break;
				case FIT_DOUBLE:
					break;
				case FIT_COMPLEX:
					break;
				case FIT_RGB16:
					dst = FreeImage_ConvertToRGB16(src);
					break;
				case FIT_RGBF:
					dst = FreeImage_ConvertToRGBF(src);
					break;
				case FIT_RGBAF:
					dst = FreeImage_ConvertToRGBAF(src);
					break;
			}
			break;
		case FIT_RGBF:
			switch(dst_type) {
				case FIT_BITMAP:
					break;
				case FIT_UINT16:
					break;
				case FIT_INT16:
					break;
				case FIT_UINT32:
					break;
				case FIT_INT32:
					break;
				case FIT_FLOAT:
					dst = FreeImage_ConvertToFloat(src);
					break;
				case FIT_DOUBLE:
					break;
				case FIT_COMPLEX:
					break;
				case FIT_RGB16:
					break;
				case FIT_RGBA16:
					break;
				case FIT_RGBAF:
					dst = FreeImage_ConvertToRGBAF(src);
					break;
			}
			break;
		case FIT_RGBAF:
			switch(dst_type) {
				case FIT_BITMAP:
					break;
				case FIT_UINT16:
					break;
				case FIT_INT16:
					break;
				case FIT_UINT32:
					break;
				case FIT_INT32:
					break;
				case FIT_FLOAT:
					dst = FreeImage_ConvertToFloat(src);
					break;
				case FIT_DOUBLE:
					break;
				case FIT_COMPLEX:
					break;
				case FIT_RGB16:
					break;
				case FIT_RGBA16:
					break;
				case FIT_RGBF:
					dst = FreeImage_ConvertToRGBF(src);
					break;
			}
			break;
	}

	if(NULL == dst) {
		FreeImage_OutputMessageProc(FIF_UNKNOWN, "FREE_IMAGE_TYPE: Unable to convert from type %d to type %d.\n No such conversion exists.", src_type, dst_type);
	}

	return dst;
}
Example #20
0
FIBITMAP * DLL_CALLCONV
FreeImage_ConvertToRGB16(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:
		{
			// convert to 24-bit if needed
			if((FreeImage_GetBPP(dib) == 24) || (FreeImage_GetBPP(dib) == 32)) {
				src = dib;
			} else {
				src = FreeImage_ConvertTo24Bits(dib);
				if(!src) return NULL;
			}
			break;
		}
		case FIT_UINT16:
			// allow conversion from unsigned 16-bit
			src = dib;
			break;
		case FIT_RGB16:
			// RGB16 type : clone the src
			return FreeImage_Clone(dib);
			break;
		case FIT_RGBA16:
			// allow conversion from 64-bit RGBA (ignore the alpha channel)
			src = dib;
			break;
		default:
			return NULL;
	}

	// allocate dst image

	const unsigned width = FreeImage_GetWidth(src);
	const unsigned height = FreeImage_GetHeight(src);

	dst = FreeImage_AllocateT(FIT_RGB16, 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 RGB16

	switch(src_type) {
		case FIT_BITMAP:
		{
			// Calculate the number of bytes per pixel (1 for 8-bit, 3 for 24-bit or 4 for 32-bit)
			const unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);

			for(unsigned y = 0; y < height; y++) {
				const BYTE *src_bits = (BYTE*)FreeImage_GetScanLine(src, y);
				FIRGB16 *dst_bits = (FIRGB16*)FreeImage_GetScanLine(dst, y);
				for(unsigned x = 0; x < width; x++) {
					dst_bits[x].red   = src_bits[FI_RGBA_RED] << 8;
					dst_bits[x].green = src_bits[FI_RGBA_GREEN] << 8;
					dst_bits[x].blue  = src_bits[FI_RGBA_BLUE] << 8;
					src_bits += bytespp;
				}
			}
		}
		break;

		case FIT_UINT16:
		{
			for(unsigned y = 0; y < height; y++) {
				const WORD *src_bits = (WORD*)FreeImage_GetScanLine(src, y);
				FIRGB16 *dst_bits = (FIRGB16*)FreeImage_GetScanLine(dst, y);
				for(unsigned x = 0; x < width; x++) {
					// convert by copying greyscale channel to each R, G, B channels
					dst_bits[x].red   = src_bits[x];
					dst_bits[x].green = src_bits[x];
					dst_bits[x].blue  = src_bits[x];
				}
			}
		}
		break;

		case FIT_RGBA16:
		{
			for(unsigned y = 0; y < height; y++) {
				const FIRGBA16 *src_bits = (FIRGBA16*)FreeImage_GetScanLine(src, y);
				FIRGB16 *dst_bits = (FIRGB16*)FreeImage_GetScanLine(dst, y);
				for(unsigned x = 0; x < width; x++) {
					// convert and skip alpha channel
					dst_bits[x].red   = src_bits[x].red;
					dst_bits[x].green = src_bits[x].green;
					dst_bits[x].blue  = src_bits[x].blue;
				}
			}
		}
		break;

		default:
			break;
	}

	if(src != dib) {
		FreeImage_Unload(src);
	}

	return dst;
}
Example #21
0
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;
}
Example #22
0
/**
@brief Composite a foreground image against a background color or a background image.

The equation for computing a composited sample value is:<br>
output = alpha * foreground + (1-alpha) * background<br>
where alpha and the input and output sample values are expressed as fractions in the range 0 to 1. 
For colour images, the computation is done separately for R, G, and B samples.

@param fg Foreground image
@param useFileBkg If TRUE and a file background is present, use it as the background color
@param appBkColor If not equal to NULL, and useFileBkg is FALSE, use this color as the background color
@param bg If not equal to NULL and useFileBkg is FALSE and appBkColor is NULL, use this as the background image
@return Returns the composite image if successful, returns NULL otherwise
@see FreeImage_IsTransparent, FreeImage_HasBackgroundColor
*/
FIBITMAP * DLL_CALLCONV
FreeImage_Composite(FIBITMAP *fg, BOOL useFileBkg, RGBQUAD *appBkColor, FIBITMAP *bg) {
	if(!FreeImage_HasPixels(fg)) return NULL;

	int width  = FreeImage_GetWidth(fg);
	int height = FreeImage_GetHeight(fg);
	int bpp    = FreeImage_GetBPP(fg);

	if((bpp != 8) && (bpp != 32))
		return NULL;

	if(bg) {
		int bg_width  = FreeImage_GetWidth(bg);
		int bg_height = FreeImage_GetHeight(bg);
		int bg_bpp    = FreeImage_GetBPP(bg);
		if((bg_width != width) || (bg_height != height) || (bg_bpp != 24))
			return NULL;
	}

	int bytespp = (bpp == 8) ? 1 : 4;

	
	int x, y, c;
	BYTE alpha = 0, not_alpha;
	BYTE index;
	RGBQUAD fgc;	// foreground color
	RGBQUAD bkc;	// background color

	memset(&fgc, 0, sizeof(RGBQUAD));
	memset(&bkc, 0, sizeof(RGBQUAD));

	// allocate the composite image
	FIBITMAP *composite = FreeImage_Allocate(width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
	if(!composite) return NULL;

	// get the palette
	RGBQUAD *pal = FreeImage_GetPalette(fg);

	// retrieve the alpha table from the foreground image
	BOOL bIsTransparent = FreeImage_IsTransparent(fg);
	BYTE *trns = FreeImage_GetTransparencyTable(fg);

	// retrieve the background color from the foreground image
	BOOL bHasBkColor = FALSE;

	if(useFileBkg && FreeImage_HasBackgroundColor(fg)) {
		FreeImage_GetBackgroundColor(fg, &bkc);
		bHasBkColor = TRUE;
	} else {
		// no file background color
		// use application background color ?
		if(appBkColor) {
			memcpy(&bkc, appBkColor, sizeof(RGBQUAD));
			bHasBkColor = TRUE;
		}
		// use background image ?
		else if(bg) {
			bHasBkColor = FALSE;
		}
	}

	for(y = 0; y < height; y++) {
		// foreground
		BYTE *fg_bits = FreeImage_GetScanLine(fg, y);
		// background
		BYTE *bg_bits = FreeImage_GetScanLine(bg, y);
		// composite image
		BYTE *cp_bits = FreeImage_GetScanLine(composite, y);

		for(x = 0; x < width; x++) {

			// foreground color + alpha

			if(bpp == 8) {
				// get the foreground color
				index = fg_bits[0];
				memcpy(&fgc, &pal[index], sizeof(RGBQUAD));
				// get the alpha
				if(bIsTransparent) {
					alpha = trns[index];
				} else {
					alpha = 255;
				}
			}
			else if(bpp == 32) {
				// get the foreground color
				fgc.rgbBlue  = fg_bits[FI_RGBA_BLUE];
				fgc.rgbGreen = fg_bits[FI_RGBA_GREEN];
				fgc.rgbRed   = fg_bits[FI_RGBA_RED];
				// get the alpha
				alpha = fg_bits[FI_RGBA_ALPHA];
			}

			// background color

			if(!bHasBkColor) {
				if(bg) {
					// get the background color from the background image
					bkc.rgbBlue  = bg_bits[FI_RGBA_BLUE];
					bkc.rgbGreen = bg_bits[FI_RGBA_GREEN];
					bkc.rgbRed   = bg_bits[FI_RGBA_RED];
				}
				else {
					// use a checkerboard pattern
					c = (((y & 0x8) == 0) ^ ((x & 0x8) == 0)) * 192;
					c = c ? c : 255;
					bkc.rgbBlue  = (BYTE)c;
					bkc.rgbGreen = (BYTE)c;
					bkc.rgbRed   = (BYTE)c;
				}
			}

			// composition

			if(alpha == 0) {
				// output = background
				cp_bits[FI_RGBA_BLUE] = bkc.rgbBlue;
				cp_bits[FI_RGBA_GREEN] = bkc.rgbGreen;
				cp_bits[FI_RGBA_RED] = bkc.rgbRed;
			}
			else if(alpha == 255) {
				// output = foreground
				cp_bits[FI_RGBA_BLUE] = fgc.rgbBlue;
				cp_bits[FI_RGBA_GREEN] = fgc.rgbGreen;
				cp_bits[FI_RGBA_RED] = fgc.rgbRed;
			}
			else {
				// output = alpha * foreground + (1-alpha) * background
				not_alpha = (BYTE)~alpha;
				cp_bits[FI_RGBA_BLUE] = (BYTE)((alpha * (WORD)fgc.rgbBlue  + not_alpha * (WORD)bkc.rgbBlue) >> 8);
				cp_bits[FI_RGBA_GREEN] = (BYTE)((alpha * (WORD)fgc.rgbGreen + not_alpha * (WORD)bkc.rgbGreen) >> 8);
				cp_bits[FI_RGBA_RED] = (BYTE)((alpha * (WORD)fgc.rgbRed   + not_alpha * (WORD)bkc.rgbRed) >> 8);
			}

			fg_bits += bytespp;
			bg_bits += 3;
			cp_bits += 3;
		}
	}

	// copy metadata from src to dst
	FreeImage_CloneMetadata(composite, fg);
	
	return composite;	
}
Example #23
0
/**
Apply the Gradient Domain High Dynamic Range Compression to a RGBF image and convert to 24-bit RGB
@param dib Input RGBF / RGB16 image
@param color_saturation Color saturation (s parameter in the paper) in [0.4..0.6]
@param attenuation Atenuation factor (beta parameter in the paper) in [0.8..0.9]
@return Returns a 24-bit RGB image if successful, returns NULL otherwise
*/
FIBITMAP* DLL_CALLCONV 
FreeImage_TmoFattal02(FIBITMAP *dib, double color_saturation, double attenuation) {	
	const float alpha = 0.1F;									// parameter alpha = 0.1
	const float beta = (float)MAX(0.8, MIN(0.9, attenuation));	// parameter beta = [0.8..0.9]
	const float s = (float)MAX(0.4, MIN(0.6, color_saturation));// exponent s controls color saturation = [0.4..0.6]

	FIBITMAP *src = NULL;
	FIBITMAP *Yin = NULL;
	FIBITMAP *Yout = NULL;
	FIBITMAP *dst = NULL;

	if(!FreeImage_HasPixels(dib)) return NULL;

	try {

		// convert to RGBF
		src = FreeImage_ConvertToRGBF(dib);
		if(!src) throw(1);

		// get the luminance channel
		Yin = ConvertRGBFToY(src);
		if(!Yin) throw(1);

		// perform the tone mapping
		Yout = tmoFattal02(Yin, alpha, beta);
		if(!Yout) throw(1);

		// clip low and high values and normalize to [0..1]
		//NormalizeY(Yout, 0.001F, 0.995F);
		NormalizeY(Yout, 0, 1);

		// compress the dynamic range

		const unsigned width = FreeImage_GetWidth(src);
		const unsigned height = FreeImage_GetHeight(src);

		const unsigned rgb_pitch = FreeImage_GetPitch(src);
		const unsigned y_pitch = FreeImage_GetPitch(Yin);

		BYTE *bits      = (BYTE*)FreeImage_GetBits(src);
		BYTE *bits_yin  = (BYTE*)FreeImage_GetBits(Yin);
		BYTE *bits_yout = (BYTE*)FreeImage_GetBits(Yout);

		for(unsigned y = 0; y < height; y++) {
			float *Lin = (float*)bits_yin;
			float *Lout = (float*)bits_yout;
			float *color = (float*)bits;
			for(unsigned x = 0; x < width; x++) {
				for(unsigned c = 0; c < 3; c++) {
					*color = (Lin[x] > 0) ? pow(*color/Lin[x], s) * Lout[x] : 0;
					color++;
				}
			}
			bits += rgb_pitch;
			bits_yin += y_pitch;
			bits_yout += y_pitch;
		}

		// not needed anymore
		FreeImage_Unload(Yin);  Yin  = NULL;
		FreeImage_Unload(Yout); Yout = NULL;

		// clamp image highest values to display white, then convert to 24-bit RGB
		dst = ClampConvertRGBFTo24(src);

		// clean-up and return
		FreeImage_Unload(src); src = NULL;

		// copy metadata from src to dst
		FreeImage_CloneMetadata(dst, dib);
		
		return dst;

	} catch(int) {
		if(src) FreeImage_Unload(src);
		if(Yin) FreeImage_Unload(Yin);
		if(Yout) FreeImage_Unload(Yout);
		return NULL;
	}
}
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;
}
Example #25
0
FIBITMAP * DLL_CALLCONV
FreeImage_Clone(FIBITMAP *dib) {
	if(!dib) {
		return NULL;
	}

	FREE_IMAGE_TYPE type = FreeImage_GetImageType(dib);
	unsigned width	= FreeImage_GetWidth(dib);
	unsigned height	= FreeImage_GetHeight(dib);
	unsigned bpp	= FreeImage_GetBPP(dib);

	const BYTE *ext_bits = ((FREEIMAGEHEADER *)dib->data)->external_bits;
	
	// check for pixel availability ...
	BOOL header_only = FreeImage_HasPixels(dib) ? FALSE : TRUE;

	// check whether this image has masks defined ...
	BOOL need_masks = (bpp == 16 && type == FIT_BITMAP) ? TRUE : FALSE;

	// allocate a new dib
	FIBITMAP *new_dib = FreeImage_AllocateHeaderT(header_only, type, width, height, bpp,
			FreeImage_GetRedMask(dib), FreeImage_GetGreenMask(dib), FreeImage_GetBlueMask(dib));

	if (new_dib) {
		// save ICC profile links
		FIICCPROFILE *src_iccProfile = FreeImage_GetICCProfile(dib);
		FIICCPROFILE *dst_iccProfile = FreeImage_GetICCProfile(new_dib);

		// save metadata links
		METADATAMAP *src_metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
		METADATAMAP *dst_metadata = ((FREEIMAGEHEADER *)new_dib->data)->metadata;

		// calculate the size of the src image
		// align the palette and the pixels on a FIBITMAP_ALIGNMENT bytes alignment boundary
		// palette is aligned on a 16 bytes boundary
		// pixels are aligned on a 16 bytes boundary
		
		// when using a user provided pixel buffer, force a 'header only' calculation		

		size_t dib_size = FreeImage_GetInternalImageSize(header_only || ext_bits, width, height, bpp, need_masks);

		// copy the bitmap + internal pointers (remember to restore new_dib internal pointers later)
		memcpy(new_dib->data, dib->data, dib_size);

		// reset ICC profile link for new_dib
		memset(dst_iccProfile, 0, sizeof(FIICCPROFILE));

		// restore metadata link for new_dib
		((FREEIMAGEHEADER *)new_dib->data)->metadata = dst_metadata;

		// reset thumbnail link for new_dib
		((FREEIMAGEHEADER *)new_dib->data)->thumbnail = NULL;

		// copy possible ICC profile
		FreeImage_CreateICCProfile(new_dib, src_iccProfile->data, src_iccProfile->size);
		dst_iccProfile->flags = src_iccProfile->flags;

		// copy metadata models
		for(METADATAMAP::iterator i = (*src_metadata).begin(); i != (*src_metadata).end(); i++) {
			int model = (*i).first;
			TAGMAP *src_tagmap = (*i).second;

			if(src_tagmap) {
				// create a metadata model
				TAGMAP *dst_tagmap = new(std::nothrow) TAGMAP();

				if(dst_tagmap) {
					// fill the model
					for(TAGMAP::iterator j = src_tagmap->begin(); j != src_tagmap->end(); j++) {
						std::string dst_key = (*j).first;
						FITAG *dst_tag = FreeImage_CloneTag( (*j).second );

						// assign key and tag value
						(*dst_tagmap)[dst_key] = dst_tag;
					}

					// assign model and tagmap
					(*dst_metadata)[model] = dst_tagmap;
				}
			}
		}

		// copy the thumbnail
		FreeImage_SetThumbnail(new_dib, FreeImage_GetThumbnail(dib));

		// copy user provided pixel buffer (if any)
		if(ext_bits) {
			const unsigned pitch = FreeImage_GetPitch(dib);
			const unsigned linesize = FreeImage_GetLine(dib);
			for(unsigned y = 0; y < height; y++) {
				memcpy(FreeImage_GetScanLine(new_dib, y), ext_bits, linesize);
				ext_bits += pitch;
			}
		}

		return new_dib;
	}

	return NULL;
}
Example #26
0
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;
}
Example #27
0
FIBITMAP * DLL_CALLCONV
FreeImage_RescaleRect(FIBITMAP *src, int dst_width, int dst_height, int src_left, int src_top, int src_right, int src_bottom, FREE_IMAGE_FILTER filter, unsigned flags) {
	FIBITMAP *dst = NULL;

	const int src_width = FreeImage_GetWidth(src);
	const int src_height = FreeImage_GetHeight(src);

	if (!FreeImage_HasPixels(src) || (dst_width <= 0) || (dst_height <= 0) || (src_width <= 0) || (src_height <= 0)) {
		return NULL;
	}

	// normalize the rectangle
	if (src_right < src_left) {
		INPLACESWAP(src_left, src_right);
	}
	if (src_bottom < src_top) {
		INPLACESWAP(src_top, src_bottom);
	}

	// check the size of the sub image
	if((src_left < 0) || (src_right > src_width) || (src_top < 0) || (src_bottom > src_height)) {
		return NULL;
	}

	// select the filter
	CGenericFilter *pFilter = NULL;
	switch (filter) {
		case FILTER_BOX:
			pFilter = new(std::nothrow) CBoxFilter();
			break;
		case FILTER_BICUBIC:
			pFilter = new(std::nothrow) CBicubicFilter();
			break;
		case FILTER_BILINEAR:
			pFilter = new(std::nothrow) CBilinearFilter();
			break;
		case FILTER_BSPLINE:
			pFilter = new(std::nothrow) CBSplineFilter();
			break;
		case FILTER_CATMULLROM:
			pFilter = new(std::nothrow) CCatmullRomFilter();
			break;
		case FILTER_LANCZOS3:
			pFilter = new(std::nothrow) CLanczos3Filter();
			break;
	}

	if (!pFilter) {
		return NULL;
	}

	CResizeEngine Engine(pFilter);

	dst = Engine.scale(src, dst_width, dst_height, src_left, src_top,
			src_right - src_left, src_bottom - src_top, flags);

	delete pFilter;

	if ((flags & FI_RESCALE_OMIT_METADATA) != FI_RESCALE_OMIT_METADATA) {
		// copy metadata from src to dst
		FreeImage_CloneMetadata(dst, src);
	}

	return dst;
}
Example #28
0
FREE_IMAGE_COLOR_TYPE DLL_CALLCONV
FreeImage_GetColorType(FIBITMAP *dib) {
	RGBQUAD *rgb;

	const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);

	// special bitmap type
	if(image_type != FIT_BITMAP) {
		switch(image_type) {
			case FIT_UINT16:
			{
				// 16-bit greyscale TIF can be either FIC_MINISBLACK (the most common case) or FIC_MINISWHITE
				// you can check this using EXIF_MAIN metadata
				FITAG *photometricTag = NULL;
				if(FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, "PhotometricInterpretation", &photometricTag)) {
					const short *value = (short*)FreeImage_GetTagValue(photometricTag);
					// PHOTOMETRIC_MINISWHITE = 0 => min value is white
					// PHOTOMETRIC_MINISBLACK = 1 => min value is black
					return (*value == 0) ? FIC_MINISWHITE : FIC_MINISBLACK;
				}
				return FIC_MINISBLACK;
			}
			break;
			case FIT_RGB16:
			case FIT_RGBF:
				return FIC_RGB;
			case FIT_RGBA16:
			case FIT_RGBAF:
				return FIC_RGBALPHA;
		}

		return FIC_MINISBLACK;
	}

	// standard image type
	switch (FreeImage_GetBPP(dib)) {
		case 1:
		{
			rgb = FreeImage_GetPalette(dib);

			if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0)) {
				rgb++;

				if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255)) {
					return FIC_MINISBLACK;
				}
			}

			if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255)) {
				rgb++;

				if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0)) {
					return FIC_MINISWHITE;
				}
			}

			return FIC_PALETTE;
		}

		case 4:
		case 8:	// Check if the DIB has a color or a greyscale palette
		{
			int ncolors = FreeImage_GetColorsUsed(dib);
		    int minisblack = 1;
			rgb = FreeImage_GetPalette(dib);

			for (int i = 0; i < ncolors; i++) {
				if ((rgb->rgbRed != rgb->rgbGreen) || (rgb->rgbRed != rgb->rgbBlue)) {
					return FIC_PALETTE;
				}

				// The DIB has a color palette if the greyscale isn't a linear ramp
				// Take care of reversed grey images
				if (rgb->rgbRed != i) {
					if ((ncolors-i-1) != rgb->rgbRed) {
						return FIC_PALETTE;
					} else {
						minisblack = 0;
					}
				}

				rgb++;
			}

			return minisblack ? FIC_MINISBLACK : FIC_MINISWHITE;
		}

		case 16:
		case 24:
			return FIC_RGB;

		case 32:
		{
			if (FreeImage_GetICCProfile(dib)->flags & FIICC_COLOR_IS_CMYK) {
				return FIC_CMYK;
			}

			if( FreeImage_HasPixels(dib) ) {
				// check for fully opaque alpha layer
				for (unsigned y = 0; y < FreeImage_GetHeight(dib); y++) {
					rgb = (RGBQUAD *)FreeImage_GetScanLine(dib, y);

					for (unsigned x = 0; x < FreeImage_GetWidth(dib); x++) {
						if (rgb[x].rgbReserved != 0xFF) {
							return FIC_RGBALPHA;
						}
					}
				}
				return FIC_RGB;
			}

			return FIC_RGBALPHA;
		}
				
		default :
			return FIC_MINISBLACK;
	}
}
Example #29
0
FIBITMAP * DLL_CALLCONV
FreeImage_Clone(FIBITMAP *dib) {
	if(!dib) return NULL;

	unsigned width  = FreeImage_GetWidth(dib);
	unsigned height = FreeImage_GetHeight(dib);
	unsigned bpp    = FreeImage_GetBPP(dib);
	
	// check for pixel availability ...
	BOOL header_only = FreeImage_HasPixels(dib) ? FALSE : TRUE;

	// allocate a new dib
	FIBITMAP *new_dib = FreeImage_AllocateHeaderT(header_only, FreeImage_GetImageType(dib), width, height, bpp, 
			FreeImage_GetRedMask(dib), FreeImage_GetGreenMask(dib), FreeImage_GetBlueMask(dib));

	if (new_dib) {
		// save ICC profile links
		FIICCPROFILE *src_iccProfile = FreeImage_GetICCProfile(dib);
		FIICCPROFILE *dst_iccProfile = FreeImage_GetICCProfile(new_dib);

		// save metadata links
		METADATAMAP *src_metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
		METADATAMAP *dst_metadata = ((FREEIMAGEHEADER *)new_dib->data)->metadata;

		// calculate the size of a FreeImage image
		// align the palette and the pixels on a FIBITMAP_ALIGNMENT bytes alignment boundary
		// palette is aligned on a 16 bytes boundary
		// pixels are aligned on a 16 bytes boundary

		size_t dib_size = FreeImage_GetImageSizeHeader(header_only, width, height, bpp); 

		// copy the bitmap + internal pointers (remember to restore new_dib internal pointers later)
		memcpy(new_dib->data, dib->data, dib_size);

		// reset ICC profile link for new_dib
		memset(dst_iccProfile, 0, sizeof(FIICCPROFILE));

		// restore metadata link for new_dib
		((FREEIMAGEHEADER *)new_dib->data)->metadata = dst_metadata;

		// reset thumbnail link for new_dib
		((FREEIMAGEHEADER *)new_dib->data)->thumbnail = NULL;

		// copy possible ICC profile
		FreeImage_CreateICCProfile(new_dib, src_iccProfile->data, src_iccProfile->size);
		dst_iccProfile->flags = src_iccProfile->flags;

		// copy metadata models
		for(METADATAMAP::iterator i = (*src_metadata).begin(); i != (*src_metadata).end(); i++) {
			int model = (*i).first;
			TAGMAP *src_tagmap = (*i).second;

			if(src_tagmap) {
				// create a metadata model
				TAGMAP *dst_tagmap = new(std::nothrow) TAGMAP();

				if(dst_tagmap) {
					// fill the model
					for(TAGMAP::iterator j = src_tagmap->begin(); j != src_tagmap->end(); j++) {
						std::string dst_key = (*j).first;
						FITAG *dst_tag = FreeImage_CloneTag( (*j).second );

						// assign key and tag value
						(*dst_tagmap)[dst_key] = dst_tag;
					}

					// assign model and tagmap
					(*dst_metadata)[model] = dst_tagmap;
				}
			}
		}

		// copy the thumbnail
		FreeImage_SetThumbnail(new_dib, FreeImage_GetThumbnail(dib));

		return new_dib;
	}

	return NULL;
}
Example #30
0
FIBITMAP * DLL_CALLCONV
FreeImage_ConvertToUINT16(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:
		{
			// convert to greyscale if needed
			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:
			// UINT16 type : clone the src
			return FreeImage_Clone(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;
		default:
			return NULL;
	}

	// allocate dst image

	const unsigned width = FreeImage_GetWidth(src);
	const unsigned height = FreeImage_GetHeight(src);

	dst = FreeImage_AllocateT(FIT_UINT16, width, height);
	if(!dst) return NULL;

	// copy metadata from src to dst
	FreeImage_CloneMetadata(dst, src);

	// convert from src type to UINT16

	switch(src_type) {
		case FIT_BITMAP:
		{
			for(unsigned y = 0; y < height; y++) {
				const BYTE *src_bits = (BYTE*)FreeImage_GetScanLine(src, y);
				WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y);
				for(unsigned x = 0; x < width; x++) {
					dst_bits[x] = src_bits[x] << 8;
				}
			}
		}
		break;

		case FIT_RGB16:
		{
			for(unsigned y = 0; y < height; y++) {
				const FIRGB16 *src_bits = (FIRGB16*)FreeImage_GetScanLine(src, y);
				WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y);
				for(unsigned x = 0; x < width; x++) {
					// convert to grey
					dst_bits[x] = (WORD)LUMA_REC709(src_bits[x].red, src_bits[x].green, src_bits[x].blue);
				}
			}
		}
		break;

		case FIT_RGBA16:
		{
			for(unsigned y = 0; y < height; y++) {
				const FIRGBA16 *src_bits = (FIRGBA16*)FreeImage_GetScanLine(src, y);
				WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y);
				for(unsigned x = 0; x < width; x++) {
					// convert to grey
					dst_bits[x] = (WORD)LUMA_REC709(src_bits[x].red, src_bits[x].green, src_bits[x].blue);
				}
			}
		}
		break;

		default:
			break;
	}

	if(src != dib) {
		FreeImage_Unload(src);
	}

	return dst;
}