简体   繁体   中英

Сreating bitmap from HDC

The problem is that although the image is created, there is a small indent on the left side, a screenshot is attached (on top is the image that my program makes, just below the program itself).在此处输入图像描述

HDC hdcWindow{ HdcWindowScreen }, hdcMemDC{ CreateCompatibleDC(hdcWindow) };
HBITMAP hbmScreen{};
BITMAP bmpScreen{};

RECT rcClient;
GetClientRect(WindowFromDC(hdcWindow), &rcClient);
hbmScreen = CreateCompatibleBitmap(hdcWindow, rcClient.right + rcClient.left, rcClient.bottom + rcClient.top);

SelectObject(hdcMemDC, hbmScreen);

if (!(BitBlt(hdcMemDC, 0, 0, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, hdcWindow, 0, 0, SRCCOPY))) {
    MessageBox(hWnd, L"BitBlt has failed", L"Failed", MB_OK);
    ClearMemory();
}

GetObject(hdcWindow, sizeof(BITMAP), &bmpScreen);

BITMAPFILEHEADER bmfHeader{};
BITMAPINFOHEADER bi{};

bi.biSize = sizeof(BITMAPFILEHEADER);
bi.biWidth = bmpScreen.bmWidth;
bi.biHeight = bmpScreen.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = 32;;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;

DWORD dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;

DWORD dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

bmfHeader.bfOffBits = static_cast<DWORD>(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));
bmfHeader.bfSize = dwSizeofDIB;
bmfHeader.bfType = 0x4D42;


GdiplusStartupInput gdiplusStartupInput{};
ULONG_PTR gdiplusToken{};
Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    CLSID myClsId{};

    Bitmap* image = new Bitmap(hbmScreen, nullptr);
    image->Save(FileName, &myClsId, NULL);
Gdiplus::GdiplusShutdown(gdiplusToken);

GetClientRect() does not include the border and title bar. All it does is tell you the dimensions of the client area.

GetWindowRect retrieves the dimensions of the bounding rectangle of the specified window. The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen.

But Windows 10 has thin invisible borders on left, right, and bottom, it is used to grip the mouse for resizing. The borders might look like this: 7,0,7,7 (left, top, right, bottom)

So if we use GetWindowRect - this gives a little large window rect as compared to what we see on screen.

Please refer: GetWindowRect returns a size including “invisible” borders

As @zett42 said that, use DwmGetWindowAttribute with DWMWA_EXTENDED_FRAME_BOUNDS to get the correct window size is a good way.

Like this:

Rect rect;

DwmGetWindowAttribute(hWnd, DWMWA_EXTENDED_FRAME_BOUNDS, (PVOID)&rect, sizeof(rect));

Note: If DPI changes, GetWindowRect will not return the correct window size.

But DwmGetWindowAttribute will still return a correct size.

Please refer: How to get rectangle bounds given hWnd?

Expand: If DPI changes, LogicalToPhysicalPointForPerMonitorDPI can return correct coordinates (+invisible borders)

LogicalToPhysicalPointForPerMonitorDPI : Converts a point in a window from logical coordinates into physical coordinates, regardless of the dots per inch (dpi) awareness of the caller.

If you think it's better to have invisible borders, you can use this API.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM