1 // ==========================================================
2 // fipWinImage class implementation
3 //
4 // Design and implementation by
5 // - Herv� Drolon (drolon@infonie.fr)
6 //
7 // This file is part of FreeImage 3
8 //
9 // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
10 // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
11 // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
12 // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
13 // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
14 // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
15 // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
16 // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
17 // THIS DISCLAIMER.
18 //
19 // Use at your own risk!
20 // ==========================================================
21
22 #include "FreeImagePlus.h"
23
24 #ifdef _WIN32
25
26 // marker used for clipboard copy / paste
27
28 static inline void
SET_FREEIMAGE_MARKER(BITMAPINFOHEADER * bmih,FIBITMAP * dib)29 SET_FREEIMAGE_MARKER(BITMAPINFOHEADER *bmih, FIBITMAP *dib) {
30 // Windows constants goes from 0L to 5L
31 // Add 0xFF to avoid conflicts
32 bmih->biCompression = 0xFF + FreeImage_GetImageType(dib);
33 }
34
35 static inline FREE_IMAGE_TYPE
GET_FREEIMAGE_MARKER(BITMAPINFOHEADER * bmih)36 GET_FREEIMAGE_MARKER(BITMAPINFOHEADER *bmih) {
37 return (FREE_IMAGE_TYPE)(bmih->biCompression - 0xFF);
38 }
39
40 ///////////////////////////////////////////////////////////////////
41 // Construction / Destruction
42
fipWinImage(FREE_IMAGE_TYPE image_type,unsigned width,unsigned height,unsigned bpp)43 fipWinImage::fipWinImage(FREE_IMAGE_TYPE image_type, unsigned width, unsigned height, unsigned bpp) : fipImage(image_type, width, height, bpp) {
44 _display_dib = NULL;
45 _bDeleteMe = FALSE;
46 // default tone mapping operator
47 _tmo = FITMO_DRAGO03;
48 _tmo_param_1 = 0;
49 _tmo_param_2 = 0;
50 _tmo_param_3 = 1;
51 _tmo_param_4 = 0;
52 }
53
~fipWinImage()54 fipWinImage::~fipWinImage() {
55 if(_bDeleteMe) {
56 FreeImage_Unload(_display_dib);
57 }
58 }
59
clear()60 void fipWinImage::clear() {
61 // delete _display_dib
62 if(_bDeleteMe) {
63 FreeImage_Unload(_display_dib);
64 }
65 _display_dib = NULL;
66 _bDeleteMe = FALSE;
67 // delete base class data
68 fipImage::clear();
69 }
70
isValid() const71 BOOL fipWinImage::isValid() const {
72 return fipImage::isValid();
73 }
74
75 ///////////////////////////////////////////////////////////////////
76 // Copying
77
operator =(const fipImage & Image)78 fipWinImage& fipWinImage::operator=(const fipImage& Image) {
79 // delete _display_dib
80 if(_bDeleteMe) {
81 FreeImage_Unload(_display_dib);
82 }
83 _display_dib = NULL;
84 _bDeleteMe = FALSE;
85 // clone the base class
86 fipImage::operator=(Image);
87
88 return *this;
89 }
90
operator =(const fipWinImage & Image)91 fipWinImage& fipWinImage::operator=(const fipWinImage& Image) {
92 if(this != &Image) {
93 // delete _display_dib
94 if(_bDeleteMe) {
95 FreeImage_Unload(_display_dib);
96 }
97 _display_dib = NULL;
98 _bDeleteMe = FALSE;
99 // copy tmo data
100 _tmo = Image._tmo;
101 _tmo_param_1 = Image._tmo_param_1;
102 _tmo_param_2 = Image._tmo_param_2;
103 _tmo_param_3 = Image._tmo_param_3;
104 _tmo_param_4 = Image._tmo_param_4;
105
106 // clone the base class
107 fipImage::operator=(Image);
108 }
109 return *this;
110 }
111
copyToHandle() const112 HANDLE fipWinImage::copyToHandle() const {
113 HANDLE hMem = NULL;
114
115 if(_dib) {
116
117 // Get equivalent DIB size
118 long dib_size = sizeof(BITMAPINFOHEADER);
119 dib_size += FreeImage_GetColorsUsed(_dib) * sizeof(RGBQUAD);
120 dib_size += FreeImage_GetPitch(_dib) * FreeImage_GetHeight(_dib);
121
122 // Allocate a DIB
123 hMem = GlobalAlloc(GHND, dib_size);
124 BYTE *dib = (BYTE*)GlobalLock(hMem);
125
126 memset(dib, 0, dib_size);
127
128 BYTE *p_dib = (BYTE*)dib;
129
130 // Copy the BITMAPINFOHEADER
131
132 BITMAPINFOHEADER *bih = FreeImage_GetInfoHeader(_dib);
133 memcpy(p_dib, bih, sizeof(BITMAPINFOHEADER));
134 if(FreeImage_GetImageType(_dib) != FIT_BITMAP) {
135 // this hack is used to store the bitmap type in the biCompression member of the BITMAPINFOHEADER
136 SET_FREEIMAGE_MARKER((BITMAPINFOHEADER*)p_dib, _dib);
137 }
138 p_dib += sizeof(BITMAPINFOHEADER);
139
140 // Copy the palette
141
142 RGBQUAD *pal = FreeImage_GetPalette(_dib);
143 memcpy(p_dib, pal, FreeImage_GetColorsUsed(_dib) * sizeof(RGBQUAD));
144 p_dib += FreeImage_GetColorsUsed(_dib) * sizeof(RGBQUAD);
145
146 // Copy the bitmap
147
148 BYTE *bits = FreeImage_GetBits(_dib);
149 memcpy(p_dib, bits, FreeImage_GetPitch(_dib) * FreeImage_GetHeight(_dib));
150
151 GlobalUnlock(hMem);
152 }
153
154 return hMem;
155 }
156
copyFromHandle(HANDLE hMem)157 BOOL fipWinImage::copyFromHandle(HANDLE hMem) {
158 BYTE *lpVoid = NULL;
159 BITMAPINFOHEADER *pHead = NULL;
160 RGBQUAD *pPalette = NULL;
161 BYTE *bits = NULL;
162 DWORD bitfields[3] = {0, 0, 0};
163
164 if(!hMem) {
165 return FALSE;
166 }
167
168 // Get a pointer to the bitmap
169 lpVoid = (BYTE *)GlobalLock(hMem);
170
171 // Get a pointer to the bitmap header
172 pHead = (BITMAPINFOHEADER *)lpVoid;
173
174 // Get a pointer to the palette
175 if(pHead->biBitCount < 16) {
176 pPalette = (RGBQUAD *)(((BYTE *)pHead) + sizeof(BITMAPINFOHEADER));
177 }
178
179 // Get a pointer to the pixels
180 bits = ((BYTE*)pHead + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * pHead->biClrUsed);
181
182 if(pHead->biCompression == BI_BITFIELDS) {
183 // Take into account the color masks that specify the red, green, and blue components (16- and 32-bit)
184 unsigned mask_size = 3 * sizeof(DWORD);
185 memcpy(&bitfields[0], bits, mask_size);
186 bits += mask_size;
187 }
188
189 if(lpVoid) {
190
191 // Allocate a new FIBITMAP
192
193 FREE_IMAGE_TYPE image_type = FIT_BITMAP;
194 // Use a hack to decide if the clipboard contains non standard bitmaps ...
195 switch(GET_FREEIMAGE_MARKER(pHead)) {
196 case FIT_UINT16:
197 case FIT_INT16:
198 case FIT_UINT32:
199 case FIT_INT32:
200 case FIT_FLOAT:
201 case FIT_DOUBLE:
202 case FIT_COMPLEX:
203 case FIT_RGB16:
204 case FIT_RGBA16:
205 case FIT_RGBF:
206 case FIT_RGBAF:
207 image_type = GET_FREEIMAGE_MARKER(pHead);
208 break;
209 }
210 if(!setSize(image_type, (WORD)pHead->biWidth, (WORD)pHead->biHeight, pHead->biBitCount, bitfields[2], bitfields[1], bitfields[0])) {
211 GlobalUnlock(lpVoid);
212 return FALSE;
213 }
214
215 // Copy the palette
216 memcpy(FreeImage_GetPalette(_dib), pPalette, pHead->biClrUsed * sizeof(RGBQUAD));
217
218 // Copy the bitmap
219 memcpy(FreeImage_GetBits(_dib), bits, FreeImage_GetPitch(_dib) * FreeImage_GetHeight(_dib));
220
221 GlobalUnlock(lpVoid);
222
223 return TRUE;
224 }
225
226 return FALSE;
227 }
228
copyFromBitmap(HBITMAP hbmp)229 BOOL fipWinImage::copyFromBitmap(HBITMAP hbmp) {
230 if(hbmp) {
231 int Success;
232 BITMAP bm;
233 // Get informations about the bitmap
234 GetObject(hbmp, sizeof(BITMAP), (LPSTR) &bm);
235 // Create the image
236 setSize(FIT_BITMAP, (WORD)bm.bmWidth, (WORD)bm.bmHeight, (WORD)bm.bmBitsPixel);
237
238 // The GetDIBits function clears the biClrUsed and biClrImportant BITMAPINFO members (dont't know why)
239 // So we save these infos below. This is needed for palettized images only.
240 int nColors = FreeImage_GetColorsUsed(_dib);
241
242 // Create a device context for the bitmap
243 HDC dc = GetDC(NULL);
244 // Copy the pixels
245 Success = GetDIBits(dc, // handle to DC
246 hbmp, // handle to bitmap
247 0, // first scan line to set
248 FreeImage_GetHeight(_dib), // number of scan lines to copy
249 FreeImage_GetBits(_dib), // array for bitmap bits
250 FreeImage_GetInfo(_dib), // bitmap data buffer
251 DIB_RGB_COLORS // RGB
252 );
253 if(Success == 0) {
254 FreeImage_OutputMessageProc(FIF_UNKNOWN, "Error : GetDIBits failed");
255 ReleaseDC(NULL, dc);
256 return FALSE;
257 }
258 ReleaseDC(NULL, dc);
259
260 // restore BITMAPINFO members
261
262 FreeImage_GetInfoHeader(_dib)->biClrUsed = nColors;
263 FreeImage_GetInfoHeader(_dib)->biClrImportant = nColors;
264
265 return TRUE;
266 }
267
268 return FALSE;
269 }
270
copyToClipboard(HWND hWndNewOwner) const271 BOOL fipWinImage::copyToClipboard(HWND hWndNewOwner) const {
272 HANDLE hDIB = copyToHandle();
273
274 if(OpenClipboard(hWndNewOwner)) {
275 if(EmptyClipboard()) {
276 if(SetClipboardData(CF_DIB, hDIB) == NULL) {
277 MessageBox(hWndNewOwner, "Unable to set Clipboard data", "FreeImage", MB_ICONERROR);
278 CloseClipboard();
279 return FALSE;
280 }
281 }
282 }
283 CloseClipboard();
284
285 return TRUE;
286 }
287
pasteFromClipboard()288 BOOL fipWinImage::pasteFromClipboard() {
289 if(!IsClipboardFormatAvailable(CF_DIB)) {
290 return FALSE;
291 }
292
293 if(OpenClipboard(NULL)) {
294 BOOL bResult = FALSE;
295 HANDLE hDIB = GetClipboardData(CF_DIB);
296 if(hDIB) {
297 bResult = copyFromHandle(hDIB);
298 }
299 CloseClipboard();
300 return bResult;
301 }
302 CloseClipboard();
303
304 return FALSE;
305 }
306
307 ///////////////////////////////////////////////////////////////////
308 // Screen capture
309
captureWindow(HWND hWndApplicationWindow,HWND hWndSelectedWindow)310 BOOL fipWinImage::captureWindow(HWND hWndApplicationWindow, HWND hWndSelectedWindow) {
311 int xScreen, yScreen, xshift, yshift;
312 RECT r;
313
314 // Get window size
315 GetWindowRect(hWndSelectedWindow, &r);
316
317 // Check if the window is out of the screen or maximixed
318 xshift = 0;
319 yshift = 0;
320 xScreen = GetSystemMetrics(SM_CXSCREEN);
321 yScreen = GetSystemMetrics(SM_CYSCREEN);
322 if(r.right > xScreen) {
323 r.right = xScreen;
324 }
325 if(r.bottom > yScreen) {
326 r.bottom = yScreen;
327 }
328 if(r.left < 0) {
329 xshift = -r.left;
330 r.left = 0;
331 }
332 if(r.top < 0) {
333 yshift = -r.top;
334 r.top = 0;
335 }
336
337 int width = r.right - r.left;
338 int height = r.bottom - r.top;
339
340 if(width <= 0 || height <= 0) {
341 return FALSE;
342 }
343
344 // Hide the application window.
345 ShowWindow(hWndApplicationWindow, SW_HIDE);
346 // Bring the window at the top most level
347 SetWindowPos(hWndSelectedWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
348 // Give enough time to refresh the window
349 Sleep(500);
350
351 // Prepare the DCs
352 HDC dstDC = GetDC(NULL);
353 HDC srcDC = GetWindowDC(hWndSelectedWindow); // full window (GetDC(hWndSelectedWindow) = clientarea)
354 HDC memDC = CreateCompatibleDC(dstDC);
355
356 // Copy the screen to the bitmap
357 HBITMAP bm = CreateCompatibleBitmap(dstDC, width, height);
358 HBITMAP oldbm = (HBITMAP)SelectObject(memDC, bm);
359 BitBlt(memDC, 0, 0, width, height, srcDC, xshift, yshift, SRCCOPY);
360
361 // Redraw the application window.
362 ShowWindow(hWndApplicationWindow, SW_SHOW);
363
364 // Restore the position
365 SetWindowPos(hWndSelectedWindow, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
366 SetWindowPos(hWndApplicationWindow, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
367
368 // Convert the HBITMAP to a FIBITMAP
369 copyFromBitmap(bm);
370
371 // Free objects
372 DeleteObject(SelectObject(memDC, oldbm));
373 DeleteDC(memDC);
374
375 // Convert 32-bit images to 24-bit
376 if(getBitsPerPixel() == 32) {
377 convertTo24Bits();
378 }
379
380 return TRUE;
381 }
382
383
384 ///////////////////////////////////////////////////////////////////
385 // Painting operations
386
drawEx(HDC hDC,RECT & rcDest,BOOL useFileBkg,RGBQUAD * appBkColor,FIBITMAP * bg) const387 void fipWinImage::drawEx(HDC hDC, RECT& rcDest, BOOL useFileBkg, RGBQUAD *appBkColor, FIBITMAP *bg) const {
388 // Convert to a standard bitmap if needed
389 if(_bHasChanged) {
390 if(_bDeleteMe) {
391 FreeImage_Unload(_display_dib);
392 _display_dib = NULL;
393 _bDeleteMe = FALSE;
394 }
395
396 FREE_IMAGE_TYPE image_type = getImageType();
397 if(image_type == FIT_BITMAP) {
398 BOOL bHasBackground = FreeImage_HasBackgroundColor(_dib);
399 BOOL bIsTransparent = FreeImage_IsTransparent(_dib);
400
401 if(!bIsTransparent && (!bHasBackground || !useFileBkg)) {
402 // Copy pointer
403 _display_dib = _dib;
404 }
405 else {
406 // Create the transparent / alpha blended image
407 _display_dib = FreeImage_Composite(_dib, useFileBkg, appBkColor, bg);
408 if(_display_dib) {
409 // Remember to delete _display_dib
410 _bDeleteMe = TRUE;
411 } else {
412 // Something failed: copy pointers
413 _display_dib = _dib;
414 }
415 }
416 } else {
417 // Convert to a standard dib for display
418
419 if(image_type == FIT_COMPLEX) {
420 // Convert to type FIT_DOUBLE
421 FIBITMAP *dib_double = FreeImage_GetComplexChannel(_dib, FICC_MAG);
422 // Convert to a standard bitmap (linear scaling)
423 _display_dib = FreeImage_ConvertToStandardType(dib_double, TRUE);
424 // Free image of type FIT_DOUBLE
425 FreeImage_Unload(dib_double);
426 } else if((image_type == FIT_RGBF) || (image_type == FIT_RGBAF) || (image_type == FIT_RGB16)) {
427 // Apply a tone mapping algorithm and convert to 24-bit
428 switch(_tmo) {
429 case FITMO_REINHARD05:
430 _display_dib = FreeImage_TmoReinhard05Ex(_dib, _tmo_param_1, _tmo_param_2, _tmo_param_3, _tmo_param_4);
431 break;
432 default:
433 _display_dib = FreeImage_ToneMapping(_dib, _tmo, _tmo_param_1, _tmo_param_2);
434 break;
435 }
436 } else if(image_type == FIT_RGBA16) {
437 // Convert to 32-bit
438 FIBITMAP *dib32 = FreeImage_ConvertTo32Bits(_dib);
439 if(dib32) {
440 // Create the transparent / alpha blended image
441 _display_dib = FreeImage_Composite(dib32, useFileBkg, appBkColor, bg);
442 FreeImage_Unload(dib32);
443 }
444 } else {
445 // Other cases: convert to a standard bitmap (linear scaling)
446 _display_dib = FreeImage_ConvertToStandardType(_dib, TRUE);
447 }
448 // Remember to delete _display_dib
449 _bDeleteMe = TRUE;
450 }
451
452 _bHasChanged = FALSE;
453 }
454
455 // Draw the dib
456 SetStretchBltMode(hDC, COLORONCOLOR);
457 StretchDIBits(hDC, rcDest.left, rcDest.top,
458 rcDest.right-rcDest.left, rcDest.bottom-rcDest.top,
459 0, 0, FreeImage_GetWidth(_display_dib), FreeImage_GetHeight(_display_dib),
460 FreeImage_GetBits(_display_dib), FreeImage_GetInfo(_display_dib), DIB_RGB_COLORS, SRCCOPY);
461
462 }
463
setToneMappingOperator(FREE_IMAGE_TMO tmo,double first_param,double second_param,double third_param,double fourth_param)464 void fipWinImage::setToneMappingOperator(FREE_IMAGE_TMO tmo, double first_param, double second_param, double third_param, double fourth_param) {
465 // avoid costly operations if possible ...
466 if((_tmo != tmo) || (_tmo_param_1 != first_param) || (_tmo_param_2 != second_param) || (_tmo_param_3 != third_param) || (_tmo_param_4 != fourth_param)) {
467 _tmo = tmo;
468 _tmo_param_1 = first_param;
469 _tmo_param_2 = second_param;
470 _tmo_param_3 = third_param;
471 _tmo_param_4 = fourth_param;
472
473 FREE_IMAGE_TYPE image_type = getImageType();
474 switch(image_type) {
475 case FIT_RGBF:
476 case FIT_RGBAF:
477 case FIT_RGB16:
478 case FIT_RGBA16:
479 _bHasChanged = TRUE;
480 break;
481 default:
482 break;
483 }
484 }
485 }
486
getToneMappingOperator(FREE_IMAGE_TMO * tmo,double * first_param,double * second_param,double * third_param,double * fourth_param) const487 void fipWinImage::getToneMappingOperator(FREE_IMAGE_TMO *tmo, double *first_param, double *second_param, double *third_param, double *fourth_param) const {
488 *tmo = _tmo;
489 *first_param = _tmo_param_1;
490 *second_param = _tmo_param_2;
491 *third_param = _tmo_param_3;
492 *fourth_param = _tmo_param_4;
493 }
494
495
496 #endif // _WIN32
497