// ========================================================== // 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