Пример #1
0
BOOL fipImage::setSize(FREE_IMAGE_TYPE image_type, WORD width, WORD height, WORD bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) {
	if(_dib) {
		FreeImage_Unload(_dib);
	}
	if((_dib = FreeImage_AllocateT(image_type, width, height, bpp, red_mask, green_mask, blue_mask)) == NULL)
		return FALSE;

	if(image_type == FIT_BITMAP) {
		// Create palette if needed
		switch(bpp)	{
			case 1:
			case 4:
			case 8:
				RGBQUAD *pal = FreeImage_GetPalette(_dib);
				for(unsigned i = 0; i < FreeImage_GetColorsUsed(_dib); i++) {
					pal[i].rgbRed = i;
					pal[i].rgbGreen = i;
					pal[i].rgbBlue = i;
				}
				break;
		}
	}

	_bHasChanged = TRUE;

	return TRUE;
}
Пример #2
0
BOOL DLL_CALLCONV
FreeImage_GetBackgroundColor(FIBITMAP *dib, RGBQUAD *bkcolor) {
	if(dib && bkcolor) {
		if(FreeImage_HasBackgroundColor(dib)) {
			// get the background color
			RGBQUAD *bkgnd_color = &((FREEIMAGEHEADER *)dib->data)->bkgnd_color;
			memcpy(bkcolor, bkgnd_color, sizeof(RGBQUAD));
			// get the background index
			if(FreeImage_GetBPP(dib) == 8) {
				RGBQUAD *pal = FreeImage_GetPalette(dib);
				for(unsigned i = 0; i < FreeImage_GetColorsUsed(dib); i++) {
					if(bkgnd_color->rgbRed == pal[i].rgbRed) {
						if(bkgnd_color->rgbGreen == pal[i].rgbGreen) {
							if(bkgnd_color->rgbBlue == pal[i].rgbBlue) {
								bkcolor->rgbReserved = i;
								return TRUE;
							}
						}
					}
				}
			}

			bkcolor->rgbReserved = 0;

			return TRUE;
		}
	}

	return FALSE;
}
Пример #3
0
	bool readImage(SImage& image, MemChunk& data, int index)
	{
		// Get image info
		SImage::info_t info;
		FIBITMAP*      bm = getFIInfo(data, info);

		// Check it created/read ok
		if (!bm)
		{
			Global::error = "Unable to read image data (unsupported format?)";
			return false;
		}

		// Get image palette if it exists
		RGBQUAD* bm_pal = FreeImage_GetPalette(bm);
		Palette  palette;
		if (bm_pal)
		{
			int a = 0;
			int b = FreeImage_GetColorsUsed(bm);
			if (b > 256)
				b = 256;
			for (; a < b; a++)
				palette.setColour(a, rgba_t(bm_pal[a].rgbRed, bm_pal[a].rgbGreen, bm_pal[a].rgbBlue, 255));
		}

		// Create image
		if (info.has_palette)
			image.create(info, &palette);
		else
			image.create(info);
		uint8_t* img_data = imageData(image);

		// Convert to 32bpp & flip vertically
		FIBITMAP* rgba = FreeImage_ConvertTo32Bits(bm);
		if (!rgba)
		{
			LOG_MESSAGE(1, "FreeImage_ConvertTo32Bits failed for image data");
			Global::error = "Error reading PNG data";
			return false;
		}
		FreeImage_FlipVertical(rgba);

		// Load raw RGBA data
		uint8_t* bits_rgba = FreeImage_GetBits(rgba);
		int      c         = 0;
		for (int a = 0; a < info.width * info.height; a++)
		{
			img_data[c++] = bits_rgba[a * 4 + 2]; // Red
			img_data[c++] = bits_rgba[a * 4 + 1]; // Green
			img_data[c++] = bits_rgba[a * 4];     // Blue
			img_data[c++] = bits_rgba[a * 4 + 3]; // Alpha
		}

		// Free memory
		FreeImage_Unload(rgba);
		FreeImage_Unload(bm);

		return true;
	}
Пример #4
0
/** @brief Inverts each pixel data.

@param src Input image to be processed.
@return Returns TRUE if successful, FALSE otherwise.
*/
BOOL DLL_CALLCONV 
FreeImage_Invert(FIBITMAP *src) {
	unsigned i, x, y, k;
	BYTE *bits;

	if (!src) return FALSE;

	int bpp = FreeImage_GetBPP(src);
	
	switch(bpp) {
        case 1 :
		case 4 :
		case 8 :
		{
			// if the dib has a colormap, just invert it
			// else, keep the linear grayscale

			if (FreeImage_GetColorType(src) == FIC_PALETTE) {
				RGBQUAD *pal = FreeImage_GetPalette(src);

				for(i = 0; i < FreeImage_GetColorsUsed(src); i++) {
					pal[i].rgbRed	= 255 - pal[i].rgbRed;
					pal[i].rgbGreen = 255 - pal[i].rgbGreen;
					pal[i].rgbBlue	= 255 - pal[i].rgbBlue;
				}
			} else {
				for(y = 0; y < FreeImage_GetHeight(src); y++) {
					bits = FreeImage_GetScanLine(src, y);

					for (x = 0; x < FreeImage_GetLine(src); x++) {
						bits[x] = ~bits[x];
					}
				}
			}

			break;
		}		

		case 24 :
		case 32 :
		{
			unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);

			for(y = 0; y < FreeImage_GetHeight(src); y++) {
				bits =  FreeImage_GetScanLine(src, y);
				for(x = 0; x < FreeImage_GetWidth(src); x++) {
					for(k = 0; k < bytespp; k++) {
						bits[k] = ~bits[k];
					}
					bits += bytespp;
				}
			}

			break;
		}

	}
	return TRUE;
}
Пример #5
0
HANDLE fipWinImage::copyToHandle() const {
	HANDLE hMem = NULL;

	if(_dib) {

		// Get equivalent DIB size
		long dib_size = sizeof(BITMAPINFOHEADER);
		dib_size += FreeImage_GetColorsUsed(_dib) * sizeof(RGBQUAD);
		dib_size += FreeImage_GetPitch(_dib) * FreeImage_GetHeight(_dib);

		// Allocate a DIB
		hMem = GlobalAlloc(GHND, dib_size);
		BYTE *dib = (BYTE*)GlobalLock(hMem);

		memset(dib, 0, dib_size);

		BYTE *p_dib = (BYTE*)dib;

		// Copy the BITMAPINFOHEADER

		BITMAPINFOHEADER *bih = FreeImage_GetInfoHeader(_dib);
		memcpy(p_dib, bih, sizeof(BITMAPINFOHEADER));
		if(FreeImage_GetImageType(_dib) != FIT_BITMAP) {
			// this hack is used to store the bitmap type in the biCompression member of the BITMAPINFOHEADER
			SET_FREEIMAGE_MARKER((BITMAPINFOHEADER*)p_dib, _dib);
		}
		p_dib += sizeof(BITMAPINFOHEADER);

		// Copy the palette

		RGBQUAD *pal = FreeImage_GetPalette(_dib);
		memcpy(p_dib, pal, FreeImage_GetColorsUsed(_dib) * sizeof(RGBQUAD));
		p_dib += FreeImage_GetColorsUsed(_dib) * sizeof(RGBQUAD);

		// Copy the bitmap

		BYTE *bits = FreeImage_GetBits(_dib);
		memcpy(p_dib, bits, FreeImage_GetPitch(_dib) * FreeImage_GetHeight(_dib));

		GlobalUnlock(hMem);
	}

	return hMem;
}
Пример #6
0
const QVector<QRgb> ImageLoaderFreeImage::colorTable() const
{
    QVector<QRgb> result;

    const RGBQUAD* const palette = FreeImage_GetPalette(m_bitmap);
    if (palette) {
        const int count = FreeImage_GetColorsUsed(m_bitmap);
        result.resize(count);
        for (int i = 0; i < count; i++)
            result.replace(i, qRgb(palette[i].rgbRed, palette[i].rgbGreen, palette[i].rgbBlue));
    }

    return result;
}
Пример #7
0
/** @brief Sets the index of the palette entry to be used as transparent color
 for the image specified. Does nothing on high color images. 
 
 This method sets the index of the palette entry to be used as single transparent
 color for the image specified. This works on palletised images only and does
 nothing for high color images.
 
 Although it is possible for palletised images to have more than one transparent
 color, this method sets the palette entry specified as the single transparent
 color for the image. All other colors will be set to be non-transparent by this
 method.
 
 As with FreeImage_SetTransparencyTable(), this method also sets the image's
 transparency property to TRUE (as it is set and obtained by
 FreeImage_SetTransparent() and FreeImage_IsTransparent() respectively) for
 palletised images.
 
 @param dib Input image, whose transparent color is to be set.
 @param index The index of the palette entry to be set as transparent color.
 */
void DLL_CALLCONV
FreeImage_SetTransparentIndex(FIBITMAP *dib, int index) {
	if (dib) {
		int count = FreeImage_GetColorsUsed(dib);
		if (count) {
			BYTE *new_tt = (BYTE *)malloc(count * sizeof(BYTE));
			memset(new_tt, 0xFF, count);
			if ((index >= 0) && (index < count)) {
				new_tt[index] = 0x00;
			}
			FreeImage_SetTransparencyTable(dib, new_tt, count);
			free(new_tt);
		}
	}
}
Пример #8
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;
}
Пример #9
0
BOOL fipWinImage::copyFromBitmap(HBITMAP hbmp) {
	if(hbmp) { 
		int Success;
        BITMAP bm;
		// Get informations about the bitmap
        GetObject(hbmp, sizeof(BITMAP), (LPSTR) &bm);
		// Create the image
        setSize(FIT_BITMAP, (WORD)bm.bmWidth, (WORD)bm.bmHeight, (WORD)bm.bmBitsPixel);

		// The GetDIBits function clears the biClrUsed and biClrImportant BITMAPINFO members (dont't know why) 
		// So we save these infos below. This is needed for palettized images only. 
		int nColors = FreeImage_GetColorsUsed(_dib);

		// Create a device context for the bitmap
        HDC dc = GetDC(NULL);
		// Copy the pixels
		Success = GetDIBits(dc,								// handle to DC
								hbmp,						// handle to bitmap
								0,							// first scan line to set
								FreeImage_GetHeight(_dib),	// number of scan lines to copy
								FreeImage_GetBits(_dib),	// array for bitmap bits
								FreeImage_GetInfo(_dib),	// bitmap data buffer
								DIB_RGB_COLORS				// RGB 
								);
		if(Success == 0) {
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Error : GetDIBits failed");
			ReleaseDC(NULL, dc);
			return FALSE;
        }
        ReleaseDC(NULL, dc);

		// restore BITMAPINFO members
		
		FreeImage_GetInfoHeader(_dib)->biClrUsed = nColors;
		FreeImage_GetInfoHeader(_dib)->biClrImportant = nColors;

		return TRUE;
    }

	return FALSE;
}
Пример #10
0
/** @brief Determines, whether a palletized image is visually greyscale or not.
 
 Unlike with FreeImage_GetColorType, which returns either FIC_MINISBLACK or
 FIC_MINISWHITE for a greyscale image with a linear ramp palette, the return  
 value of this function does not depend on the palette's order, but only on the
 palette's individual colors.
 @param dib The image to be tested.
 @return Returns TRUE if the palette of the image specified contains only
 greyscales, FALSE otherwise.
 */
static BOOL
IsVisualGreyscaleImage(FIBITMAP *dib) {

	switch (FreeImage_GetBPP(dib)) {
		case 1:
		case 4:
		case 8: {
			unsigned ncolors = FreeImage_GetColorsUsed(dib);
			RGBQUAD *rgb = FreeImage_GetPalette(dib);
			for (unsigned i = 0; i< ncolors; i++) {
				if ((rgb->rgbRed != rgb->rgbGreen) || (rgb->rgbRed != rgb->rgbBlue)) {
					return FALSE;
				}
			}
			return TRUE;
		}
		default: {
			return (FreeImage_GetColorType(dib) == FIC_MINISBLACK);
		}
	}
}
Пример #11
0
static FIBITMAP *FreeImage_CreateDIBFromHBITMAP(HBITMAP hBmp)
{
	BITMAP bm;

	if(hBmp) {
		GetObject(hBmp, sizeof(BITMAP), (LPSTR) &bm);
		FIBITMAP *dib = FreeImage_Allocate(bm.bmWidth, bm.bmHeight, bm.bmBitsPixel,0,0,0);
		// The GetDIBits function clears the biClrUsed and biClrImportant BITMAPINFO members (dont't know why)
		// So we save these infos below. This is needed for palettized images only.
		int nColors = FreeImage_GetColorsUsed(dib);
		HDC dc = GetDC(NULL);
		int Success = GetDIBits(dc, hBmp, 0, FreeImage_GetHeight(dib),
			FreeImage_GetBits(dib), FreeImage_GetInfo(dib), DIB_RGB_COLORS);
		ReleaseDC(NULL, dc);
		// restore BITMAPINFO members
		FreeImage_GetInfoHeader(dib)->biClrUsed = nColors;
		FreeImage_GetInfoHeader(dib)->biClrImportant = nColors;
		return dib;
	}
	return NULL;
}
Пример #12
0
	FIBITMAP* getFIInfo(MemChunk& data, SImage::info_t& info)
	{
		// Get FreeImage bitmap info from entry data
		FIMEMORY*         mem = FreeImage_OpenMemory((BYTE*)data.getData(), data.getSize());
		FREE_IMAGE_FORMAT fif = FreeImage_GetFileTypeFromMemory(mem, 0);
		FIBITMAP*         bm  = FreeImage_LoadFromMemory(fif, mem, 0);
		FreeImage_CloseMemory(mem);

		// Check it created/read ok
		if (!bm)
			return nullptr;

		// Get info from image
		info.width     = FreeImage_GetWidth(bm);
		info.height    = FreeImage_GetHeight(bm);
		info.colformat = RGBA; // Generic images always converted to RGBA on loading
		info.format    = id_;

		// Check if palette supplied
		if (FreeImage_GetColorsUsed(bm) > 0)
			info.has_palette = true;

		return bm;
	}
Пример #13
0
static BOOL DLL_CALLCONV
Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
	if ((dib != NULL) && (handle != NULL)) {
		// write the file header

		BITMAPFILEHEADER bitmapfileheader;
		bitmapfileheader.bfType = 0x4D42;
		bitmapfileheader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + FreeImage_GetHeight(dib) * FreeImage_GetPitch(dib);
		bitmapfileheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + FreeImage_GetColorsUsed(dib) * sizeof(RGBQUAD);
		bitmapfileheader.bfReserved1 = 0;
		bitmapfileheader.bfReserved2 = 0;

		// take care of the bit fields data of any

		bool bit_fields = (FreeImage_GetBPP(dib) == 16);

		if (bit_fields) {
			bitmapfileheader.bfSize += 3 * sizeof(DWORD);
			bitmapfileheader.bfOffBits += 3 * sizeof(DWORD);
		}

#ifdef FREEIMAGE_BIGENDIAN
		SwapFileHeader(&bitmapfileheader);
#endif
		if (io->write_proc(&bitmapfileheader, sizeof(BITMAPFILEHEADER), 1, handle) != 1)
			return FALSE;		

		// update the bitmap info header

		BITMAPINFOHEADER bih = *FreeImage_GetInfoHeader(dib);

		if (bit_fields)
			bih.biCompression = BI_BITFIELDS;
		else if ((bih.biBitCount == 8) && (flags & BMP_SAVE_RLE))
			bih.biCompression = BI_RLE8;
		else
			bih.biCompression = BI_RGB;

		// write the bitmap info header

#ifdef FREEIMAGE_BIGENDIAN
		SwapInfoHeader(&bih);
#endif
		if (io->write_proc(&bih, sizeof(BITMAPINFOHEADER), 1, handle) != 1)
			return FALSE;

		// write the bit fields when we are dealing with a 16 bit BMP

		if (bit_fields) {
			DWORD d;

			d = FreeImage_GetRedMask(dib);

			if (io->write_proc(&d, sizeof(DWORD), 1, handle) != 1)
				return FALSE;

			d = FreeImage_GetGreenMask(dib);

			if (io->write_proc(&d, sizeof(DWORD), 1, handle) != 1)
				return FALSE;

			d = FreeImage_GetBlueMask(dib);

			if (io->write_proc(&d, sizeof(DWORD), 1, handle) != 1)
				return FALSE;
		}

		// write the palette

		if (FreeImage_GetPalette(dib) != NULL) {
			RGBQUAD *pal = FreeImage_GetPalette(dib);
			FILE_BGRA bgra;
			for(unsigned i = 0; i < FreeImage_GetColorsUsed(dib); i++ ) {
				bgra.b = pal[i].rgbBlue;
				bgra.g = pal[i].rgbGreen;
				bgra.r = pal[i].rgbRed;
				bgra.a = pal[i].rgbReserved;
				if (io->write_proc(&bgra, sizeof(FILE_BGRA), 1, handle) != 1)
					return FALSE;
			}
		}

		// write the bitmap data... if RLE compression is enable, use it

		unsigned bpp = FreeImage_GetBPP(dib);
		if ((bpp == 8) && (flags & BMP_SAVE_RLE)) {
			BYTE *buffer = new BYTE[FreeImage_GetPitch(dib) * 2];

			for (DWORD i = 0; i < FreeImage_GetHeight(dib); ++i) {
				int size = RLEEncodeLine(buffer, FreeImage_GetScanLine(dib, i), FreeImage_GetLine(dib));

				if (io->write_proc(buffer, size, 1, handle) != 1) {
					delete [] buffer;
					return FALSE;
				}
			}

			buffer[0] = RLE_COMMAND;
			buffer[1] = RLE_ENDOFBITMAP;

			if (io->write_proc(buffer, 2, 1, handle) != 1) {
				delete [] buffer;
				return FALSE;
			}

			delete [] buffer;
#ifdef FREEIMAGE_BIGENDIAN
		} else if (bpp == 16) {
			WORD pixel;
			for(int y = 0; y < FreeImage_GetHeight(dib); y++) {
				BYTE *line = FreeImage_GetScanLine(dib, y);
				for(int x = 0; x < FreeImage_GetWidth(dib); x++) {
					pixel = ((WORD *)line)[x];
					SwapShort(&pixel);
					if (io->write_proc(&pixel, sizeof(WORD), 1, handle) != 1)
						return FALSE;
				}
			}
		} else if (bpp == 24) {
			FILE_BGR bgr;
			for(int y = 0; y < FreeImage_GetHeight(dib); y++) {
				BYTE *line = FreeImage_GetScanLine(dib, y);
				for(int x = 0; x < FreeImage_GetWidth(dib); x++) {
					RGBTRIPLE *triple = ((RGBTRIPLE *)line)+x;
					bgr.b = triple->rgbtBlue;
					bgr.g = triple->rgbtGreen;
					bgr.r = triple->rgbtRed;
					if (io->write_proc(&bgr, sizeof(FILE_BGR), 1, handle) != 1)
						return FALSE;
				}
			}
		} else if (bpp == 32) {
			FILE_BGRA bgra;
			for(int y = 0; y < FreeImage_GetHeight(dib); y++) {
				BYTE *line = FreeImage_GetScanLine(dib, y);
				for(int x = 0; x < FreeImage_GetWidth(dib); x++) {
					RGBQUAD *quad = ((RGBQUAD *)line)+x;
					bgra.b = quad->rgbBlue;
					bgra.g = quad->rgbGreen;
					bgra.r = quad->rgbRed;
					bgra.a = quad->rgbReserved;
					if (io->write_proc(&bgra, sizeof(FILE_BGRA), 1, handle) != 1)
						return FALSE;
				}
			}
#endif
		} else if (io->write_proc(FreeImage_GetBits(dib), FreeImage_GetHeight(dib) * FreeImage_GetPitch(dib), 1, handle) != 1) {
			return FALSE;
		}

		return TRUE;
	} else {
		return FALSE;
	}
}
Пример #14
0
/** @brief Allocates a new image of the specified type, width, height and bit depth and
 optionally fills it with the specified color.

 This function is an extension to FreeImage_AllocateT, which additionally supports specifying
 a palette to be set for the newly create image, as well as specifying a background color,
 the newly created image should initially be filled with.

 Basically, this function internally relies on function FreeImage_AllocateT, followed by a
 call to FreeImage_FillBackground. This is why both parameters color and options behave the
 same as it is documented for function FreeImage_FillBackground. So, please refer to the
 documentation of FreeImage_FillBackground to learn more about parameters color and options.

 The palette specified through parameter palette is only copied to the newly created
 image, if its image type is FIT_BITMAP and the desired bit depth is smaller than or equal
 to 8 bits per pixel. In other words, the palette parameter is only taken into account for
 palletized images. However, if the preceding conditions match and if palette is not NULL,
 the memory pointed to by the palette pointer is assumed to be at least as large as size
 of a fully populated palette for the desired bit depth. So, for an 8-bit image, this size
 is 256 x sizeof(RGBQUAD), for an 4-bit image it is 16 x sizeof(RGBQUAD) and it is
 2 x sizeof(RGBQUAD) for a 1-bit image. In other words, this function does not support
 partial palettes.

 However, specifying a palette is not necessarily needed, even for palletized images. This
 function is capable of implicitly creating a palette, if parameter palette is NULL. If the
 specified background color is a greyscale value (red = green = blue) or if option
 FI_COLOR_ALPHA_IS_INDEX is specified, a greyscale palette is created. For a 1-bit image, only
 if the specified background color is either black or white, a monochrome palette, consisting
 of black and white only is created. In any case, the darker colors are stored at the smaller
 palette indices.

 If the specified background color is not a greyscale value, or is neither black nor white
 for a 1-bit image, solely this single color is injected into the otherwise black-initialized
 palette. For this operation, option FI_COLOR_ALPHA_IS_INDEX is implicit, so the specified
 color is applied to the palette entry, specified by the background color's rgbReserved
 member. The image is then filled with this palette index.

 This function returns a newly created image as function FreeImage_AllocateT does, if both
 parameters color and palette are NULL. If only color is NULL, the palette pointed to by
 parameter palette is initially set for the new image, if a palletized image of type
 FIT_BITMAP is created. However, in the latter case, this function returns an image, whose
 pixels are all initialized with zeros so, the image will be filled with the color of the
 first palette entry.

 @param type Specifies the image type of the new image.
 @param width The desired width in pixels of the new image.
 @param height The desired height in pixels of the new image.
 @param bpp The desired bit depth of the new image.
 @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.
 @param red_mask Specifies the bits used to store the red components of a pixel.
 @param green_mask Specifies the bits used to store the green components of a pixel.
 @param blue_mask Specifies the bits used to store the blue components of a pixel.
 @return Returns a pointer to a newly allocated image on success, NULL otherwise.
 */
FIBITMAP * DLL_CALLCONV
FreeImage_AllocateExT(FREE_IMAGE_TYPE type, int width, int height, int bpp, const void *color, int options, const RGBQUAD *palette, unsigned red_mask, unsigned green_mask, unsigned blue_mask) {

	FIBITMAP *bitmap = FreeImage_AllocateT(type, width, height, bpp, red_mask, green_mask, blue_mask);
	
	if (!color) {
		if ((palette) && (type == FIT_BITMAP) && (bpp <= 8)) {
			memcpy(FreeImage_GetPalette(bitmap), palette, FreeImage_GetColorsUsed(bitmap) * sizeof(RGBQUAD));
		}
		return bitmap;
	}

	if (bitmap != NULL) {
		
		// Only fill the new bitmap if the specified color
		// differs from "black", that is not all bytes of the
		// color are equal to zero.
		switch (bpp) {
			case 1: {
				// although 1-bit implies FIT_BITMAP, better get an unsigned 
				// color and palette
				unsigned *urgb = (unsigned *)color;
				unsigned *upal = (unsigned *)FreeImage_GetPalette(bitmap);
				RGBQUAD rgbq = RGBQUAD();

				if (palette != NULL) {
					// clone the specified palette
					memcpy(FreeImage_GetPalette(bitmap), palette, 2 * sizeof(RGBQUAD));
				} else if (options & FI_COLOR_ALPHA_IS_INDEX) {
					CREATE_GREYSCALE_PALETTE(upal, 2);
				} else {
					// check, whether the specified color is either black or white
					if ((*urgb & 0xFFFFFF) == 0x000000) {
						// in any case build a FIC_MINISBLACK palette
						CREATE_GREYSCALE_PALETTE(upal, 2);
						color = &rgbq;
					} else if ((*urgb & 0xFFFFFF) == 0xFFFFFF) {
						// in any case build a FIC_MINISBLACK palette
						CREATE_GREYSCALE_PALETTE(upal, 2);
						rgbq.rgbReserved = 1;
						color = &rgbq;
					} else {
						// Otherwise inject the specified color into the so far
						// black-only palette. We use color->rgbReserved as the
						// desired palette index.
						BYTE index = ((RGBQUAD *)color)->rgbReserved & 0x01;
						upal[index] = *urgb & 0x00FFFFFF;  
					}
					options |= FI_COLOR_ALPHA_IS_INDEX;
				}
				// and defer to FreeImage_FillBackground
				FreeImage_FillBackground(bitmap, color, options);
				break;
			}
			case 4: {
				// 4-bit implies FIT_BITMAP so, get a RGBQUAD color
				RGBQUAD *rgb = (RGBQUAD *)color;
				RGBQUAD *pal = FreeImage_GetPalette(bitmap);
				RGBQUAD rgbq = RGBQUAD();
				
				if (palette != NULL) {
					// clone the specified palette
					memcpy(pal, palette, 16 * sizeof(RGBQUAD));
				} else if (options & FI_COLOR_ALPHA_IS_INDEX) {
					CREATE_GREYSCALE_PALETTE(pal, 16);
				} else {
					// check, whether the specified color is a grey one
					if ((rgb->rgbRed == rgb->rgbGreen) && (rgb->rgbRed == rgb->rgbBlue)) {
						// if so, build a greyscale palette
						CREATE_GREYSCALE_PALETTE(pal, 16);
						rgbq.rgbReserved = rgb->rgbRed >> 4;
						color = &rgbq;
					} else {
						// Otherwise inject the specified color into the so far
						// black-only palette. We use color->rgbReserved as the
						// desired palette index.
						BYTE index = (rgb->rgbReserved & 0x0F);
						((unsigned *)pal)[index] = *((unsigned *)rgb) & 0x00FFFFFF;
					}
					options |= FI_COLOR_ALPHA_IS_INDEX;
				}
				// and defer to FreeImage_FillBackground
				FreeImage_FillBackground(bitmap, color, options);
				break;
			}
			case 8: {
				// 8-bit implies FIT_BITMAP so, get a RGBQUAD color
				RGBQUAD *rgb = (RGBQUAD *)color;
				RGBQUAD *pal = FreeImage_GetPalette(bitmap);
				RGBQUAD rgbq;

				if (palette != NULL) {
					// clone the specified palette
					memcpy(pal, palette, 256 * sizeof(RGBQUAD));
				} else if (options & FI_COLOR_ALPHA_IS_INDEX) {
					CREATE_GREYSCALE_PALETTE(pal, 256);
				} else {
					// check, whether the specified color is a grey one
					if ((rgb->rgbRed == rgb->rgbGreen) && (rgb->rgbRed == rgb->rgbBlue)) {
						// if so, build a greyscale palette
						CREATE_GREYSCALE_PALETTE(pal, 256);
						rgbq.rgbReserved = rgb->rgbRed;
						color = &rgbq;
					} else {
						// Otherwise inject the specified color into the so far
						// black-only palette. We use color->rgbReserved as the
						// desired palette index.
						BYTE index = rgb->rgbReserved;
						((unsigned *)pal)[index] = *((unsigned *)rgb) & 0x00FFFFFF;  
					}
					options |= FI_COLOR_ALPHA_IS_INDEX;
				}
				// and defer to FreeImage_FillBackground
				FreeImage_FillBackground(bitmap, color, options);
				break;
			}
			case 16: {
				WORD wcolor = (type == FIT_BITMAP) ?
					RGBQUAD_TO_WORD(bitmap, ((RGBQUAD *)color)) : *((WORD *)color);
				if (wcolor != 0) {
					FreeImage_FillBackground(bitmap, color, options);
				}
				break;
			}
			default: {
				int bytespp = bpp / 8;
				for (int i = 0; i < bytespp; i++) {
					if (((BYTE *)color)[i] != 0) {
						FreeImage_FillBackground(bitmap, color, options);
						break;
					}
				}
				break;
			}
		}
Пример #15
0
unsigned DLL_CALLCONV
FreeImage_GetDIBSize(FIBITMAP *dib) {
	return (dib) ? sizeof(BITMAPINFOHEADER) + (FreeImage_GetColorsUsed(dib) * sizeof(RGBQUAD)) + (FreeImage_GetPitch(dib) * FreeImage_GetHeight(dib)) : 0;
}
Пример #16
0
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
    if (handle != NULL) {
        FIBITMAP *dib = NULL;

        DWORD type, size;

        io->read_proc(&type, 4, 1, handle);
#ifndef FREEIMAGE_BIGENDIAN
        SwapLong(&type);
#endif

        if(type != ID_FORM)
            return NULL;

        io->read_proc(&size, 4, 1, handle);
#ifndef FREEIMAGE_BIGENDIAN
        SwapLong(&size);
#endif

        io->read_proc(&type, 4, 1, handle);
#ifndef FREEIMAGE_BIGENDIAN
        SwapLong(&type);
#endif

        if((type != ID_ILBM) && (type != ID_PBM))
            return NULL;

        size -= 4;

        unsigned width = 0, height = 0, planes = 0, depth = 0, comp = 0;

        while (size) {
            DWORD ch_type,ch_size;

            io->read_proc(&ch_type, 4, 1, handle);
#ifndef FREEIMAGE_BIGENDIAN
            SwapLong(&ch_type);
#endif

            io->read_proc(&ch_size,4,1,handle );
#ifndef FREEIMAGE_BIGENDIAN
            SwapLong(&ch_size);
#endif

            unsigned ch_end = io->tell_proc(handle) + ch_size;

            if (ch_type == ID_BMHD) {           // Bitmap Header
                if (dib)
                    FreeImage_Unload(dib);

                BMHD bmhd;

                io->read_proc(&bmhd, sizeof(bmhd), 1, handle);
#ifndef FREEIMAGE_BIGENDIAN
                SwapHeader(&bmhd);
#endif

                width = bmhd.w;
                height = bmhd.h;
                planes = bmhd.nPlanes;
                comp = bmhd.compression;

                if(bmhd.masking & 1)
                    planes++;   // there is a mask ( 'stencil' )

                if (planes > 8 && planes != 24)
                    return NULL;

                depth = planes > 8 ? 24 : 8;

                if( depth == 24 ) {
                    dib = FreeImage_Allocate(width, height, depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
                } else {
                    dib = FreeImage_Allocate(width, height, depth);
                }
            } else if (ch_type == ID_CMAP) {    // Palette (Color Map)
                if (!dib)
                    return NULL;

                RGBQUAD *pal = FreeImage_GetPalette(dib);
                if(pal != NULL) {
                    unsigned palette_entries = MIN((unsigned)ch_size / 3, FreeImage_GetColorsUsed(dib));
                    for (unsigned k = 0; k < palette_entries; k++) {
                        io->read_proc(&pal[k].rgbRed, 1, 1, handle );
                        io->read_proc(&pal[k].rgbGreen, 1, 1, handle );
                        io->read_proc(&pal[k].rgbBlue, 1, 1, handle );
                    }
                }
            } else if (ch_type == ID_BODY) {
                if (!dib)
                    return NULL;

                if (type == ID_PBM) {
                    // NON INTERLACED (LBM)

                    unsigned line = FreeImage_GetLine(dib) + 1 & ~1;

                    for (unsigned i = 0; i < FreeImage_GetHeight(dib); i++) {
                        BYTE *bits = FreeImage_GetScanLine(dib, FreeImage_GetHeight(dib) - i - 1);

                        if (comp == 1) {
                            // use RLE compression

                            DWORD number_of_bytes_written = 0;
                            BYTE rle_count;
                            BYTE byte;

                            while (number_of_bytes_written < line) {
                                io->read_proc(&rle_count, 1, 1, handle);

                                if (rle_count < 128) {
                                    for (int k = 0; k < rle_count + 1; k++) {
                                        io->read_proc(&byte, 1, 1, handle);

                                        bits[number_of_bytes_written++] += byte;
                                    }
                                } else if (rle_count > 128) {
                                    io->read_proc(&byte, 1, 1, handle);

                                    for (int k = 0; k < 257 - rle_count; k++) {
                                        bits[number_of_bytes_written++] += byte;
                                    }
                                }
                            }
                        } else {
                            // don't use compression

                            io->read_proc(bits, line, 1, handle);
                        }
                    }

                    return dib;
                } else {
                    // INTERLACED (ILBM)

                    unsigned pixel_size = depth/8;
                    unsigned n_width=(width+15)&~15;
                    unsigned plane_size = n_width/8;
                    unsigned src_size = plane_size * planes;
                    BYTE *src = (BYTE*)malloc(src_size);
                    BYTE *dest = FreeImage_GetBits(dib);

                    dest += FreeImage_GetPitch(dib) * height;

                    for (unsigned y = 0; y < height; y++) {
                        dest -= FreeImage_GetPitch(dib);

                        // read all planes in one hit,
                        // 'coz PSP compresses across planes...

                        if (comp) {
                            // unpacker algorithm

                            for(unsigned x = 0; x < src_size;) {
                                // read the next source byte into t
                                signed char t = 0;
                                io->read_proc(&t, 1, 1, handle);

                                if (t >= 0) {
                                    // t = [0..127] => copy the next t+1 bytes literally
                                    unsigned size_to_read = t + 1;

                                    if((size_to_read + x) > src_size) {
                                        // sanity check for buffer overruns
                                        size_to_read = src_size - x;
                                        io->read_proc(src + x, size_to_read, 1, handle);
                                        x += (t + 1);
                                    } else {
                                        io->read_proc(src + x, size_to_read, 1, handle);
                                        x += size_to_read;
                                    }
                                } else if (t != -128) {
                                    // t = [-1..-127]  => replicate the next byte -t+1 times
                                    BYTE b = 0;
                                    io->read_proc(&b, 1, 1, handle);
                                    unsigned size_to_copy = (unsigned)(-(int)t + 1);

                                    if((size_to_copy + x) > src_size) {
                                        // sanity check for buffer overruns
                                        size_to_copy = src_size - x;
                                        memset(src + x, b, size_to_copy);
                                        x += (unsigned)(-(int)t + 1);
                                    } else {
                                        memset(src + x, b, size_to_copy);
                                        x += size_to_copy;
                                    }
                                }
                                // t = -128 => noop
                            }
                        } else {
                            io->read_proc(src, src_size, 1, handle);
                        }

                        // lazy planar->chunky...

                        for (unsigned x = 0; x < width; x++) {
                            for (unsigned n = 0; n < planes; n++) {
                                BYTE bit = (BYTE)( src[n * plane_size + (x / 8)] >> ((x^7) & 7) );

                                dest[x * pixel_size + (n / 8)] |= (bit & 1) << (n & 7);
                            }
                        }

#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
                        if (depth == 24) {
                            for (unsigned x = 0; x < width; ++x){
                                INPLACESWAP(dest[x * 3], dest[x * 3 + 2]);
                            }
                        }
#endif
                    }

                    free(src);

                    return dib;
                }
            }

            // Every odd-length chunk is followed by a 0 pad byte.  This pad
            //  byte is not counted in ch_size.
            if (ch_size & 1) {
                ch_size++;
                ch_end++;
            }

            io->seek_proc(handle, ch_end - io->tell_proc(handle), SEEK_CUR);

            size -= ch_size + 8;
        }

        if (dib)
            FreeImage_Unload(dib);
    }
Пример #17
0
FREE_IMAGE_COLOR_TYPE DLL_CALLCONV
FreeImage_GetColorType(FIBITMAP *dib) {
	RGBQUAD *rgb;

	FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);

	// special bitmap type
	if(image_type != FIT_BITMAP) {
		switch(image_type) {
			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;

			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;
		}
				
		default :
			return FIC_MINISBLACK;
	}
}
Пример #18
0
static HBITMAP 
GetDibSection(FIBITMAP *src, HDC hdc, int left, int top, int right, int bottom)
{
	if(!src) 
		return NULL;

	unsigned bpp = FreeImage_GetBPP(src);

	if(bpp <=4)
		return NULL;

	// normalize the rectangle
	if(right < left)
		INPLACESWAP(left, right);

	if(bottom < top)
		INPLACESWAP(top, bottom);

	// check the size of the sub image
	int src_width  = FreeImage_GetWidth(src);
	int src_height = FreeImage_GetHeight(src);
	int src_pitch = FreeImage_GetPitch(src);

	if((left < 0) || (right > src_width) || (top < 0) || (bottom > src_height))
		return NULL;

	// allocate the sub image
	int dst_width = (right - left);
	int dst_height = (bottom - top);

	BITMAPINFO *info = (BITMAPINFO *) malloc(sizeof(BITMAPINFO) + (FreeImage_GetColorsUsed(src) * sizeof(RGBQUAD)));
	BITMAPINFOHEADER *bih = (BITMAPINFOHEADER *)info;

	bih->biSize = sizeof(BITMAPINFOHEADER);
	bih->biWidth = dst_width;
	bih->biHeight = dst_height;
	bih->biPlanes = 1;
	bih->biBitCount = bpp;
	bih->biCompression = BI_RGB;
	bih->biSizeImage = 0;
    bih->biXPelsPerMeter = 0;
    bih->biYPelsPerMeter = 0;
   	bih->biClrUsed = 0;           // Always use the whole palette.
    bih->biClrImportant = 0;

	// copy the palette
	if(bpp < 16)
		memcpy(info->bmiColors, FreeImage_GetPalette(src), FreeImage_GetColorsUsed(src) * sizeof(RGBQUAD));

	BYTE *dst_bits;

	HBITMAP hbitmap = CreateDIBSection(hdc, info, DIB_RGB_COLORS, (void **) &dst_bits, NULL, 0);

	free(info);

	if(hbitmap == NULL || dst_bits == NULL)
		return NULL;

	// get the pointers to the bits and such
	BYTE *src_bits = FreeImage_GetScanLine(src, src_height - top - dst_height);

	// calculate the number of bytes per pixel
	unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);
	
	// point to x = left
	src_bits += (left * bytespp);	

	int dst_line = (dst_width * bpp + 7) / 8;
	int dst_pitch = (dst_line + 3) & ~3;

	for(int y = 0; y < dst_height; y++)
		memcpy(dst_bits + (y * dst_pitch), src_bits + (y * src_pitch), dst_line);

	return hbitmap;
}
Пример #19
0
/** @brief Looks up a specified color in a FIBITMAP's palette and returns the color's
 palette index or -1 if the color was not found.

 Unlike with FreeImage_GetColorType, which returns either FIC_MINISBLACK or
 FIC_MINISWHITE for a greyscale image with a linear ramp palette, the return
 value of this function does not depend on the palette's order, but only on the
 palette's individual colors.
 @param dib The image, whose palette should be searched through.
 @param color The color to be searched in the palette.
 @param options Options that affect the color search process.
 @param color_type A pointer, that optionally specifies the image's color type as
 returned by FreeImage_GetColorType. If invalid or NULL, this function determines the
 color type with FreeImage_GetColorType.
 @return Returns the specified color's palette index, the color's rgbReserved member
 if option FI_COLOR_ALPHA_IS_INDEX was specified or -1, if the color was not found
 in the image's palette or if the specified image is non-palletized.
 */
static int
GetPaletteIndex(FIBITMAP *dib, const RGBQUAD *color, int options, FREE_IMAGE_COLOR_TYPE *color_type) {
	
	int result = -1;
	
	if ((!dib) || (!color)) {
		return result;
	}
	
	int bpp = FreeImage_GetBPP(dib);

	// First check trivial case: return color->rgbReserved if only
	// FI_COLOR_ALPHA_IS_INDEX is set.
	if ((options & FI_COLOR_ALPHA_IS_INDEX) == FI_COLOR_ALPHA_IS_INDEX) {
		if (bpp == 1) {
			return color->rgbReserved & 0x01;
		} else if (bpp == 4) {
			return color->rgbReserved & 0x0F;
		}
		return color->rgbReserved;
	}
	
	if (bpp == 8) {
		FREE_IMAGE_COLOR_TYPE ct =
			(color_type == NULL || *color_type < 0) ?
				FreeImage_GetColorType(dib) : *color_type;
		if (ct == FIC_MINISBLACK) {
			return GREY(color->rgbRed, color->rgbGreen, color->rgbBlue);
		}
		if (ct == FIC_MINISWHITE) {
			return 255 - GREY(color->rgbRed, color->rgbGreen, color->rgbBlue);
		}
	} else if (bpp > 8) {
		// for palettized images only
		return result;
	}

	if (options & FI_COLOR_FIND_EQUAL_COLOR) {
		
		// Option FI_COLOR_ALPHA_IS_INDEX is implicit here so, set
		// index to color->rgbReserved
		result = color->rgbReserved;
		if (bpp == 1) {
			result &= 0x01;
		} else if (bpp == 4) {
			result &= 0x0F;
		}		

		unsigned ucolor;
		if (!IsVisualGreyscaleImage(dib)) {
			ucolor = (*((unsigned *)color)) & 0xFFFFFF;
		} else {
			ucolor = GREY(color->rgbRed, color->rgbGreen, color->rgbBlue) * 0x010101;
			//ucolor = (ucolor | (ucolor << 8) | (ucolor << 16));
		}
		unsigned ncolors = FreeImage_GetColorsUsed(dib);
		unsigned *palette = (unsigned *)FreeImage_GetPalette(dib);
		for (unsigned i = 0; i < ncolors; i++) {
			if ((palette[i] & 0xFFFFFF) == ucolor) {
				result = i;
				break;
			}
		}
	} else {
		unsigned minimum = UINT_MAX;
		unsigned ncolors = FreeImage_GetColorsUsed(dib);
		BYTE *palette = (BYTE *)FreeImage_GetPalette(dib);
		BYTE red, green, blue;
		if (!IsVisualGreyscaleImage(dib)) {
			red = color->rgbRed;
			green = color->rgbGreen;
			blue = color->rgbBlue;
		} else {
			red = GREY(color->rgbRed, color->rgbGreen, color->rgbBlue);
			green = blue = red;
		}
		for (unsigned i = 0; i < ncolors; i++) {
			unsigned m = abs(palette[FI_RGBA_BLUE] - blue)
					+ abs(palette[FI_RGBA_GREEN] - green)
					+ abs(palette[FI_RGBA_RED] - red);
			if (m < minimum) {
				minimum = m;
				result = i;
				if (m == 0) {
					break;
				}
			}
			palette += sizeof(RGBQUAD);
		}		
	}
	return result;
}
Пример #20
0
/** @brief Perfoms an histogram transformation on a 8, 24 or 32-bit image 
according to the values of a lookup table (LUT).

The transformation is done as follows.<br>
Image 8-bit : if the image has a color palette, the LUT is applied to this palette, 
otherwise, it is applied to the grey values.<br>
Image 24-bit & 32-bit : if channel == FICC_RGB, the same LUT is applied to each color
plane (R,G, and B). Otherwise, the LUT is applied to the specified channel only.
@param src Input image to be processed.
@param LUT Lookup table. <b>The size of 'LUT' is assumed to be 256.</b>
@param channel The color channel to be processed (only used with 24 & 32-bit DIB).
@return Returns TRUE if successful, FALSE otherwise.
@see FREE_IMAGE_COLOR_CHANNEL
*/
BOOL DLL_CALLCONV 
FreeImage_AdjustCurve(FIBITMAP *src, BYTE *LUT, FREE_IMAGE_COLOR_CHANNEL channel) {
	unsigned x, y;
	BYTE *bits = NULL;

	if(!src || !LUT || (FreeImage_GetImageType(src) != FIT_BITMAP))
		return FALSE;

	int bpp = FreeImage_GetBPP(src);
	if((bpp != 8) && (bpp != 24) && (bpp != 32))
		return FALSE;

	// apply the LUT
	switch(bpp) {

		case 8 :
		{
			// if the dib has a colormap, apply the LUT to it
			// else, apply the LUT to pixel values

			if(FreeImage_GetColorType(src) == FIC_PALETTE) {
				RGBQUAD *rgb = FreeImage_GetPalette(src);
				for (unsigned pal = 0; pal < FreeImage_GetColorsUsed(src); pal++) {
					rgb->rgbRed   = LUT[rgb->rgbRed];
					rgb->rgbGreen = LUT[rgb->rgbGreen];
					rgb->rgbBlue  = LUT[rgb->rgbBlue];
					rgb++;
				}
			}
			else {
				for(y = 0; y < FreeImage_GetHeight(src); y++) {
					bits =  FreeImage_GetScanLine(src, y);
					for(x = 0; x < FreeImage_GetWidth(src); x++) {
						bits[x] = LUT[ bits[x] ];
					}
				}
			}

			break;
		}

		case 24 :
		case 32 :
		{
			int bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);

			switch(channel) {
				case FICC_RGB :
					for(y = 0; y < FreeImage_GetHeight(src); y++) {
						bits =  FreeImage_GetScanLine(src, y);
						for(x = 0; x < FreeImage_GetWidth(src); x++) {
							bits[FI_RGBA_BLUE]	= LUT[ bits[FI_RGBA_BLUE] ];	// B
							bits[FI_RGBA_GREEN] = LUT[ bits[FI_RGBA_GREEN] ];	// G
							bits[FI_RGBA_RED]	= LUT[ bits[FI_RGBA_RED] ];		// R
							
							bits += bytespp;
						}
					}
					break;

				case FICC_BLUE :
					for(y = 0; y < FreeImage_GetHeight(src); y++) {
						bits =  FreeImage_GetScanLine(src, y);
						for(x = 0; x < FreeImage_GetWidth(src); x++) {
							bits[FI_RGBA_BLUE] = LUT[ bits[FI_RGBA_BLUE] ];		// B
							
							bits += bytespp;
						}
					}
					break;

				case FICC_GREEN :
					for(y = 0; y < FreeImage_GetHeight(src); y++) {
						bits =  FreeImage_GetScanLine(src, y);
						for(x = 0; x < FreeImage_GetWidth(src); x++) {
							bits[FI_RGBA_GREEN] = LUT[ bits[FI_RGBA_GREEN] ];	// G
							
							bits += bytespp;
						}
					}
					break;

				case FICC_RED :
					for(y = 0; y < FreeImage_GetHeight(src); y++) {
						bits =  FreeImage_GetScanLine(src, y);
						for(x = 0; x < FreeImage_GetWidth(src); x++) {
							bits[FI_RGBA_RED] = LUT[ bits[FI_RGBA_RED] ];		// R
							
							bits += bytespp;
						}
					}
					break;
					
				case FICC_ALPHA :
					if(32 == bpp) {
						for(y = 0; y < FreeImage_GetHeight(src); y++) {
							bits =  FreeImage_GetScanLine(src, y);
							for(x = 0; x < FreeImage_GetWidth(src); x++) {
								bits[FI_RGBA_ALPHA] = LUT[ bits[FI_RGBA_ALPHA] ];	// A
								
								bits += bytespp;
							}
						}
					}
					break;

				default:
					break;
			}
			break;
		}
	}

	return TRUE;
}
Пример #21
0
WORD fipImage::getPaletteSize() const {
	return FreeImage_GetColorsUsed(_dib) * sizeof(RGBQUAD);
}
Пример #22
0
/** @brief Applies color mapping for one or several colors on a 1-, 4- or 8-bit
 palletized or a 16-, 24- or 32-bit high color image.

 This function maps up to <i>count</i> colors specified in <i>srccolors</i> to
 these specified in <i>dstcolors</i>. Thereby, color <i>srccolors[N]</i>,
 if found in the image, will be replaced by color <i>dstcolors[N]</i>. If
 parameter <i>swap</i> is TRUE, additionally all colors specified in
 <i>dstcolors</i> are also mapped to these specified in <i>srccolors</i>. For
 high color images, the actual image data will be modified whereas, for
 palletized images only the palette will be changed.<br>

 The function returns the number of pixels changed or zero, if no pixels were
 changed. 

 Both arrays <i>srccolors</i> and <i>dstcolors</i> are assumed not to hold less
 than <i>count</i> colors.<br>

 For 16-bit images, all colors specified are transparently converted to their 
 proper 16-bit representation (either in RGB555 or RGB565 format, which is
 determined by the image's red- green- and blue-mask).<br>

 <b>Note, that this behaviour is different from what FreeImage_ApplyPaletteIndexMapping()
 does, which modifies the actual image data on palletized images.</b>

 @param dib Input/output image to be processed.
 @param srccolors Array of colors to be used as the mapping source.
 @param dstcolors Array of colors to be used as the mapping destination.
 @param count The number of colors to be mapped. This is the size of both
 <i>srccolors</i> and <i>dstcolors</i>.  
 @param ignore_alpha If TRUE, 32-bit images and colors are treated as 24-bit.
 @param swap If TRUE, source and destination colors are swapped, that is,
 each destination color is also mapped to the corresponding source color.  
 @return Returns the total number of pixels changed. 
 */
unsigned DLL_CALLCONV
FreeImage_ApplyColorMapping(FIBITMAP *dib, RGBQUAD *srccolors, RGBQUAD *dstcolors, unsigned count, BOOL ignore_alpha, BOOL swap) {
	unsigned result = 0;

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

	// validate parameters
	if ((!srccolors) || (!dstcolors)|| (count < 1)) {
		return 0;
	}

	int bpp = FreeImage_GetBPP(dib);
	switch (bpp) {
		case 1:
		case 4:
		case 8: {
			unsigned size = FreeImage_GetColorsUsed(dib);
			RGBQUAD *pal = FreeImage_GetPalette(dib);
			RGBQUAD *a, *b;
			for (unsigned x = 0; x < size; x++) {
				for (unsigned j = 0; j < count; j++) {
					a = srccolors;
					b = dstcolors;
					for (int i = (swap ? 0 : 1); i < 2; i++) {
						if ((pal[x].rgbBlue == a[j].rgbBlue)&&(pal[x].rgbGreen == a[j].rgbGreen) &&(pal[x].rgbRed== a[j].rgbRed)) {
							pal[x].rgbBlue = b[j].rgbBlue;
							pal[x].rgbGreen = b[j].rgbGreen;
							pal[x].rgbRed = b[j].rgbRed;
							result++;
							j = count;
							break;
						}
						a = dstcolors;
						b = srccolors;
					}
				}
			}
			return result;
		}
		case 16: {
			WORD *src16 = (WORD *)malloc(sizeof(WORD) * count);
			if (NULL == src16) {
				return 0;
			}

			WORD *dst16 = (WORD *)malloc(sizeof(WORD) * count);
			if (NULL == dst16) {
				free(src16);
				return 0;
			}

			for (unsigned j = 0; j < count; j++) {
				src16[j] = RGBQUAD_TO_WORD(dib, (srccolors + j));
				dst16[j] = RGBQUAD_TO_WORD(dib, (dstcolors + j));
			}

			unsigned height = FreeImage_GetHeight(dib);
			unsigned width = FreeImage_GetWidth(dib);
			WORD *a, *b;
			for (unsigned y = 0; y < height; y++) {
				WORD *bits = (WORD *)FreeImage_GetScanLine(dib, y);
				for (unsigned x = 0; x < width; x++, bits++) {
					for (unsigned j = 0; j < count; j++) {
						a = src16;
						b = dst16;
						for (int i = (swap ? 0 : 1); i < 2; i++) {
							if (*bits == a[j]) {
								*bits = b[j];
								result++;
								j = count;
								break;
							}
							a = dst16;
							b = src16;
						}
					}
				}
			}
			free(src16);
			free(dst16);
			return result;
		}
		case 24: {
			unsigned height = FreeImage_GetHeight(dib);
			unsigned width = FreeImage_GetWidth(dib);
			RGBQUAD *a, *b;
			for (unsigned y = 0; y < height; y++) {
				BYTE *bits = FreeImage_GetScanLine(dib, y);
				for (unsigned x = 0; x < width; x++, bits += 3) {
					for (unsigned j = 0; j < count; j++) {
						a = srccolors;
						b = dstcolors;
						for (int i = (swap ? 0 : 1); i < 2; i++) {
							if ((bits[FI_RGBA_BLUE] == a[j].rgbBlue) && (bits[FI_RGBA_GREEN] == a[j].rgbGreen) &&(bits[FI_RGBA_RED] == a[j].rgbRed)) {
								bits[FI_RGBA_BLUE] = b[j].rgbBlue;
								bits[FI_RGBA_GREEN] = b[j].rgbGreen;
								bits[FI_RGBA_RED] = b[j].rgbRed;
								result++;
								j = count;
								break;
							}
							a = dstcolors;
							b = srccolors;
						}
					}
				}
			}
			return result;
		}
		case 32: {
			unsigned height = FreeImage_GetHeight(dib);
			unsigned width = FreeImage_GetWidth(dib);
			RGBQUAD *a, *b;
			for (unsigned y = 0; y < height; y++) {
				BYTE *bits = FreeImage_GetScanLine(dib, y);
				for (unsigned x = 0; x < width; x++, bits += 4) {
					for (unsigned j = 0; j < count; j++) {
						a = srccolors;
						b = dstcolors;
						for (int i = (swap ? 0 : 1); i < 2; i++) {
							if ((bits[FI_RGBA_BLUE] == a[j].rgbBlue) &&(bits[FI_RGBA_GREEN] == a[j].rgbGreen) &&(bits[FI_RGBA_RED] == a[j].rgbRed)
								&&((ignore_alpha) || (bits[FI_RGBA_ALPHA] == a[j].rgbReserved))) {
								bits[FI_RGBA_BLUE] = b[j].rgbBlue;
								bits[FI_RGBA_GREEN] = b[j].rgbGreen;
								bits[FI_RGBA_RED] = b[j].rgbRed;
								if (!ignore_alpha) {
									bits[FI_RGBA_ALPHA] = b[j].rgbReserved;
								}
								result++;
								j = count;
								break;
							}
							a = dstcolors;
							b = srccolors;
						}
					}
				}
			}
			return result;
		}
		default: {
			return 0;
		}
	}
}
Пример #23
0
/** @brief Inverts each pixel data.

@param src Input image to be processed.
@return Returns TRUE if successful, FALSE otherwise.
*/
BOOL DLL_CALLCONV 
FreeImage_Invert(FIBITMAP *src) {

	if (!FreeImage_HasPixels(src)) return FALSE;
	
	unsigned i, x, y, k;
	
	const unsigned width = FreeImage_GetWidth(src);
	const unsigned height = FreeImage_GetHeight(src);
	const unsigned bpp = FreeImage_GetBPP(src);

	FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(src);

	if(image_type == FIT_BITMAP) {
		switch(bpp) {
			case 1 :
			case 4 :
			case 8 :
			{
				// if the dib has a colormap, just invert it
				// else, keep the linear grayscale

				if (FreeImage_GetColorType(src) == FIC_PALETTE) {
					RGBQUAD *pal = FreeImage_GetPalette(src);

					for(i = 0; i < FreeImage_GetColorsUsed(src); i++) {
						pal[i].rgbRed	= 255 - pal[i].rgbRed;
						pal[i].rgbGreen = 255 - pal[i].rgbGreen;
						pal[i].rgbBlue	= 255 - pal[i].rgbBlue;
					}
				} else {
					for(y = 0; y < height; y++) {
						BYTE *bits = FreeImage_GetScanLine(src, y);

						for (x = 0; x < FreeImage_GetLine(src); x++) {
							bits[x] = ~bits[x];
						}
					}
				}

				break;
			}		

			case 24 :
			case 32 :
			{
				// Calculate the number of bytes per pixel (3 for 24-bit or 4 for 32-bit)
				const unsigned bytespp = FreeImage_GetLine(src) / width;

				for(y = 0; y < height; y++) {
					BYTE *bits = FreeImage_GetScanLine(src, y);
					for(x = 0; x < width; x++) {
						for(k = 0; k < bytespp; k++) {
							bits[k] = ~bits[k];
						}
						bits += bytespp;
					}
				}

				break;
			}
			default:
				return FALSE;
		}
	}
	else if((image_type == FIT_UINT16) || (image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) {
		// Calculate the number of words per pixel (1 for 16-bit, 3 for 48-bit or 4 for 64-bit)
		const unsigned wordspp = (FreeImage_GetLine(src) / width) / sizeof(WORD);

		for(y = 0; y < height; y++) {
			WORD *bits = (WORD*)FreeImage_GetScanLine(src, y);
			for(x = 0; x < width; x++) {
				for(k = 0; k < wordspp; k++) {
					bits[k] = ~bits[k];
				}
				bits += wordspp;
			}
		}
	}
	else {
		// anything else ... 
		return FALSE;
	}
		
	return TRUE;
}
Пример #24
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;
	}
}
Пример #25
0
WORD fipImage::getColorsUsed() const {
	return FreeImage_GetColorsUsed(_dib);
}
Пример #26
0
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;
	png_uint_32 width, height;
	int color_type;
	int bit_depth;
	int pixel_depth = 0;	// pixel_depth = bit_depth * channels

	FIBITMAP *dib = NULL;
	png_bytepp row_pointers = NULL;

    fi_ioStructure fio;
    fio.s_handle = handle;
	fio.s_io = io;
    
	if (handle) {
		BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;

		try {		
			// check to see if the file is in fact a PNG file

			BYTE png_check[PNG_BYTES_TO_CHECK];

			io->read_proc(png_check, PNG_BYTES_TO_CHECK, 1, handle);

			if (png_sig_cmp(png_check, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0) {
				return NULL;	// Bad signature
			}
			
			// create the chunk manage structure

			png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, error_handler, warning_handler);

			if (!png_ptr) {
				return NULL;			
			}

			// create the info structure

		    info_ptr = png_create_info_struct(png_ptr);

			if (!info_ptr) {
				png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
				return NULL;
			}

			// init the IO

			png_set_read_fn(png_ptr, &fio, _ReadProc);

            if (setjmp(png_jmpbuf(png_ptr))) {
				png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
				return NULL;
			}

			// because we have already read the signature...

			png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);

			// read the IHDR chunk

			png_read_info(png_ptr, info_ptr);
			png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL);

			// configure the decoder

			FREE_IMAGE_TYPE image_type = FIT_BITMAP;

			if(!ConfigureDecoder(png_ptr, info_ptr, flags, &image_type)) {
				throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
			}

			// update image info

			color_type = png_get_color_type(png_ptr, info_ptr);
			bit_depth = png_get_bit_depth(png_ptr, info_ptr);
			pixel_depth = bit_depth * png_get_channels(png_ptr, info_ptr);

			// create a dib and write the bitmap header
			// set up the dib palette, if needed

			switch (color_type) {
				case PNG_COLOR_TYPE_RGB:
				case PNG_COLOR_TYPE_RGB_ALPHA:
					dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
					break;

				case PNG_COLOR_TYPE_PALETTE:
					dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
					if(dib) {
						png_colorp png_palette = NULL;
						int palette_entries = 0;

						png_get_PLTE(png_ptr,info_ptr, &png_palette, &palette_entries);

						palette_entries = MIN((unsigned)palette_entries, FreeImage_GetColorsUsed(dib));

						// store the palette

						RGBQUAD *palette = FreeImage_GetPalette(dib);
						for(int i = 0; i < palette_entries; i++) {
							palette[i].rgbRed   = png_palette[i].red;
							palette[i].rgbGreen = png_palette[i].green;
							palette[i].rgbBlue  = png_palette[i].blue;
						}
					}
					break;

				case PNG_COLOR_TYPE_GRAY:
					dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);

					if(dib && (pixel_depth <= 8)) {
						RGBQUAD *palette = FreeImage_GetPalette(dib);
						const int palette_entries = 1 << pixel_depth;

						for(int i = 0; i < palette_entries; i++) {
							palette[i].rgbRed   =
							palette[i].rgbGreen =
							palette[i].rgbBlue  = (BYTE)((i * 255) / (palette_entries - 1));
						}
					}
					break;

				default:
					throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
			}

			if(!dib) {
				throw FI_MSG_ERROR_DIB_MEMORY;
			}

			// store the transparency table

			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
				// array of alpha (transparency) entries for palette
				png_bytep trans_alpha = NULL;
				// number of transparent entries
				int num_trans = 0;						
				// graylevel or color sample values of the single transparent color for non-paletted images
				png_color_16p trans_color = NULL;

				png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color);

				if((color_type == PNG_COLOR_TYPE_GRAY) && trans_color) {
					// single transparent color
					if (trans_color->gray < 256) { 
						BYTE table[256]; 
						memset(table, 0xFF, 256); 
						table[trans_color->gray] = 0; 
						FreeImage_SetTransparencyTable(dib, table, 256); 
					}
					// check for a full transparency table, too
					else if ((trans_alpha) && (pixel_depth <= 8)) {
						FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans);
					}

				} else if((color_type == PNG_COLOR_TYPE_PALETTE) && trans_alpha) {
					// transparency table
					FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans);
				}
			}

			// store the background color (only supported for FIT_BITMAP types)

			if ((image_type == FIT_BITMAP) && png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) {
				// Get the background color to draw transparent and alpha images over.
				// Note that even if the PNG file supplies a background, you are not required to
				// use it - you should use the (solid) application background if it has one.

				png_color_16p image_background = NULL;
				RGBQUAD rgbBkColor;

				if (png_get_bKGD(png_ptr, info_ptr, &image_background)) {
					rgbBkColor.rgbRed      = (BYTE)image_background->red;
					rgbBkColor.rgbGreen    = (BYTE)image_background->green;
					rgbBkColor.rgbBlue     = (BYTE)image_background->blue;
					rgbBkColor.rgbReserved = 0;

					FreeImage_SetBackgroundColor(dib, &rgbBkColor);
				}
			}

			// get physical resolution

			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) {
				png_uint_32 res_x, res_y;
				
				// we'll overload this var and use 0 to mean no phys data,
				// since if it's not in meters we can't use it anyway

				int res_unit_type = PNG_RESOLUTION_UNKNOWN;

				png_get_pHYs(png_ptr,info_ptr, &res_x, &res_y, &res_unit_type);

				if (res_unit_type == PNG_RESOLUTION_METER) {
					FreeImage_SetDotsPerMeterX(dib, res_x);
					FreeImage_SetDotsPerMeterY(dib, res_y);
				}
			}

			// get possible ICC profile

			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP)) {
				png_charp profile_name = NULL;
				png_bytep profile_data = NULL;
				png_uint_32 profile_length = 0;
				int  compression_type;

				png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &profile_length);

				// copy ICC profile data (must be done after FreeImage_AllocateHeader)

				FreeImage_CreateICCProfile(dib, profile_data, profile_length);
			}

			// --- header only mode => clean-up and return

			if (header_only) {
				// get possible metadata (it can be located both before and after the image data)
				ReadMetadata(png_ptr, info_ptr, dib);
				if (png_ptr) {
					// clean up after the read, and free any memory allocated - REQUIRED
					png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
				}
				return dib;
			}

			// set the individual row_pointers to point at the correct offsets

			row_pointers = (png_bytepp)malloc(height * sizeof(png_bytep));

			if (!row_pointers) {
				png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
				FreeImage_Unload(dib);
				return NULL;
			}

			// read in the bitmap bits via the pointer table
			// allow loading of PNG with minor errors (such as images with several IDAT chunks)

			for (png_uint_32 k = 0; k < height; k++) {
				row_pointers[height - 1 - k] = FreeImage_GetScanLine(dib, k);
			}

			png_set_benign_errors(png_ptr, 1);
			png_read_image(png_ptr, row_pointers);

			// check if the bitmap contains transparency, if so enable it in the header

			if (FreeImage_GetBPP(dib) == 32) {
				if (FreeImage_GetColorType(dib) == FIC_RGBALPHA) {
					FreeImage_SetTransparent(dib, TRUE);
				} else {
					FreeImage_SetTransparent(dib, FALSE);
				}
			}
				
			// cleanup

			if (row_pointers) {
				free(row_pointers);
				row_pointers = NULL;
			}

			// read the rest of the file, getting any additional chunks in info_ptr

			png_read_end(png_ptr, info_ptr);

			// get possible metadata (it can be located both before and after the image data)

			ReadMetadata(png_ptr, info_ptr, dib);

			if (png_ptr) {
				// clean up after the read, and free any memory allocated - REQUIRED
				png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
			}

			return dib;

		} catch (const char *text) {
			if (png_ptr) {
				png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
			}
			if (row_pointers) {
				free(row_pointers);
			}
			if (dib) {
				FreeImage_Unload(dib);
			}
			FreeImage_OutputMessageProc(s_format_id, text);
			
			return NULL;
		}
	}			

	return NULL;
}
Пример #27
0
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
	png_structp png_ptr = NULL;
	png_infop info_ptr;
	png_uint_32 width, height;
	png_colorp png_palette = NULL;
	int color_type, palette_entries = 0;
	int bit_depth, pixel_depth;		// pixel_depth = bit_depth * channels

	FIBITMAP *dib = NULL;
	RGBQUAD *palette = NULL;		// pointer to dib palette
	png_bytepp  row_pointers = NULL;
	int i;

    fi_ioStructure fio;
    fio.s_handle = handle;
	fio.s_io = io;
    
	if (handle) {
		BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;

		try {		
			// check to see if the file is in fact a PNG file

			BYTE png_check[PNG_BYTES_TO_CHECK];

			io->read_proc(png_check, PNG_BYTES_TO_CHECK, 1, handle);

			if (png_sig_cmp(png_check, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0) {
				return NULL;	// Bad signature
			}
			
			// create the chunk manage structure

			png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, error_handler, warning_handler);

			if (!png_ptr) {
				return NULL;			
			}

			// create the info structure

		    info_ptr = png_create_info_struct(png_ptr);

			if (!info_ptr) {
				png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
				return NULL;
			}

			// init the IO

			png_set_read_fn(png_ptr, &fio, _ReadProc);

            if (setjmp(png_jmpbuf(png_ptr))) {
				png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
				return NULL;
			}

			// because we have already read the signature...

			png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);

			// read the IHDR chunk

			png_read_info(png_ptr, info_ptr);
			png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL);

			pixel_depth = png_get_bit_depth(png_ptr, info_ptr) * png_get_channels(png_ptr, info_ptr);

			// get image data type (assume standard image type)

			FREE_IMAGE_TYPE image_type = FIT_BITMAP;
			if (bit_depth == 16) {
				if ((pixel_depth == 16) && (color_type == PNG_COLOR_TYPE_GRAY)) {
					image_type = FIT_UINT16;
				} 
				else if ((pixel_depth == 48) && (color_type == PNG_COLOR_TYPE_RGB)) {
					image_type = FIT_RGB16;
				} 
				else if ((pixel_depth == 64) && (color_type == PNG_COLOR_TYPE_RGB_ALPHA)) {
					image_type = FIT_RGBA16;
				} else {
					// tell libpng to strip 16 bit/color files down to 8 bits/color
					png_set_strip_16(png_ptr);
					bit_depth = 8;
				}
			}

#ifndef FREEIMAGE_BIGENDIAN
			if((image_type == FIT_UINT16) || (image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) {
				// turn on 16 bit byte swapping
				png_set_swap(png_ptr);
			}
#endif						

			// set some additional flags

			switch(color_type) {
				case PNG_COLOR_TYPE_RGB:
				case PNG_COLOR_TYPE_RGB_ALPHA:
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
					// flip the RGB pixels to BGR (or RGBA to BGRA)

					if(image_type == FIT_BITMAP) {
						png_set_bgr(png_ptr);
					}
#endif
					break;

				case PNG_COLOR_TYPE_PALETTE:
					// expand palette images to the full 8 bits from 2 bits/pixel

					if (pixel_depth == 2) {
						png_set_packing(png_ptr);
						pixel_depth = 8;
					}					

					break;

				case PNG_COLOR_TYPE_GRAY:
					// expand grayscale images to the full 8 bits from 2 bits/pixel
					// but *do not* expand fully transparent palette entries to a full alpha channel

					if (pixel_depth == 2) {
						png_set_expand_gray_1_2_4_to_8(png_ptr);
						pixel_depth = 8;
					}

					break;

				case PNG_COLOR_TYPE_GRAY_ALPHA:
					// expand 8-bit greyscale + 8-bit alpha to 32-bit

					png_set_gray_to_rgb(png_ptr);
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
					// flip the RGBA pixels to BGRA

					png_set_bgr(png_ptr);
#endif
					pixel_depth = 32;

					break;

				default:
					throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
			}

			// unlike the example in the libpng documentation, we have *no* idea where
			// this file may have come from--so if it doesn't have a file gamma, don't
			// do any correction ("do no harm")

			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) {
				double gamma = 0;
				double screen_gamma = 2.2;

				if (png_get_gAMA(png_ptr, info_ptr, &gamma) && ( flags & PNG_IGNOREGAMMA ) != PNG_IGNOREGAMMA) {
					png_set_gamma(png_ptr, screen_gamma, gamma);
				}
			}

			// all transformations have been registered; now update info_ptr data

			png_read_update_info(png_ptr, info_ptr);

			// color type may have changed, due to our transformations

			color_type = png_get_color_type(png_ptr,info_ptr);

			// create a DIB and write the bitmap header
			// set up the DIB palette, if needed

			switch (color_type) {
				case PNG_COLOR_TYPE_RGB:
					png_set_invert_alpha(png_ptr);

					if(image_type == FIT_BITMAP) {
						dib = FreeImage_AllocateHeader(header_only, width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
					} else {
						dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth);
					}
					break;

				case PNG_COLOR_TYPE_RGB_ALPHA:
					if(image_type == FIT_BITMAP) {
						dib = FreeImage_AllocateHeader(header_only, width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
					} else {
						dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth);
					}
					break;

				case PNG_COLOR_TYPE_PALETTE:
					dib = FreeImage_AllocateHeader(header_only, width, height, pixel_depth);

					png_get_PLTE(png_ptr,info_ptr, &png_palette, &palette_entries);

					palette_entries = MIN((unsigned)palette_entries, FreeImage_GetColorsUsed(dib));
					palette = FreeImage_GetPalette(dib);

					// store the palette

					for (i = 0; i < palette_entries; i++) {
						palette[i].rgbRed   = png_palette[i].red;
						palette[i].rgbGreen = png_palette[i].green;
						palette[i].rgbBlue  = png_palette[i].blue;
					}
					break;

				case PNG_COLOR_TYPE_GRAY:
					dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth);

					if(pixel_depth <= 8) {
						palette = FreeImage_GetPalette(dib);
						palette_entries = 1 << pixel_depth;

						for (i = 0; i < palette_entries; i++) {
							palette[i].rgbRed   =
							palette[i].rgbGreen =
							palette[i].rgbBlue  = (BYTE)((i * 255) / (palette_entries - 1));
						}
					}
					break;

				default:
					throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
			}

			// store the transparency table

			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
				// array of alpha (transparency) entries for palette
				png_bytep trans_alpha = NULL;
				// number of transparent entries
				int num_trans = 0;						
				// graylevel or color sample values of the single transparent color for non-paletted images
				png_color_16p trans_color = NULL;

				png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color);

				if((color_type == PNG_COLOR_TYPE_GRAY) && trans_color) {
					// single transparent color
					if (trans_color->gray < palette_entries) { 
						BYTE table[256]; 
						memset(table, 0xFF, palette_entries); 
						table[trans_color->gray] = 0; 
						FreeImage_SetTransparencyTable(dib, table, palette_entries); 
					}
				} else if((color_type == PNG_COLOR_TYPE_PALETTE) && trans_alpha) {
					// transparency table
					FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans);
				}
			}

			// store the background color 

			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) {
				// Get the background color to draw transparent and alpha images over.
				// Note that even if the PNG file supplies a background, you are not required to
				// use it - you should use the (solid) application background if it has one.

				png_color_16p image_background = NULL;
				RGBQUAD rgbBkColor;

				if (png_get_bKGD(png_ptr, info_ptr, &image_background)) {
					rgbBkColor.rgbRed      = (BYTE)image_background->red;
					rgbBkColor.rgbGreen    = (BYTE)image_background->green;
					rgbBkColor.rgbBlue     = (BYTE)image_background->blue;
					rgbBkColor.rgbReserved = 0;

					FreeImage_SetBackgroundColor(dib, &rgbBkColor);
				}
			}

			// get physical resolution

			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) {
				png_uint_32 res_x, res_y;
				
				// we'll overload this var and use 0 to mean no phys data,
				// since if it's not in meters we can't use it anyway

				int res_unit_type = PNG_RESOLUTION_UNKNOWN;

				png_get_pHYs(png_ptr,info_ptr, &res_x, &res_y, &res_unit_type);

				if (res_unit_type == PNG_RESOLUTION_METER) {
					FreeImage_SetDotsPerMeterX(dib, res_x);
					FreeImage_SetDotsPerMeterY(dib, res_y);
				}
			}

			// get possible ICC profile

			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP)) {
				png_charp profile_name = NULL;
				png_bytep profile_data = NULL;
				png_uint_32 profile_length = 0;
				int  compression_type;

				png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &profile_length);

				// copy ICC profile data (must be done after FreeImage_AllocateHeader)

				FreeImage_CreateICCProfile(dib, profile_data, profile_length);
			}

			// --- header only mode => clean-up and return

			if (header_only) {
				// get possible metadata (it can be located both before and after the image data)
				ReadMetadata(png_ptr, info_ptr, dib);
				if (png_ptr) {
					// clean up after the read, and free any memory allocated - REQUIRED
					png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
				}
				return dib;
			}

			// set the individual row_pointers to point at the correct offsets

			row_pointers = (png_bytepp)malloc(height * sizeof(png_bytep));

			if (!row_pointers) {
				png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
				FreeImage_Unload(dib);
				return NULL;
			}

			// read in the bitmap bits via the pointer table
			// allow loading of PNG with minor errors (such as images with several IDAT chunks)

			for (png_uint_32 k = 0; k < height; k++) {
				row_pointers[height - 1 - k] = FreeImage_GetScanLine(dib, k);			
			}

			png_set_benign_errors(png_ptr, 1);
			png_read_image(png_ptr, row_pointers);

			// check if the bitmap contains transparency, if so enable it in the header

			if (FreeImage_GetBPP(dib) == 32) {
				if (FreeImage_GetColorType(dib) == FIC_RGBALPHA) {
					FreeImage_SetTransparent(dib, TRUE);
				} else {
					FreeImage_SetTransparent(dib, FALSE);
				}
			}
				
			// cleanup

			if (row_pointers) {
				free(row_pointers);
				row_pointers = NULL;
			}

			// read the rest of the file, getting any additional chunks in info_ptr

			png_read_end(png_ptr, info_ptr);

			// get possible metadata (it can be located both before and after the image data)

			ReadMetadata(png_ptr, info_ptr, dib);

			if (png_ptr) {
				// clean up after the read, and free any memory allocated - REQUIRED
				png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
			}

			return dib;

		} catch (const char *text) {
			if (png_ptr) {
				png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
			}
			if (row_pointers) {
				free(row_pointers);
			}
			if (dib) {
				FreeImage_Unload(dib);			
			}
			FreeImage_OutputMessageProc(s_format_id, text);
			
			return NULL;
		}
	}			

	return NULL;
}
Пример #28
0
/**
 * @return the number of entries in the color palette
 */
unsigned long fipImage::getPaletteSize() const{

	return FreeImage_GetColorsUsed( pImageData );
}