从HBITMAP获取字节

6
如果我有一个HBITMAP指针,并且我的应用程序是控制台应用程序,我该如何从hbitmap获取图像字节。我尝试使用GetDIBits,它需要HDC等参数,但我无法获取它。 编辑:我从文件加载位图。
HBITMAP bm = 0; 
BITMAP Bitmap;
bm = (HBITMAP)LoadImage (0, TEXT("C:\\img1.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

我将HBITMAP传递给函数,并期望得到另一个经过处理的图像的HBITMAP:

HBITMAP out1 = func(bm);

func 是指:

HBITMAP func(HBITMAP im);

问题在于如何从HBITMAP中获取图像字节。


2
@WhozCraig 他说他尝试过GetDIBits,但没有DC可以传递给它(就像你链接的示例所显示的那样)。 - Jonathon Reinhart
@JonathonReinhart 对不起,我没有使用GetDIBits()链接到试图(但失败了)遵循Microsoft网站上规定的方法执行此任务的OP。我没有做出联系,显然我应该这样做。 - WhozCraig
@Jonathon Reinhart 我需要进行一些图像处理,然后将结果输出到一个新的HBITMAP指针中。 - maximus
@maximus 嗯,那你的问题就没什么意义了。看看我编辑过的内容吧。 - Jonathon Reinhart
@maximus 我认为你需要展示你的代码。如果不看到你正在做什么/试图做什么,我无法提供更多帮助。 - Jonathon Reinhart
显示剩余5条评论
5个回答

14

最简单的方法是不要使用GetDIBits(也不要使用GetBitmapBits)。这些函数的问题在于它们会复制数据。
如果你想直接获取数据,只需使用(对于DDB位图)

BITMAP bitmap;
GetObject(hBitmap, sizeof(bitmap), (LPVOID)&bitmap);

对于 DIB 位图,请使用

DIBSECTION dib;
GetObject(hBitmap, sizeof(dib), (LPVOID)&dib);

获取对象信息,请参见:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd144904%28v=vs.85%29.aspx

这不涉及任何数据复制,因此避免了与 GetDIBits 相关的复杂问题,请参见:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd144879%28v=vs.85%29.aspx
特别是底部的注释,以解释 GetDIBits 的困难之处。

请注意,您将不会获得调色板信息; 但由于大多数位图都是24位或32位,因此在大多数情况下这几乎不是问题。


7
根据https://msdn.microsoft.com/en-us/library/dd144904(v=vs.85).aspx,如果位图不是由`CreateDIBSection`创建的,则`bitmap.bmBit`指针将为空。 - Logman

1

由于您正在使用 LoadImage 来获取 HBITMAP,因此它确实是 DIB(设备无关位图)(他们称其为 DIBsection)。但是,您没有颜色信息。

这篇 MSDN HOWTO 指导您如何将 DIBsection 选择到内存 DC 中。然后,他们继续使用 GetDIBColorTable 来获取调色板。然而,我认为从那里开始,通过该 DC,您可以使用 GetDIBits 获取 RGB 位图信息,就像您一直在尝试做的那样。

这是大致的概述:

// Create a memory DC and select the DIBSection into it
hMemDC = CreateCompatibleDC( NULL );
(HBITMAP)SelectObject( hMemDC, hBitmap );

GetDIBits(hMemDC, hBitmap, ...);

在他们的代码中,你会注意到SelectObject返回一个处理程序,指向了DC中的内容。然后他们在调用DeleteDC之前恢复它。我不确定这是否完全必要,但他们确实这样做。为了清晰起见,我在这里省略了它。

1
我们的解决办法是:在正确的调色板(如果是索引颜色)仍然选中设备上下文时调用 GetDIBits。(没有选择调色板,颜色会变得混乱。)
但在我们的用例中,发现 DIB 部分表现更好,因此也要检查并进行基准测试。但是,有一些陷阱。Windows 不会使用调色板,我们必须在使用之前调用 SetDIBColorTable。但设备上下文仍需要选择一个条目(仅黑色)的虚拟调色板,并将其实现到设备上下文中,否则 Windows 也会忽略由 SetDIBColorTable 设置的调色板。必须同时存在 SetDIBColorTableRealizePalette,否则颜色会混乱。

0

由于问题已编辑,请查看新答案...

没有设备上下文句柄 (HDC),你无法完成这个操作。这是因为 GetDIBits 需要一个 HBITMAP,它是

位图的句柄。这必须是兼容位图(DDB)。

DDB 是一个依赖于设备的位图(与 DIB 或设备无关位图相对)。这意味着:

请注意,DDB 不包含颜色值;相反,颜色以设备相关格式存储。

这就是为什么 GetDIBits 需要一个 HDC 的原因。否则它无法获取颜色信息。

也许一个好问题是:你在哪里得到了一个没有相应 HDCHBITMAP


如果您想在内存中创建此位图,首先可以调用 CreateCompatibleDC 创建与某些设备兼容的内存 DC,然后使用该 DC 调用 CreateCompatibleBitmap。然后您就有了一个 HBITMAPHDC,可以随意使用。否则,如果您不知道您的 HBITMAP 指向什么,就不能指望对其进行任何有用的操作。


你的意思是,如果使用HBITMAP指针,我就必须处理HDC吗? - maximus
如果你想获取颜色信息,可以看一下我在DDBs上包含的链接。 - Jonathon Reinhart
1
只有当您处理依赖于 HDCDDB 时,才需要考虑。如果您处理的是 DIB,则不需要 HDC。那么您的 HBITMAP 实际上指向什么 - DDB 还是 DIB - Remy Lebeau
@RemyLebeau 我认为 HBITMAP 总是 DDBHBITMAP on MSDN 将您指向 此页面,之后 关于位图 指出 "位图是可以选择到设备上下文 (DC) 中的 GDI 对象之一"。 - Jonathon Reinhart
如果您从资源中加载位图,则会获得一个 HBITMAP,但它不与特定的 DC 相关联。正如 Remy 所说,它正在加载 DIB 而不是 DDB,因此不需要 DC。 - Cody Gray
显示剩余7条评论

0

从MSDN: "注意 此函数仅用于与16位Windows版本的兼容性。应用程序应使用GetDIBits函数。" - Jonathon Reinhart
此外,这只是获取原始位,但它仍然是一个依赖于设备的位图,因此您没有正确的颜色信息。 - Jonathon Reinhart
请查看我在问题描述中最新的评论。 - Jonathon Reinhart
@Vahid Farahmand GetBitmapBits 返回的值是0,意味着失败。 - maximus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接