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