win32 - 如何将屏幕捕获为8位或16位位图?

时间:2010-05-18 18:20:53

标签: c winapi bitmap

我刚开始使用win32 GDI编程并且很难找到好的参考资料。我有一个简单的应用程序,通过执行以下操作捕获屏幕:

UINT32 x,y;
x = GetSystemMetrics(SM_CXSCREEN);
y = GetSystemMetrics(SM_CYSCREEN);

HDC hdc = GetDC(NULL);
HDC hdcScreen = CreateCompatibleDC(hdc);

HBITMAP hbmp = CreateCompatibleBitmap(hdc, x, y);

SelectObject(hdcScreen, hbmp);

BitBlt(hdcScreen, 0, 0, x, y, hdc, 0, 0, SRCCOPY)

ReleaseDC(NULL, hdc);

UINT32 x,y; x = GetSystemMetrics(SM_CXSCREEN); y = GetSystemMetrics(SM_CYSCREEN); HDC hdc = GetDC(NULL); HDC hdcScreen = CreateCompatibleDC(hdc); HBITMAP hbmp = CreateCompatibleBitmap(hdc, x, y); SelectObject(hdcScreen, hbmp); BitBlt(hdcScreen, 0, 0, x, y, hdc, 0, 0, SRCCOPY) ReleaseDC(NULL, hdc);

我正在捕获一个在我的机器上是32位的兼容位图。使用相同/类似的调用如何以8位捕获屏幕?那么16位呢?

2 个答案:

答案 0 :(得分:2)

使用CreateDIBSection创建一个8bpp的位图,然后使用BitBlt。


填写BITMAPINFO结构将会很有趣。您不能使用普通的BITMAPINFO结构,因为它只为单个调色板条目分配空间,并且使用8bpp图像 - 您将需要完整的256个条目。

如果你想作弊,可以使用匿名联合声明一个BITMAPINFO,它的调色板有足够的空间。

union
{
  BITMAPINFO bmi;
  struct {
    BITMAPINFOHEADER bmih;
    RGBQUAD extra[256];
  } dummy;
};

bmi.bmiHeader.biSize = sizeof (bmi.bmiHeader);
bmi.biBitCount = 8;
// and so on.

关于在颜色表中初始化的值...我想不出一种简单的方法来从GDI获得默认的8bpp调色板,而不是8bpp模式。我怀疑CreateHalftonePalette在非调色板设备上不会做任何事情。

答案 1 :(得分:1)

我很确定你必须捕获一个32位的位图,然后自己将其转换为8位。 8位转换通常会丢失相当数量的数据,并且有很多不同的算法可供选择。除非你真的没有没有选择,否则我会重新考虑这样做。这是很长时间,因为大多数人都有很多理由搞乱8位位图 - 而且他们 一团糟。

8位位图(至少是典型的位图)具有“调色板”,其指定要在位图文件中使用的每种(最多)256种颜色的24位值。通常,您希望选择与原始位图中的颜色最接近的颜色。已经发明了 lot 算法来实现这一目标。谷歌搜索“颜色减少算法”之类的东西应该产生相当多的点击,有很多变化,如何做到这一点,折衷执行速度,内存使用等等。我甚至不能开始猜测谁最适合为了你的特殊目的。

正如我前面所说,我的第一个倾向是花些时间和精力来简单地消除这个要求。从32减少到24或甚至16位非常简单,并保留了原始质量的 lot 。转到8位是非常困难的会失去很多质量。