如何从截屏代码中获取可加载到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
相关产品推荐
相关产品推荐

