summaryrefslogtreecommitdiff
path: root/plugins/SendScreenshotPlus/src/Utils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/SendScreenshotPlus/src/Utils.cpp')
-rw-r--r--plugins/SendScreenshotPlus/src/Utils.cpp824
1 files changed, 412 insertions, 412 deletions
diff --git a/plugins/SendScreenshotPlus/src/Utils.cpp b/plugins/SendScreenshotPlus/src/Utils.cpp
index 1d0d92f5ea..bc543d1024 100644
--- a/plugins/SendScreenshotPlus/src/Utils.cpp
+++ b/plugins/SendScreenshotPlus/src/Utils.cpp
@@ -1,412 +1,412 @@
-/*
-
-Miranda NG: the free IM client for Microsoft* Windows*
-
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
-Copyright (c) 2000-09 Miranda ICQ/IM project,
-
-This file is part of Send Screenshot Plus, a Miranda IM plugin.
-Copyright (c) 2010 Ing.U.Horn
-
-Parts of this file based on original sorce code
-(c) 2004-2006 Sérgio Vieira Rolanski (portet from Borland C++)
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-*/
-
-#include "stdafx.h"
-
-void ComboBox_SelectItem(HWND hCombo, LPARAM data)
-{
- for (int i = 0;; i++) {
- LPARAM itemData = ComboBox_GetItemData(hCombo, i);
- if (itemData == data) {
- ComboBox_SetCurSel(hCombo, i);
- return;
- }
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// MonitorInfoEnum
-
-static BOOL CALLBACK MonitorInfoEnumProc(HMONITOR hMonitor, HDC, LPRECT, LPARAM dwData)
-{
- MONITORS* monitors = (MONITORS*)dwData;
- ++monitors->count;
- monitors->info = (MONITORINFOEX*)mir_realloc(monitors->info, sizeof(MONITORINFOEX)*monitors->count);
- monitors->info[monitors->count - 1].cbSize = sizeof(MONITORINFOEX);
- if (!GetMonitorInfo(hMonitor, (LPMONITORINFO)(monitors->info + monitors->count - 1)))
- return FALSE; // stop enumeration if error
-
- return TRUE;
-}
-
-size_t MonitorInfoEnum(MONITORINFOEX* &myMonitors, RECT &virtualScreen)
-{
- MONITORS tmp = { 0, nullptr };
- if (EnumDisplayMonitors(nullptr, nullptr, MonitorInfoEnumProc, (LPARAM)&tmp)) {
- myMonitors = tmp.info;
- memset(&virtualScreen, 0, sizeof(virtualScreen));
- for (size_t i = 0; i < tmp.count; ++i) {
- UnionRect(&virtualScreen, &virtualScreen, &tmp.info[i].rcMonitor);
- }
- return tmp.count;
- }
-
- mir_free(tmp.info);
- return 0;
-}
-
-FIBITMAP* CreateDIBFromDC(HDC hDC, const RECT* rect, HWND hCapture = nullptr);
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// capture window as FIBITMAP - caller must FreeImage_Unload(dib)
-
-FIBITMAP* CaptureWindow(HWND hCapture, BOOL bClientArea, BOOL bIndirectCapture)
-{
- FIBITMAP* dib;
- HWND hForegroundWin;
- RECT rect; // cropping rect
-
- if (!hCapture || !IsWindow(hCapture))
- return nullptr;
-
- hForegroundWin = GetForegroundWindow(); // old foreground window
- SetForegroundWindow(hCapture); // force target foreground
- BringWindowToTop(hCapture); // bring it to top as well
-
- // redraw window to prevent runtime artifacts in picture
- UpdateWindow(hCapture);
-
- HWND hParent = GetAncestor(hCapture, GA_PARENT);
- if (hParent && !IsChild(hParent, hCapture))
- hParent = nullptr;
- if (bIndirectCapture) {
- intptr_t wastopmost = GetWindowLongPtr(hCapture, GWL_EXSTYLE)&WS_EX_TOPMOST;
- if (!wastopmost)
- SetWindowPos(hCapture, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
- if (bClientArea) {
- GetClientRect(hCapture, &rect);
- ClientToScreen(hCapture, (POINT*)&rect);
- rect.right += rect.left; rect.bottom += rect.top;
- }
- else
- GetWindowRect(hCapture, &rect);
- dib = CaptureMonitor(nullptr, &rect);
- if (!wastopmost)
- SetWindowPos(hCapture, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
- }
- else {
- HDC hDCsrc;
- GetWindowRect(hCapture, &rect);
- if (hParent)
- hDCsrc = GetDC(hCapture); // hCapture is part of a window, capture that
- else
- hDCsrc = GetWindowDC(hCapture); // entire window w/ title bar
- rect.right = ABS(rect.right - rect.left);
- rect.bottom = ABS(rect.bottom - rect.top);
- rect.left = rect.top = 0;
- // capture window and get FIBITMAP
- dib = CreateDIBFromDC(hDCsrc, &rect, hCapture);
- ReleaseDC(hCapture, hDCsrc);
-
- // we could capture directly, but doing so breaks GetWindowRgn() and also includes artifacts...
- if (bClientArea) {
- GetWindowRect(hCapture, &rect);
- RECT rectCA; GetClientRect(hCapture, &rectCA);
- ClientToScreen(hCapture, (POINT*)&rectCA);
- rectCA.left = ABS(rectCA.left - rect.left);
- rectCA.top = ABS(rectCA.top - rect.top);
- rectCA.right += rectCA.left; rectCA.bottom += rectCA.top;
-
- // crop the window to ClientArea
- FIBITMAP* dibClient = FreeImage_Copy(dib, rectCA.left, rectCA.top, rectCA.right, rectCA.bottom);
- FreeImage_Unload(dib);
- dib = dibClient;
- }
- }
-
- // restore previous foreground window
- if (hForegroundWin) {
- SetForegroundWindow(hForegroundWin);
- BringWindowToTop(hForegroundWin);
- }
- return dib;
-}
-
-FIBITMAP* CaptureMonitor(const wchar_t* szDevice, const RECT* cropRect/*=NULL*/)
-{
- HDC hScrDC;
- RECT rect;
-
- // get screen resolution
- if (!szDevice) {
- hScrDC = CreateDC(L"DISPLAY", nullptr, nullptr, nullptr);
- rect.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
- rect.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
- rect.right = GetSystemMetrics(SM_XVIRTUALSCREEN) + GetSystemMetrics(SM_CXVIRTUALSCREEN);
- rect.bottom = GetSystemMetrics(SM_YVIRTUALSCREEN) + GetSystemMetrics(SM_CYVIRTUALSCREEN);
- }
- else {
- hScrDC = CreateDC(szDevice, nullptr, nullptr, nullptr);
- rect.left = rect.top = 0;
- rect.right = GetDeviceCaps(hScrDC, HORZRES);
- rect.bottom = GetDeviceCaps(hScrDC, VERTRES);
- }
- if (cropRect) {
- if (cropRect->left > rect.left) rect.left = cropRect->left;
- if (cropRect->top > rect.top) rect.top = cropRect->top;
- if (cropRect->right < rect.right) rect.right = cropRect->right;
- if (cropRect->bottom < rect.bottom) rect.bottom = cropRect->bottom;
- }
-
- FIBITMAP *dib = CreateDIBFromDC(hScrDC, &rect);
- ReleaseDC(nullptr, hScrDC);
- return dib;
-}
-
-FIBITMAP* CreateDIBFromDC(HDC hDC, const RECT* rect, HWND hCapture/*=NULL*/)
-{
- long width = rect->right - rect->left;
- long height = rect->bottom - rect->top;
-
- // create a DC for the screen and create
- // a memory DC compatible to screen DC
- HDC hScrDC = hDC;
- if (!hScrDC)
- hScrDC = GetDC(hCapture);
- HDC hMemDC = CreateCompatibleDC(hScrDC);
- // create a bitmap compatible with the screen DC
- HBITMAP hBitmap = CreateCompatibleBitmap(hScrDC, width, height);
- // select new bitmap into memory DC
- SelectObject(hMemDC, hBitmap);
-
- if (hCapture && hDC)
- PrintWindow(hCapture, hMemDC, 0);
- else // bitblt screen DC to memory DC
- BitBlt(hMemDC, 0, 0, width, height, hScrDC, rect->left, rect->top, CAPTUREBLT | SRCCOPY);
-
- FIBITMAP *dib = FreeImage_CreateDIBFromHBITMAP(hBitmap);
-
- // alpha channel from window is always wrong and sometimes even for desktop (Win7, no aero)
- // coz GDI do not draw all in alpha mode.
- // we have to create our own new alpha channel.
- bool bFixAlpha = true;
- bool bInvert = false;
- HBRUSH hBr = CreateSolidBrush(RGB(255, 255, 255)); // Create a SolidBrush object for non transparent area
- HBITMAP hMask = CreateBitmap(width, height, 1, 1, nullptr); // Create monochrome (1 bit) B+W mask bitmap.
- HDC hMaskDC = CreateCompatibleDC(nullptr);
- SelectBitmap(hMaskDC, hMask);
- HRGN hRgn = CreateRectRgn(0, 0, 0, 0);
- if (hCapture && GetWindowRgn(hCapture, hRgn) == ERROR) {
- if ((GetWindowLongPtr(hCapture, GWL_EXSTYLE)&WS_EX_LAYERED)) {
- uint8_t bAlpha = 0;
- COLORREF crKey = 0x00000000;
- DWORD dwFlags = 0;
- if (GetLayeredWindowAttributes(hCapture, &crKey, &bAlpha, &dwFlags)) {
- // per window transparency (like fading in a whole window)
- if ((dwFlags&LWA_COLORKEY)) {
- SetBkColor(hMemDC, crKey);
- BitBlt(hMaskDC, 0, 0, width, height, hMemDC, rect->left, rect->top, SRCCOPY);
- bInvert = true;
- }
- else if ((dwFlags&LWA_ALPHA)) {
- bFixAlpha = false;
- }
- }
- else { // per-pixel transparency (won't use the WM_PAINT)
- bFixAlpha = false;
- }
- }
- else { // not layered - fill the window region
- SetRectRgn(hRgn, 0, 0, width, height);
- FillRgn(hMaskDC, hRgn, hBr);
- }
- }
- else {
- if (!hCapture) SetRectRgn(hRgn, 0, 0, width, height); // client area only, no transparency
- FillRgn(hMaskDC, hRgn, hBr);
- }
- DeleteObject(hRgn);
- if (bFixAlpha) {
- FIBITMAP* dibMask = FreeImage_CreateDIBFromHBITMAP(hMask);
- if (bInvert) FreeImage_Invert(dibMask);
- FIBITMAP* dib8 = FreeImage_ConvertTo8Bits(dibMask);
- // copy the dib8 alpha mask to dib32 main bitmap
- FreeImage_SetChannel(dib, dib8, FICC_ALPHA);
- FreeImage_Unload(dibMask);
- FreeImage_Unload(dib8);
- }
- DeleteDC(hMaskDC);
- DeleteObject(hMask);
- DeleteObject(hBr);
-
- // clean up
- DeleteDC(hMemDC);
- DeleteObject(hBitmap);
- if (!hDC)
- ReleaseDC(nullptr, hScrDC);
-
-#ifdef _DEBUG
- switch (FreeImage_GetImageType(dib)) {
- case FIT_UNKNOWN:
- OutputDebugStringA("FIBITMAP Type: FIT_UNKNOWN\r\n");
- break;
- case FIT_BITMAP:
- OutputDebugStringA("FIBITMAP Type: FIT_BITMAP\r\n");
- break;
- case FIT_UINT16:
- OutputDebugStringA("FIBITMAP Type: FIT_UINT16\r\n");
- break;
- case FIT_INT16:
- OutputDebugStringA("FIBITMAP Type: FIT_INT16\r\n");
- break;
- case FIT_UINT32:
- OutputDebugStringA("FIBITMAP Type: FIT_UINT32\r\n");
- break;
- case FIT_INT32:
- OutputDebugStringA("FIBITMAP Type: FIT_INT32\r\n");
- break;
- case FIT_FLOAT:
- OutputDebugStringA("FIBITMAP Type: FIT_FLOAT\r\n");
- break;
- case FIT_DOUBLE:
- OutputDebugStringA("FIBITMAP Type: FIT_DOUBLE\r\n");
- break;
- case FIT_COMPLEX:
- OutputDebugStringA("FIBITMAP Type: FIT_COMPLEX\r\n");
- break;
- case FIT_RGB16:
- OutputDebugStringA("FIBITMAP Type: FIT_RGB16\r\n");
- break;
- case FIT_RGBA16:
- OutputDebugStringA("FIBITMAP Type: FIT_RGBA16\r\n");
- break;
- case FIT_RGBF:
- OutputDebugStringA("FIBITMAP Type: FIT_RGBF\r\n");
- break;
- case FIT_RGBAF:
- OutputDebugStringA("FIBITMAP Type: FIT_RGBAF\r\n");
- break;
- default:
- OutputDebugStringA("FIBITMAP Type: non detectable image type (error)\r\n");
- break;
- }
- BOOL inf = FreeImage_IsTransparent(dib);
- OutputDebugStringA(inf ? "FIBITMAP Transparent: true\r\n" : "FIBITMAP Transparent: false\r\n");
-#endif
- return dib;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-char* GetFileNameA(const wchar_t* pszPath)
-{
- const wchar_t* slash = wcsrchr(pszPath, '\\');
- if (!slash) slash = wcsrchr(pszPath, '/');
- if (slash)
- return mir_u2a(slash + 1);
- else
- return mir_u2a(pszPath);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-BOOL GetEncoderClsid(wchar_t *wchMimeType, CLSID &clsidEncoder)
-{
- UINT uiNum = 0;
- UINT uiSize = 0;
- BOOL bOk = FALSE;
- Gdiplus::GetImageEncodersSize(&uiNum, &uiSize);
- if (uiSize > 0) {
- Gdiplus::ImageCodecInfo* pImageCodecInfo = (Gdiplus::ImageCodecInfo*)mir_alloc(uiSize);
- if (pImageCodecInfo) {
- Gdiplus::GetImageEncoders(uiNum, uiSize, pImageCodecInfo);
- for (UINT i = 0; i < uiNum; ++i) {
- if (!mir_wstrcmp(pImageCodecInfo[i].MimeType, wchMimeType)) {
- clsidEncoder = pImageCodecInfo[i].Clsid;
- bOk = TRUE;
- }
- }
- mir_free(pImageCodecInfo);
- }
- }
- return bOk;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-void SaveGIF(HBITMAP hBmp, const wchar_t *szFilename)
-{
- Gdiplus::GdiplusStartupInput gdiplusStartupInput;
- ULONG_PTR gdiplusToken;
- Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr);
-
- Gdiplus::Bitmap *pBitmap = Gdiplus::Bitmap::FromHBITMAP(hBmp, (HPALETTE)GetStockObject(DEFAULT_PALETTE));
- if (pBitmap) {
- // Get the CLSID of the GIF encoder.
- CLSID clsidEncoder;
- if (GetEncoderClsid(L"image/gif", clsidEncoder)) {
- LPWSTR pswFile = mir_wstrdup(szFilename);
- pBitmap->Save((const wchar_t*)pswFile, &clsidEncoder, nullptr);
- mir_free(pswFile);
- }
- delete pBitmap;
- }
- Gdiplus::GdiplusShutdown(gdiplusToken);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-void SaveTIF(HBITMAP hBmp, const wchar_t *szFilename)
-{
- // http://www.codeproject.com/Messages/1406708/How-to-reduce-the-size-of-an-Image-using-GDIplus.aspx
- ULONG_PTR gdiplusToken;
- Gdiplus::GdiplusStartupInput gdiplusStartupInput;
- Gdiplus::Status stat;
- Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr);
-
- Gdiplus::Bitmap *pBitmap = Gdiplus::Bitmap::FromHBITMAP(hBmp, (HPALETTE)GetStockObject(DEFAULT_PALETTE));
- if (pBitmap) {
- // Get the CLSID of the GIF encoder.
- CLSID EncCLSID;
- if (GetEncoderClsid(L"image/tiff", EncCLSID)) {
- //--- Create a 2-parameter array, for Compression and for Color Bit depth
- Gdiplus::EncoderParameters* EncParams = (Gdiplus::EncoderParameters*) malloc(sizeof(Gdiplus::EncoderParameters) + 1 * sizeof(Gdiplus::EncoderParameter));
- // Gdiplus::EncoderParameters pEncoderParameters;
- //--- Use LZW Compression instead of Group 4, since it works for color and G4 doesn't
- ULONG ulCompression = Gdiplus::EncoderValueCompressionLZW;
- ULONG ulColorDepth = 24L;
-
- EncParams->Count = 2;
- EncParams->Parameter[0].Guid = Gdiplus::EncoderCompression;
- EncParams->Parameter[0].Type = Gdiplus::EncoderParameterValueTypeLong;
- EncParams->Parameter[0].NumberOfValues = 1;
- EncParams->Parameter[0].Value = &ulCompression;
- EncParams->Parameter[1].Guid = Gdiplus::EncoderColorDepth;
- EncParams->Parameter[1].Type = Gdiplus::EncoderParameterValueTypeLong;
- EncParams->Parameter[1].NumberOfValues = 1;
- EncParams->Parameter[1].Value = &ulColorDepth;
-
- LPWSTR pswFile = mir_wstrdup(szFilename);
- stat = pBitmap->Save((const wchar_t*)pswFile, &EncCLSID, EncParams);
- mir_free(pswFile);
- free(EncParams);
- }
- delete pBitmap;
- }
- Gdiplus::GdiplusShutdown(gdiplusToken);
-}
+/*
+
+Miranda NG: the free IM client for Microsoft* Windows*
+
+Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org),
+Copyright (c) 2000-09 Miranda ICQ/IM project,
+
+This file is part of Send Screenshot Plus, a Miranda IM plugin.
+Copyright (c) 2010 Ing.U.Horn
+
+Parts of this file based on original sorce code
+(c) 2004-2006 Sérgio Vieira Rolanski (portet from Borland C++)
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "stdafx.h"
+
+void ComboBox_SelectItem(HWND hCombo, LPARAM data)
+{
+ for (int i = 0;; i++) {
+ LPARAM itemData = ComboBox_GetItemData(hCombo, i);
+ if (itemData == data) {
+ ComboBox_SetCurSel(hCombo, i);
+ return;
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MonitorInfoEnum
+
+static BOOL CALLBACK MonitorInfoEnumProc(HMONITOR hMonitor, HDC, LPRECT, LPARAM dwData)
+{
+ MONITORS* monitors = (MONITORS*)dwData;
+ ++monitors->count;
+ monitors->info = (MONITORINFOEX*)mir_realloc(monitors->info, sizeof(MONITORINFOEX)*monitors->count);
+ monitors->info[monitors->count - 1].cbSize = sizeof(MONITORINFOEX);
+ if (!GetMonitorInfo(hMonitor, (LPMONITORINFO)(monitors->info + monitors->count - 1)))
+ return FALSE; // stop enumeration if error
+
+ return TRUE;
+}
+
+size_t MonitorInfoEnum(MONITORINFOEX* &myMonitors, RECT &virtualScreen)
+{
+ MONITORS tmp = { 0, nullptr };
+ if (EnumDisplayMonitors(nullptr, nullptr, MonitorInfoEnumProc, (LPARAM)&tmp)) {
+ myMonitors = tmp.info;
+ memset(&virtualScreen, 0, sizeof(virtualScreen));
+ for (size_t i = 0; i < tmp.count; ++i) {
+ UnionRect(&virtualScreen, &virtualScreen, &tmp.info[i].rcMonitor);
+ }
+ return tmp.count;
+ }
+
+ mir_free(tmp.info);
+ return 0;
+}
+
+FIBITMAP* CreateDIBFromDC(HDC hDC, const RECT* rect, HWND hCapture = nullptr);
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// capture window as FIBITMAP - caller must FreeImage_Unload(dib)
+
+FIBITMAP* CaptureWindow(HWND hCapture, BOOL bClientArea, BOOL bIndirectCapture)
+{
+ FIBITMAP* dib;
+ HWND hForegroundWin;
+ RECT rect; // cropping rect
+
+ if (!hCapture || !IsWindow(hCapture))
+ return nullptr;
+
+ hForegroundWin = GetForegroundWindow(); // old foreground window
+ SetForegroundWindow(hCapture); // force target foreground
+ BringWindowToTop(hCapture); // bring it to top as well
+
+ // redraw window to prevent runtime artifacts in picture
+ UpdateWindow(hCapture);
+
+ HWND hParent = GetAncestor(hCapture, GA_PARENT);
+ if (hParent && !IsChild(hParent, hCapture))
+ hParent = nullptr;
+ if (bIndirectCapture) {
+ intptr_t wastopmost = GetWindowLongPtr(hCapture, GWL_EXSTYLE)&WS_EX_TOPMOST;
+ if (!wastopmost)
+ SetWindowPos(hCapture, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ if (bClientArea) {
+ GetClientRect(hCapture, &rect);
+ ClientToScreen(hCapture, (POINT*)&rect);
+ rect.right += rect.left; rect.bottom += rect.top;
+ }
+ else
+ GetWindowRect(hCapture, &rect);
+ dib = CaptureMonitor(nullptr, &rect);
+ if (!wastopmost)
+ SetWindowPos(hCapture, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ }
+ else {
+ HDC hDCsrc;
+ GetWindowRect(hCapture, &rect);
+ if (hParent)
+ hDCsrc = GetDC(hCapture); // hCapture is part of a window, capture that
+ else
+ hDCsrc = GetWindowDC(hCapture); // entire window w/ title bar
+ rect.right = ABS(rect.right - rect.left);
+ rect.bottom = ABS(rect.bottom - rect.top);
+ rect.left = rect.top = 0;
+ // capture window and get FIBITMAP
+ dib = CreateDIBFromDC(hDCsrc, &rect, hCapture);
+ ReleaseDC(hCapture, hDCsrc);
+
+ // we could capture directly, but doing so breaks GetWindowRgn() and also includes artifacts...
+ if (bClientArea) {
+ GetWindowRect(hCapture, &rect);
+ RECT rectCA; GetClientRect(hCapture, &rectCA);
+ ClientToScreen(hCapture, (POINT*)&rectCA);
+ rectCA.left = ABS(rectCA.left - rect.left);
+ rectCA.top = ABS(rectCA.top - rect.top);
+ rectCA.right += rectCA.left; rectCA.bottom += rectCA.top;
+
+ // crop the window to ClientArea
+ FIBITMAP* dibClient = FreeImage_Copy(dib, rectCA.left, rectCA.top, rectCA.right, rectCA.bottom);
+ FreeImage_Unload(dib);
+ dib = dibClient;
+ }
+ }
+
+ // restore previous foreground window
+ if (hForegroundWin) {
+ SetForegroundWindow(hForegroundWin);
+ BringWindowToTop(hForegroundWin);
+ }
+ return dib;
+}
+
+FIBITMAP* CaptureMonitor(const wchar_t* szDevice, const RECT* cropRect/*=NULL*/)
+{
+ HDC hScrDC;
+ RECT rect;
+
+ // get screen resolution
+ if (!szDevice) {
+ hScrDC = CreateDC(L"DISPLAY", nullptr, nullptr, nullptr);
+ rect.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
+ rect.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
+ rect.right = GetSystemMetrics(SM_XVIRTUALSCREEN) + GetSystemMetrics(SM_CXVIRTUALSCREEN);
+ rect.bottom = GetSystemMetrics(SM_YVIRTUALSCREEN) + GetSystemMetrics(SM_CYVIRTUALSCREEN);
+ }
+ else {
+ hScrDC = CreateDC(szDevice, nullptr, nullptr, nullptr);
+ rect.left = rect.top = 0;
+ rect.right = GetDeviceCaps(hScrDC, HORZRES);
+ rect.bottom = GetDeviceCaps(hScrDC, VERTRES);
+ }
+ if (cropRect) {
+ if (cropRect->left > rect.left) rect.left = cropRect->left;
+ if (cropRect->top > rect.top) rect.top = cropRect->top;
+ if (cropRect->right < rect.right) rect.right = cropRect->right;
+ if (cropRect->bottom < rect.bottom) rect.bottom = cropRect->bottom;
+ }
+
+ FIBITMAP *dib = CreateDIBFromDC(hScrDC, &rect);
+ ReleaseDC(nullptr, hScrDC);
+ return dib;
+}
+
+FIBITMAP* CreateDIBFromDC(HDC hDC, const RECT* rect, HWND hCapture/*=NULL*/)
+{
+ long width = rect->right - rect->left;
+ long height = rect->bottom - rect->top;
+
+ // create a DC for the screen and create
+ // a memory DC compatible to screen DC
+ HDC hScrDC = hDC;
+ if (!hScrDC)
+ hScrDC = GetDC(hCapture);
+ HDC hMemDC = CreateCompatibleDC(hScrDC);
+ // create a bitmap compatible with the screen DC
+ HBITMAP hBitmap = CreateCompatibleBitmap(hScrDC, width, height);
+ // select new bitmap into memory DC
+ SelectObject(hMemDC, hBitmap);
+
+ if (hCapture && hDC)
+ PrintWindow(hCapture, hMemDC, 0);
+ else // bitblt screen DC to memory DC
+ BitBlt(hMemDC, 0, 0, width, height, hScrDC, rect->left, rect->top, CAPTUREBLT | SRCCOPY);
+
+ FIBITMAP *dib = FreeImage_CreateDIBFromHBITMAP(hBitmap);
+
+ // alpha channel from window is always wrong and sometimes even for desktop (Win7, no aero)
+ // coz GDI do not draw all in alpha mode.
+ // we have to create our own new alpha channel.
+ bool bFixAlpha = true;
+ bool bInvert = false;
+ HBRUSH hBr = CreateSolidBrush(RGB(255, 255, 255)); // Create a SolidBrush object for non transparent area
+ HBITMAP hMask = CreateBitmap(width, height, 1, 1, nullptr); // Create monochrome (1 bit) B+W mask bitmap.
+ HDC hMaskDC = CreateCompatibleDC(nullptr);
+ SelectBitmap(hMaskDC, hMask);
+ HRGN hRgn = CreateRectRgn(0, 0, 0, 0);
+ if (hCapture && GetWindowRgn(hCapture, hRgn) == ERROR) {
+ if ((GetWindowLongPtr(hCapture, GWL_EXSTYLE)&WS_EX_LAYERED)) {
+ uint8_t bAlpha = 0;
+ COLORREF crKey = 0x00000000;
+ DWORD dwFlags = 0;
+ if (GetLayeredWindowAttributes(hCapture, &crKey, &bAlpha, &dwFlags)) {
+ // per window transparency (like fading in a whole window)
+ if ((dwFlags&LWA_COLORKEY)) {
+ SetBkColor(hMemDC, crKey);
+ BitBlt(hMaskDC, 0, 0, width, height, hMemDC, rect->left, rect->top, SRCCOPY);
+ bInvert = true;
+ }
+ else if ((dwFlags&LWA_ALPHA)) {
+ bFixAlpha = false;
+ }
+ }
+ else { // per-pixel transparency (won't use the WM_PAINT)
+ bFixAlpha = false;
+ }
+ }
+ else { // not layered - fill the window region
+ SetRectRgn(hRgn, 0, 0, width, height);
+ FillRgn(hMaskDC, hRgn, hBr);
+ }
+ }
+ else {
+ if (!hCapture) SetRectRgn(hRgn, 0, 0, width, height); // client area only, no transparency
+ FillRgn(hMaskDC, hRgn, hBr);
+ }
+ DeleteObject(hRgn);
+ if (bFixAlpha) {
+ FIBITMAP* dibMask = FreeImage_CreateDIBFromHBITMAP(hMask);
+ if (bInvert) FreeImage_Invert(dibMask);
+ FIBITMAP* dib8 = FreeImage_ConvertTo8Bits(dibMask);
+ // copy the dib8 alpha mask to dib32 main bitmap
+ FreeImage_SetChannel(dib, dib8, FICC_ALPHA);
+ FreeImage_Unload(dibMask);
+ FreeImage_Unload(dib8);
+ }
+ DeleteDC(hMaskDC);
+ DeleteObject(hMask);
+ DeleteObject(hBr);
+
+ // clean up
+ DeleteDC(hMemDC);
+ DeleteObject(hBitmap);
+ if (!hDC)
+ ReleaseDC(nullptr, hScrDC);
+
+#ifdef _DEBUG
+ switch (FreeImage_GetImageType(dib)) {
+ case FIT_UNKNOWN:
+ OutputDebugStringA("FIBITMAP Type: FIT_UNKNOWN\r\n");
+ break;
+ case FIT_BITMAP:
+ OutputDebugStringA("FIBITMAP Type: FIT_BITMAP\r\n");
+ break;
+ case FIT_UINT16:
+ OutputDebugStringA("FIBITMAP Type: FIT_UINT16\r\n");
+ break;
+ case FIT_INT16:
+ OutputDebugStringA("FIBITMAP Type: FIT_INT16\r\n");
+ break;
+ case FIT_UINT32:
+ OutputDebugStringA("FIBITMAP Type: FIT_UINT32\r\n");
+ break;
+ case FIT_INT32:
+ OutputDebugStringA("FIBITMAP Type: FIT_INT32\r\n");
+ break;
+ case FIT_FLOAT:
+ OutputDebugStringA("FIBITMAP Type: FIT_FLOAT\r\n");
+ break;
+ case FIT_DOUBLE:
+ OutputDebugStringA("FIBITMAP Type: FIT_DOUBLE\r\n");
+ break;
+ case FIT_COMPLEX:
+ OutputDebugStringA("FIBITMAP Type: FIT_COMPLEX\r\n");
+ break;
+ case FIT_RGB16:
+ OutputDebugStringA("FIBITMAP Type: FIT_RGB16\r\n");
+ break;
+ case FIT_RGBA16:
+ OutputDebugStringA("FIBITMAP Type: FIT_RGBA16\r\n");
+ break;
+ case FIT_RGBF:
+ OutputDebugStringA("FIBITMAP Type: FIT_RGBF\r\n");
+ break;
+ case FIT_RGBAF:
+ OutputDebugStringA("FIBITMAP Type: FIT_RGBAF\r\n");
+ break;
+ default:
+ OutputDebugStringA("FIBITMAP Type: non detectable image type (error)\r\n");
+ break;
+ }
+ BOOL inf = FreeImage_IsTransparent(dib);
+ OutputDebugStringA(inf ? "FIBITMAP Transparent: true\r\n" : "FIBITMAP Transparent: false\r\n");
+#endif
+ return dib;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+char* GetFileNameA(const wchar_t* pszPath)
+{
+ const wchar_t* slash = wcsrchr(pszPath, '\\');
+ if (!slash) slash = wcsrchr(pszPath, '/');
+ if (slash)
+ return mir_u2a(slash + 1);
+ else
+ return mir_u2a(pszPath);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+BOOL GetEncoderClsid(wchar_t *wchMimeType, CLSID &clsidEncoder)
+{
+ UINT uiNum = 0;
+ UINT uiSize = 0;
+ BOOL bOk = FALSE;
+ Gdiplus::GetImageEncodersSize(&uiNum, &uiSize);
+ if (uiSize > 0) {
+ Gdiplus::ImageCodecInfo* pImageCodecInfo = (Gdiplus::ImageCodecInfo*)mir_alloc(uiSize);
+ if (pImageCodecInfo) {
+ Gdiplus::GetImageEncoders(uiNum, uiSize, pImageCodecInfo);
+ for (UINT i = 0; i < uiNum; ++i) {
+ if (!mir_wstrcmp(pImageCodecInfo[i].MimeType, wchMimeType)) {
+ clsidEncoder = pImageCodecInfo[i].Clsid;
+ bOk = TRUE;
+ }
+ }
+ mir_free(pImageCodecInfo);
+ }
+ }
+ return bOk;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void SaveGIF(HBITMAP hBmp, const wchar_t *szFilename)
+{
+ Gdiplus::GdiplusStartupInput gdiplusStartupInput;
+ ULONG_PTR gdiplusToken;
+ Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr);
+
+ Gdiplus::Bitmap *pBitmap = Gdiplus::Bitmap::FromHBITMAP(hBmp, (HPALETTE)GetStockObject(DEFAULT_PALETTE));
+ if (pBitmap) {
+ // Get the CLSID of the GIF encoder.
+ CLSID clsidEncoder;
+ if (GetEncoderClsid(L"image/gif", clsidEncoder)) {
+ LPWSTR pswFile = mir_wstrdup(szFilename);
+ pBitmap->Save((const wchar_t*)pswFile, &clsidEncoder, nullptr);
+ mir_free(pswFile);
+ }
+ delete pBitmap;
+ }
+ Gdiplus::GdiplusShutdown(gdiplusToken);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void SaveTIF(HBITMAP hBmp, const wchar_t *szFilename)
+{
+ // http://www.codeproject.com/Messages/1406708/How-to-reduce-the-size-of-an-Image-using-GDIplus.aspx
+ ULONG_PTR gdiplusToken;
+ Gdiplus::GdiplusStartupInput gdiplusStartupInput;
+ Gdiplus::Status stat;
+ Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr);
+
+ Gdiplus::Bitmap *pBitmap = Gdiplus::Bitmap::FromHBITMAP(hBmp, (HPALETTE)GetStockObject(DEFAULT_PALETTE));
+ if (pBitmap) {
+ // Get the CLSID of the GIF encoder.
+ CLSID EncCLSID;
+ if (GetEncoderClsid(L"image/tiff", EncCLSID)) {
+ //--- Create a 2-parameter array, for Compression and for Color Bit depth
+ Gdiplus::EncoderParameters* EncParams = (Gdiplus::EncoderParameters*) malloc(sizeof(Gdiplus::EncoderParameters) + 1 * sizeof(Gdiplus::EncoderParameter));
+ // Gdiplus::EncoderParameters pEncoderParameters;
+ //--- Use LZW Compression instead of Group 4, since it works for color and G4 doesn't
+ ULONG ulCompression = Gdiplus::EncoderValueCompressionLZW;
+ ULONG ulColorDepth = 24L;
+
+ EncParams->Count = 2;
+ EncParams->Parameter[0].Guid = Gdiplus::EncoderCompression;
+ EncParams->Parameter[0].Type = Gdiplus::EncoderParameterValueTypeLong;
+ EncParams->Parameter[0].NumberOfValues = 1;
+ EncParams->Parameter[0].Value = &ulCompression;
+ EncParams->Parameter[1].Guid = Gdiplus::EncoderColorDepth;
+ EncParams->Parameter[1].Type = Gdiplus::EncoderParameterValueTypeLong;
+ EncParams->Parameter[1].NumberOfValues = 1;
+ EncParams->Parameter[1].Value = &ulColorDepth;
+
+ LPWSTR pswFile = mir_wstrdup(szFilename);
+ stat = pBitmap->Save((const wchar_t*)pswFile, &EncCLSID, EncParams);
+ mir_free(pswFile);
+ free(EncParams);
+ }
+ delete pBitmap;
+ }
+ Gdiplus::GdiplusShutdown(gdiplusToken);
+}