You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从截屏代码中获取可加载到QGraphicsView的图像数据?

问题:如何从GDI+截屏代码中获取QGraphicsView可用的图像数据?

我正在为一款应用构建模块,该模块需截取屏幕画面并显示在QGraphicsView中。以下是我将截屏保存为jpg文件的GDI+代码:

#include <gdiplus.h>

int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) {
    using namespace Gdiplus;
    UINT  num = 0;
    UINT  size = 0;

    ImageCodecInfo* pImageCodecInfo = NULL;

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

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

    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;
        }    
    }
    free(pImageCodecInfo);
    return 0;
}

void gdiscreen() {
    using namespace Gdiplus;
    IStream* istream;
    HRESULT res = CreateStreamOnHGlobal(NULL, true, &istream);
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    {
        HDC scrdc, memdc;
        HBITMAP membit;
        scrdc = ::GetDC(0);
        int Height = GetSystemMetrics(SM_CYSCREEN);
        int Width = GetSystemMetrics(SM_CXSCREEN);
        memdc = CreateCompatibleDC(scrdc);
        membit = CreateCompatibleBitmap(scrdc, Width, Height);
        HBITMAP hOldBitmap =(HBITMAP) SelectObject(memdc, membit);
        BitBlt(memdc, 0, 0, Width, Height, scrdc, 0, 0, SRCCOPY);
        
        Gdiplus::Bitmap bitmap(membit, NULL);
        CLSID clsid;
        GetEncoderClsid(L"image/jpeg", &clsid); //Type of image
        bitmap.Save(L"print.jpeg", &clsid, NULL); //Name of the file to save
        bitmap.Save(istream, &clsid, NULL);
        
        delete &clsid;
        DeleteObject(memdc);
        DeleteObject(membit);
        ::ReleaseDC(0,scrdc);
    }
    GdiplusShutdown(gdiplusToken);
    istream->Release();
}

int main(){
    gdiscreen();
    return 0;
}

解决方案

你可以通过以下几种方式获取QGraphicsView可用的图像数据,无需先保存为本地文件:

1. 直接从HBITMAP转换为QPixmap

代码中membit就是包含截屏内容的HBITMAP,这是最直接的数据源。Qt提供了转换接口,可直接将HBITMAP转为QPixmap:

// 在BitBlt完成后,使用membit转换
QPixmap pixmap = QPixmap::fromWinHBITMAP(membit);
// 将pixmap添加到QGraphicsScene并显示
QGraphicsScene* scene = new QGraphicsScene;
scene->addPixmap(pixmap);
ui->graphicsView->setScene(scene);

注意:转换后不要立即销毁membit,需在QPixmap使用完成后再调用DeleteObject(membit)。

2. 从Gdiplus::Bitmap提取像素数据到QImage

通过Gdiplus的Bitmap::LockBits获取像素缓冲区,将原始像素数据复制到QImage中,再转为QPixmap:

Gdiplus::Bitmap bitmap(membit, NULL);
Gdiplus::BitmapData bmpData;
Gdiplus::Rect rect(0, 0, bitmap.GetWidth(), bitmap.GetHeight());
// 锁定像素缓冲区,选择和QImage兼容的RGB32格式
bitmap.LockBits(&rect, Gdiplus::ImageLockModeRead, PixelFormat32bppARGB, &bmpData);

// 创建QImage并复制像素数据
QImage img((uchar*)bmpData.Scan0, bitmap.GetWidth(), bitmap.GetHeight(), bmpData.Stride, QImage::Format_RGB32);
QPixmap pixmap = QPixmap::fromImage(img);

// 解锁缓冲区
bitmap.UnlockBits(&bmpData);

3. 从IStream读取数据加载为QImage

你已经将Bitmap保存到了istream中,可将流内容读取到QByteArray,再用QImage加载:

// 将流指针重置到开头
LARGE_INTEGER liZero = {0};
istream->Seek(liZero, STREAM_SEEK_SET, NULL);

// 读取流内容到QByteArray
QByteArray buffer;
char temp[1024];
ULONG bytesRead;
while (istream->Read(temp, sizeof(temp), &bytesRead) == S_OK && bytesRead > 0) {
    buffer.append(temp, bytesRead);
}

// 加载为QImage并转为QPixmap
QImage img;
img.loadFromData(buffer, "JPG");
QPixmap pixmap = QPixmap::fromImage(img);

代码修正提醒

原代码中有两处错误需要修正:

  • delete &clsid;:clsid是栈上声明的变量,不能用delete删除,直接移除该行。
  • DeleteObject(memdc):memdc是设备上下文,应该用DeleteDC(memdc)销毁。

内容的提问来源于stack exchange,提问作者user21806805

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 15:33:15