blob: 092b655f7b8a8754456c1fd42c6718fe1231b4f4 [file] [log] [blame]
// ==========================================================
// fipWinImage class implementation
//
// Design and implementation by
// - Hervé Drolon (drolon@infonie.fr)
//
// This file is part of FreeImage 3
//
// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
// THIS DISCLAIMER.
//
// Use at your own risk!
// ==========================================================
#include "FreeImagePlus.h"
#ifdef _WIN32
// marker used for clipboard copy / paste
static inline void
SET_FREEIMAGE_MARKER(BITMAPINFOHEADER *bmih, FIBITMAP *dib) {
// Windows constants goes from 0L to 5L
// Add 0xFF to avoid conflicts
bmih->biCompression = 0xFF + FreeImage_GetImageType(dib);
}
static inline FREE_IMAGE_TYPE
GET_FREEIMAGE_MARKER(BITMAPINFOHEADER *bmih) {
return (FREE_IMAGE_TYPE)(bmih->biCompression - 0xFF);
}
///////////////////////////////////////////////////////////////////
// Construction / Destruction
fipWinImage::fipWinImage(FREE_IMAGE_TYPE image_type, unsigned width, unsigned height, unsigned bpp) : fipImage(image_type, width, height, bpp) {
_display_dib = NULL;
_bDeleteMe = FALSE;
// default tone mapping operator
_tmo = FITMO_DRAGO03;
_tmo_param_1 = 0;
_tmo_param_2 = 0;
_tmo_param_3 = 1;
_tmo_param_4 = 0;
}
fipWinImage::~fipWinImage() {
if(_bDeleteMe) {
FreeImage_Unload(_display_dib);
}
}
void fipWinImage::clear() {
// delete _display_dib
if(_bDeleteMe) {
FreeImage_Unload(_display_dib);
}
_display_dib = NULL;
_bDeleteMe = FALSE;
// delete base class data
fipImage::clear();
}
BOOL fipWinImage::isValid() const {
return fipImage::isValid();
}
///////////////////////////////////////////////////////////////////
// Copying
fipWinImage& fipWinImage::operator=(const fipImage& Image) {
// delete _display_dib
if(_bDeleteMe) {
FreeImage_Unload(_display_dib);
}
_display_dib = NULL;
_bDeleteMe = FALSE;
// clone the base class
fipImage::operator=(Image);
return *this;
}
fipWinImage& fipWinImage::operator=(const fipWinImage& Image) {
if(this != &Image) {
// delete _display_dib
if(_bDeleteMe) {
FreeImage_Unload(_display_dib);
}
_display_dib = NULL;
_bDeleteMe = FALSE;
// copy tmo data
_tmo = Image._tmo;
_tmo_param_1 = Image._tmo_param_1;
_tmo_param_2 = Image._tmo_param_2;
_tmo_param_3 = Image._tmo_param_3;
_tmo_param_4 = Image._tmo_param_4;
// clone the base class
fipImage::operator=(Image);
}
return *this;
}
HANDLE fipWinImage::copyToHandle() const {
HANDLE hMem = NULL;
if(_dib) {
// Get equivalent DIB size
long dib_size = sizeof(BITMAPINFOHEADER);
dib_size += FreeImage_GetColorsUsed(_dib) * sizeof(RGBQUAD);
dib_size += FreeImage_GetPitch(_dib) * FreeImage_GetHeight(_dib);
// Allocate a DIB
hMem = GlobalAlloc(GHND, dib_size);
BYTE *dib = (BYTE*)GlobalLock(hMem);
memset(dib, 0, dib_size);
BYTE *p_dib = (BYTE*)dib;
// Copy the BITMAPINFOHEADER
BITMAPINFOHEADER *bih = FreeImage_GetInfoHeader(_dib);
memcpy(p_dib, bih, sizeof(BITMAPINFOHEADER));
if(FreeImage_GetImageType(_dib) != FIT_BITMAP) {
// this hack is used to store the bitmap type in the biCompression member of the BITMAPINFOHEADER
SET_FREEIMAGE_MARKER((BITMAPINFOHEADER*)p_dib, _dib);
}
p_dib += sizeof(BITMAPINFOHEADER);
// Copy the palette
RGBQUAD *pal = FreeImage_GetPalette(_dib);
memcpy(p_dib, pal, FreeImage_GetColorsUsed(_dib) * sizeof(RGBQUAD));
p_dib += FreeImage_GetColorsUsed(_dib) * sizeof(RGBQUAD);
// Copy the bitmap
BYTE *bits = FreeImage_GetBits(_dib);
memcpy(p_dib, bits, FreeImage_GetPitch(_dib) * FreeImage_GetHeight(_dib));
GlobalUnlock(hMem);
}
return hMem;
}
BOOL fipWinImage::copyFromHandle(HANDLE hMem) {
BYTE *lpVoid = NULL;
BITMAPINFOHEADER *pHead = NULL;
RGBQUAD *pPalette = NULL;
BYTE *bits = NULL;
DWORD bitfields[3] = {0, 0, 0};
// Get a pointer to the bitmap
lpVoid = (BYTE *)GlobalLock(hMem);
// Get a pointer to the bitmap header
pHead = (BITMAPINFOHEADER *)lpVoid;
// Get a pointer to the palette
if(pHead->biBitCount < 16)
pPalette = (RGBQUAD *)(((BYTE *)pHead) + sizeof(BITMAPINFOHEADER));
// Get a pointer to the pixels
bits = ((BYTE*)pHead + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * pHead->biClrUsed);
if(pHead->biCompression == BI_BITFIELDS) {
// Take into account the color masks that specify the red, green, and blue components (16- and 32-bit)
unsigned mask_size = 3 * sizeof(DWORD);
memcpy(&bitfields[0], bits, mask_size);
bits += mask_size;
}
if(lpVoid) {
// Allocate a new FIBITMAP
FREE_IMAGE_TYPE image_type = FIT_BITMAP;
// Use a hack to decide if the clipboard contains non standard bitmaps ...
switch(GET_FREEIMAGE_MARKER(pHead)) {
case FIT_UINT16:
case FIT_INT16:
case FIT_UINT32:
case FIT_INT32:
case FIT_FLOAT:
case FIT_DOUBLE:
case FIT_COMPLEX:
case FIT_RGB16:
case FIT_RGBA16:
case FIT_RGBF:
case FIT_RGBAF:
image_type = GET_FREEIMAGE_MARKER(pHead);
break;
}
if(!setSize(image_type, (WORD)pHead->biWidth, (WORD)pHead->biHeight, pHead->biBitCount, bitfields[2], bitfields[1], bitfields[0])) {
GlobalUnlock(lpVoid);
return FALSE;
}
// Copy the bitmap header
memcpy(FreeImage_GetInfoHeader(_dib), pHead, sizeof(BITMAPINFOHEADER));
// Copy the palette
memcpy(FreeImage_GetPalette(_dib), pPalette, pHead->biClrUsed * sizeof(RGBQUAD));
// Copy the bitmap
memcpy(FreeImage_GetBits(_dib), bits, FreeImage_GetPitch(_dib) * FreeImage_GetHeight(_dib));
GlobalUnlock(lpVoid);
return TRUE;
}
return FALSE;
}
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;
}
BOOL fipWinImage::copyToClipboard(HWND hWndNewOwner) const {
HANDLE hDIB = copyToHandle();
if(OpenClipboard(hWndNewOwner)) {
if(EmptyClipboard()) {
if(SetClipboardData(CF_DIB, hDIB) == NULL) {
MessageBox(hWndNewOwner, "Unable to set Clipboard data", "FreeImage", MB_ICONERROR);
CloseClipboard();
return FALSE;
}
}
}
CloseClipboard();
return TRUE;
}
BOOL fipWinImage::pasteFromClipboard() {
if(!IsClipboardFormatAvailable(CF_DIB))
return FALSE;
if(OpenClipboard(NULL)) {
HANDLE hDIB = GetClipboardData(CF_DIB);
copyFromHandle(hDIB);
CloseClipboard();
return TRUE;
}
CloseClipboard();
return FALSE;
}
///////////////////////////////////////////////////////////////////
// Screen capture
BOOL fipWinImage::captureWindow(HWND hWndApplicationWindow, HWND hWndSelectedWindow) {
int xScreen, yScreen, xshift, yshift;
RECT r;
// Get window size
GetWindowRect(hWndSelectedWindow, &r);
// Check if the window is out of the screen or maximixed
xshift = 0;
yshift = 0;
xScreen = GetSystemMetrics(SM_CXSCREEN);
yScreen = GetSystemMetrics(SM_CYSCREEN);
if(r.right > xScreen)
r.right = xScreen;
if(r.bottom > yScreen)
r.bottom = yScreen;
if(r.left < 0) {
xshift = -r.left;
r.left = 0;
}
if(r.top < 0){
yshift = -r.top;
r.top = 0;
}
int width = r.right - r.left;
int height = r.bottom - r.top;
if(width <= 0 || height <= 0)
return FALSE;
// Hide the application window.
ShowWindow(hWndApplicationWindow, SW_HIDE);
// Bring the window at the top most level
SetWindowPos(hWndSelectedWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
// Give enough time to refresh the window
Sleep(500);
// Prepare the DCs
HDC dstDC = GetDC(NULL);
HDC srcDC = GetWindowDC(hWndSelectedWindow); // full window (GetDC(hWndSelectedWindow) = clientarea)
HDC memDC = CreateCompatibleDC(dstDC);
// Copy the screen to the bitmap
HBITMAP bm = CreateCompatibleBitmap(dstDC, width, height);
HBITMAP oldbm = (HBITMAP)SelectObject(memDC, bm);
BitBlt(memDC, 0, 0, width, height, srcDC, xshift, yshift, SRCCOPY);
// Redraw the application window.
ShowWindow(hWndApplicationWindow, SW_SHOW);
// Restore the position
SetWindowPos(hWndSelectedWindow, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
SetWindowPos(hWndApplicationWindow, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
// Convert the HBITMAP to a FIBITMAP
copyFromBitmap(bm);
// Free objects
DeleteObject(SelectObject(memDC, oldbm));
DeleteDC(memDC);
// Convert 32-bit images to 24-bit
if(getBitsPerPixel() == 32) {
convertTo24Bits();
}
return TRUE;
}
///////////////////////////////////////////////////////////////////
// Painting operations
void fipWinImage::drawEx(HDC hDC, RECT& rcDest, BOOL useFileBkg, RGBQUAD *appBkColor, FIBITMAP *bg) const {
// Convert to a standard bitmap if needed
if(_bHasChanged) {
if(_bDeleteMe) {
FreeImage_Unload(_display_dib);
_display_dib = NULL;
_bDeleteMe = FALSE;
}
FREE_IMAGE_TYPE image_type = getImageType();
if(image_type == FIT_BITMAP) {
BOOL bHasBackground = FreeImage_HasBackgroundColor(_dib);
BOOL bIsTransparent = FreeImage_IsTransparent(_dib);
if(!bIsTransparent && (!bHasBackground || !useFileBkg)) {
// Copy pointer
_display_dib = _dib;
}
else {
// Create the transparent / alpha blended image
_display_dib = FreeImage_Composite(_dib, useFileBkg, appBkColor, bg);
if(_display_dib) {
// Remember to delete _display_dib
_bDeleteMe = TRUE;
} else {
// Something failed: copy pointers
_display_dib = _dib;
}
}
} else {
// Convert to a standard dib for display
if(image_type == FIT_COMPLEX) {
// Convert to type FIT_DOUBLE
FIBITMAP *dib_double = FreeImage_GetComplexChannel(_dib, FICC_MAG);
// Convert to a standard bitmap (linear scaling)
_display_dib = FreeImage_ConvertToStandardType(dib_double, TRUE);
// Free image of type FIT_DOUBLE
FreeImage_Unload(dib_double);
} else if((image_type == FIT_RGBF) || (image_type == FIT_RGBAF) || (image_type == FIT_RGB16)) {
// Apply a tone mapping algorithm and convert to 24-bit
switch(_tmo) {
case FITMO_REINHARD05:
_display_dib = FreeImage_TmoReinhard05Ex(_dib, _tmo_param_1, _tmo_param_2, _tmo_param_3, _tmo_param_4);
break;
default:
_display_dib = FreeImage_ToneMapping(_dib, _tmo, _tmo_param_1, _tmo_param_2);
break;
}
} else if(image_type == FIT_RGBA16) {
// Convert to 32-bit
FIBITMAP *dib32 = FreeImage_ConvertTo32Bits(_dib);
if(dib32) {
// Create the transparent / alpha blended image
_display_dib = FreeImage_Composite(dib32, useFileBkg, appBkColor, bg);
FreeImage_Unload(dib32);
}
} else {
// Other cases: convert to a standard bitmap (linear scaling)
_display_dib = FreeImage_ConvertToStandardType(_dib, TRUE);
}
// Remember to delete _display_dib
_bDeleteMe = TRUE;
}
_bHasChanged = FALSE;
}
// Draw the dib
SetStretchBltMode(hDC, COLORONCOLOR);
StretchDIBits(hDC, rcDest.left, rcDest.top,
rcDest.right-rcDest.left, rcDest.bottom-rcDest.top,
0, 0, FreeImage_GetWidth(_display_dib), FreeImage_GetHeight(_display_dib),
FreeImage_GetBits(_display_dib), FreeImage_GetInfo(_display_dib), DIB_RGB_COLORS, SRCCOPY);
}
void fipWinImage::setToneMappingOperator(FREE_IMAGE_TMO tmo, double first_param, double second_param, double third_param, double fourth_param) {
// avoid costly operations if possible ...
if((_tmo != tmo) || (_tmo_param_1 != first_param) || (_tmo_param_2 != second_param) || (_tmo_param_3 != third_param) || (_tmo_param_4 != fourth_param)) {
_tmo = tmo;
_tmo_param_1 = first_param;
_tmo_param_2 = second_param;
_tmo_param_3 = third_param;
_tmo_param_4 = fourth_param;
FREE_IMAGE_TYPE image_type = getImageType();
switch(image_type) {
case FIT_RGBF:
case FIT_RGBAF:
case FIT_RGB16:
case FIT_RGBA16:
_bHasChanged = TRUE;
break;
default:
break;
}
}
}
void fipWinImage::getToneMappingOperator(FREE_IMAGE_TMO *tmo, double *first_param, double *second_param, double *third_param, double *fourth_param) const {
*tmo = _tmo;
*first_param = _tmo_param_1;
*second_param = _tmo_param_2;
*third_param = _tmo_param_3;
*fourth_param = _tmo_param_4;
}
#endif // _WIN32