You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
497 lines
14 KiB
497 lines
14 KiB
// ==========================================================
|
|
// 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};
|
|
|
|
if(!hMem) {
|
|
return FALSE;
|
|
}
|
|
|
|
// 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 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)) {
|
|
BOOL bResult = FALSE;
|
|
HANDLE hDIB = GetClipboardData(CF_DIB);
|
|
if(hDIB) {
|
|
bResult = copyFromHandle(hDIB);
|
|
}
|
|
CloseClipboard();
|
|
return bResult;
|
|
}
|
|
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
|