如何使用c ++为最小尺寸的窗口制作屏幕截图

Posted

技术标签:

【中文标题】如何使用c ++为最小尺寸的窗口制作屏幕截图【英文标题】:how to make a screenshot for windows with minimum size with c ++ 【发布时间】:2020-01-29 11:40:19 【问题描述】:

我实现了一个截屏程序,但问题是图像大小大于 6 MB。

我想进行修正以最小化图像尺寸。

这是我的功能

BOOL CALLBACK MonitorEnumProcCallback( HMONITOR hMonitor,  HDC DevC,LPRECT lprcMonitor,LPARAM dwData) 

        const char*BmpName;
        string BmpNameString;
        BmpNameString="screen.jpeg";
        BmpName= BmpNameString.c_str();
        MONITORINFO  info;
        info.cbSize = sizeof(MONITORINFO);
        BOOL monitorInfo = GetMonitorInfo(hMonitor, &info);
        if (monitorInfo) 
         DWORD Width = info.rcMonitor.right - info.rcMonitor.left;
         DWORD Height = info.rcMonitor.bottom - info.rcMonitor.top;
         DWORD FileSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 3 * Width * Height;
         char *BmpFileData = (char*)GlobalAlloc(0x0040, FileSize); 
         PBITMAPFILEHEADER BFileHeader = (PBITMAPFILEHEADER)BmpFileData;
         PBITMAPINFOHEADER  BInfoHeader = (PBITMAPINFOHEADER)&BmpFileData[sizeof(BITMAPFILEHEADER)];
         BFileHeader->bfType = 0x4D42; // BM
         BFileHeader->bfSize = sizeof(BITMAPFILEHEADER);
         BFileHeader->bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
         BInfoHeader->biSize = sizeof(BITMAPINFOHEADER);
         BInfoHeader->biPlanes = 1;
         BInfoHeader->biBitCount = 24;
         BInfoHeader->biCompression = BI_RGB;
         BInfoHeader->biHeight = Height;
         BInfoHeader->biWidth = Width;
         RGBTRIPLE *Image = (RGBTRIPLE*)&BmpFileData[sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)];
         RGBTRIPLE color;
         HDC CaptureDC = CreateCompatibleDC(DevC);
         HBITMAP CaptureBitmap = CreateCompatibleBitmap(DevC, Width, Height);
         SelectObject(CaptureDC, CaptureBitmap);
         BitBlt(CaptureDC, 0, 0, Width, Height, DevC, info.rcMonitor.left, info.rcMonitor.top, SRCCOPY | CAPTUREBLT);
         GetDIBits(CaptureDC, CaptureBitmap, 0, Height, Image, (LPBITMAPINFO)BInfoHeader, DIB_RGB_COLORS);
         DWORD Junk;
         HANDLE FH = CreateFileA(BmpName, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, 0, 0);
         WriteFile(FH, BmpFileData, FileSize, &Junk, 0);
         CloseHandle(FH);
         GlobalFree(BmpFileData);
        
        return TRUE;
    

data

【问题讨论】:

什么是最小尺寸?最小的图像大小为 0x0,接近 0 字节(只有一些元信息) 使用 jpeg 等有损压缩方法进行转换。 @ThomasSablik 最小尺寸?大小为 1 MB 压缩您的图像数据。简单地传递压缩格式的文件名不会神奇地压缩图像数据。而是通过 Windows 映像组件使用 Windows 上可用的编解码器之一。 【参考方案1】:

如果你不介意的话,可以使用下面的GDI+方法得到一个比较小的尺寸:

#include<windows.h>
#include <iostream>
#include <string.h>
#include <gdiplus.h>
#include <stdio.h>

using namespace Gdiplus;
using namespace std;
#pragma comment(lib, "Gdiplus.lib")

int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)

    UINT  num = 0;          // number of image encoders
    UINT  size = 0;         // size of the image encoder array in bytes

    ImageCodecInfo* pImageCodecInfo = NULL;

    GetImageEncodersSize(&num, &size);
    if (size == 0)
        return -1;  // Failure

    pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
    if (pImageCodecInfo == NULL)
        return -1;  // Failure

    GetImageEncoders(num, size, pImageCodecInfo);

    for (UINT j = 0; j < num; ++j)
    
        if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0)
        
            *pClsid = pImageCodecInfo[j].Clsid;
            free(pImageCodecInfo);
            return j;  // Success
        
    

    free(pImageCodecInfo);
    return -1;  // Failure


BOOL CALLBACK MonitorEnumProcCallback(HMONITOR hMonitor, HDC DevC, LPRECT lprcMonitor, LPARAM dwData)

    wstring BmpNameString = L"screen.jpeg";
    MONITORINFO  info;
    info.cbSize = sizeof(MONITORINFO);
    BOOL monitorInfo = GetMonitorInfo(hMonitor, &info);
    if (monitorInfo) 
        DWORD Width = info.rcMonitor.right - info.rcMonitor.left;
        DWORD Height = info.rcMonitor.bottom - info.rcMonitor.top;
        //DWORD FileSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 3 * Width * Height;
        //char* BmpFileData = (char*)GlobalAlloc(0x0040, FileSize);
        //PBITMAPFILEHEADER BFileHeader = (PBITMAPFILEHEADER)BmpFileData;
        //PBITMAPINFOHEADER  BInfoHeader = (PBITMAPINFOHEADER)&BmpFileData[sizeof(BITMAPFILEHEADER)];
        //BFileHeader->bfType = 0x4D42; // BM
        //BFileHeader->bfSize = sizeof(BITMAPFILEHEADER);
        //BFileHeader->bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
        //BInfoHeader->biSize = sizeof(BITMAPINFOHEADER);
        //BInfoHeader->biPlanes = 1;
        //BInfoHeader->biBitCount = 24;
        //BInfoHeader->biCompression = BI_RLE8;
        //BInfoHeader->biHeight = Height;
        //BInfoHeader->biWidth = Width;
        //RGBTRIPLE* Image = (RGBTRIPLE*)&BmpFileData[sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)];
        //RGBTRIPLE color;

        HDC CaptureDC = CreateCompatibleDC(DevC);
        HBITMAP CaptureBitmap = CreateCompatibleBitmap(DevC, Width, Height);
        HGDIOBJ old_obj = SelectObject(CaptureDC, CaptureBitmap);
        BitBlt(CaptureDC, 0, 0, Width, Height, DevC, info.rcMonitor.left, info.rcMonitor.top, SRCCOPY | CAPTUREBLT);
        //GetDIBits(CaptureDC, CaptureBitmap, 0, Height, Image, (LPBITMAPINFO)BInfoHeader, DIB_RGB_COLORS);
        /*DWORD Junk;
        HANDLE FH = CreateFileA(BmpName, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, 0, 0);
        WriteFile(FH, BmpFileData, FileSize, &Junk, 0);
        CloseHandle(FH);
        GlobalFree(BmpFileData);*/
        Gdiplus::Bitmap bitmap(CaptureBitmap, NULL);

        CLSID pngClsid;
        GetEncoderClsid(L"image/jpeg", &pngClsid);
        bitmap.Save(BmpNameString.c_str(), &pngClsid, NULL);

        SelectObject(CaptureDC, old_obj);
        DeleteDC(CaptureDC);
        ReleaseDC(NULL, DevC);
        DeleteObject(CaptureBitmap);
    
    return TRUE;

int main()

    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    HDC hdc = GetDC(NULL);

    EnumDisplayMonitors(hdc,NULL, MonitorEnumProcCallback,NULL);

    ReleaseDC(NULL,hdc);
    GdiplusShutdown(gdiplusToken);
    return 0;

【讨论】:

以上是关于如何使用c ++为最小尺寸的窗口制作屏幕截图的主要内容,如果未能解决你的问题,请参考以下文章

如何更改 QTableWidget 的最小尺寸?

如何在Java中将窗口调整为全屏?

如何在c中获取屏幕截图[关闭]

解决使用复制浏览器的屏幕截图出现黑色窗口的问题

iTunes Connect 不再接受 iPad 屏幕截图

Matlab中如何只把figure中的图像区域保存为图片文件