从屏幕HDC保存像素

时间:2019-04-03 20:39:58

标签: c++ bitblt hdc createdibsection

许多论坛提供了以下代码,说明如何将屏幕像素的副本复制到数组中:

char* Pixels = NULL;
HDC MemDC = CreateCompatibleDC(Context);
HBITMAP Section = CreateDIBSection(Context, &Info, DIB_RGB_COLORS, (void**)&Pixels, 0, 0);
DeleteObject(SelectObject(MemDC, Section));
BitBlt(MemDC, 0, 0, Width, Height, Context, Area.left, Area.top, SRCCOPY);
DeleteDC(MemDC);
std::fstream hFile(FilePath, std::ios::out | std::ios::binary);
if (hFile.is_open())
{
    hFile.write((char*)&Header, sizeof(Header));
    hFile.write((char*)&Info.bmiHeader, sizeof(Info.bmiHeader));
    hFile.write(Pixels, (((BitsPerPixel * Width + 31) & ~31) / 8) * Height);
    hFile.close();
    DeleteObject(Section);
    return true;
}

Link

但是,这实际上涉及将像素“内存”区域从屏幕HDC复制到内存中。为什么不这样:

char* Pixels = NULL;
HBITMAP Section = CreateDIBSection(Context, &Info, DIB_RGB_COLORS, (void**)&Pixels, 0, 0);
SelectObject(Context, Section);

上下文HDC已经包含所有数据。为什么我不能只阅读它?

我认为必须在HDC中选择位图 ,并且HDC 实际上会携带数据。那么,为什么CreateDIBSection仍返回一个指针,尽管该位图尚未被选择到任何HDC中? (如果它提供了指向作为参数传递的HDC内存的指针,则该数组已经包含屏幕的像素值,但并非如此,因为仍然需要BitBlt。)

我之所以得出这个结论,是因为BitBlt接受HDC参数,而不是位图。这可能意味着它将数据复制到关联的HDC。

1 个答案:

答案 0 :(得分:0)

视频内存可以存储在多个位置,包括主系统内存(RAM),视频卡上的专用内存,外部显示设备,甚至是这些的某种组合。对该内存的访问可能很慢,并且某个进程可能无法访问该内存(至少需要将其映射到该进程的地址空间中)。

存储在硬件中的视频数据在传递给您的应用程序之前可能需要转换为其他格式。而且该硬件可能能够利用其他方法来复制不直接涉及CPU的数据(例如直接内存访问或DMA)。由于该复制确实花费少量时间,因此您想要的部分可能会在复制到主内存之前(一个非常慢的过程)被复制到视频适配器上视频内存的另一部分(这可能是非常快的过程)。

视频显示也是一种共享资源:系统上的所有进程可能都需要访问它。如果您有一个指向视频存储器的指针,那么您读到的内容可能不是可见的(如果它已更新为其他内容),或者如果您写入它,则可能会损坏屏幕。