【发布时间】:2012-01-11 05:47:12
【问题描述】:
我正在从具有以下内容的文件中加载 DIBSection:
HBITMAP bmpIn = (HBITMAP) LoadImage(NULL, _T("c:\\Temp\\Temp.bmp"), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);
根据经验,我发现加载的位图与我过去使用的位图之间存在以下差异,但我找不到任何说明应该存在差异的文档。
- 行在内存中的顺序是自上而下而不是自下而上。我已验证 .bmp 文件本身是自下而上排序的。
- 行填充是 2 字节的倍数,而不是 4。
当您使用 CreateDIBSection 从头开始创建 DIBSection 时,我还发现了一个记录差异。
-
GetObject返回的 DIBSECTION.dsHandle 和 BITMAP.bmBits 值将为 NULL。
前两个差异的文档在哪里,我是否遗漏了什么?这适用于 Windows 7,但我无法想象其他版本的 Windows 会有所不同。
编辑:一些额外的细节。这是temp.bmp 的十六进制转储;这是一个 7x7 的图像,右侧有一条白色条纹,蓝色值沿左侧递增(0x10、0x20 等)。可以看到底线 (00,00,70) 是第一个,并且有 3 个字节的填充。
00: 42 4d de 00 00 00 00 00 00 00 36 00 00 00 28 00
10: 00 00 07 00 00 00 07 00 00 00 01 00 18 00 00 00
20: 00 00 a8 00 00 00 00 00 00 00 00 00 00 00 00 00
30: 00 00 00 00 00 00 70 00 00 00 00 00 00 00 00 00
40: 00 00 00 00 00 00 00 00 ff ff ff 00 00 00 60 00
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
60: ff ff ff 00 00 00 50 00 00 00 00 00 00 00 00 00
70: 00 00 00 00 00 00 00 00 ff ff ff 00 00 00 40 00
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
90: ff ff ff 00 00 00 30 00 00 00 00 00 00 00 00 00
a0: 00 00 00 00 00 00 00 00 ff ff ff 00 00 00 20 00
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c0: ff ff ff 00 00 00 10 00 00 00 00 00 00 00 00 00
d0: 00 00 00 00 00 00 00 00 ff ff ff 00 00 00
这是一个读取 .bmp 文件并写出内容的示例程序。为简洁起见,我删除了错误检查。
int _tmain(int argc, _TCHAR* argv[])
{
HBITMAP bmpIn = (HBITMAP) LoadImage(NULL, argv[1], IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);
FILE * out = _tfopen(argv[2], _T("wb"));
DIBSECTION obj = {0};
GetObject(bmpIn, sizeof(obj), &obj);
cout << "dsBm.bmHeight = " << obj.dsBm.bmHeight << endl;
cout << "dsBmih.biHeight = " << obj.dsBmih.biHeight << endl;
cout << "sizeof(DIBSECTION) = " << sizeof(DIBSECTION) << endl;
fwrite(&obj, sizeof(DIBSECTION), 1, out);
int stride = (((obj.dsBmih.biWidth * obj.dsBmih.biBitCount) + 15) / 16) * 2;
int bytecount = abs(obj.dsBmih.biHeight) * stride;
vector<BYTE> bits(bytecount);
GetBitmapBits(bmpIn, bytecount, &bits[0]);
fwrite(&bits[0], 1, bytecount, out);
fclose(out);
return 0;
}
这是上述程序的输出以及所生成文件的十六进制转储:
dsBm.bmHeight = 7
dsBmih.biHeight = 7
sizeof(DIBSECTION) = 84
00: 00 00 00 00 07 00 00 00 07 00 00 00 18 00 00 00
10: 01 00 18 00 00 00 11 00 28 00 00 00 07 00 00 00
20: 07 00 00 00 01 00 18 00 00 00 00 00 a8 00 00 00
30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
50: 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00
60: 00 00 00 00 00 00 ff ff ff 00 20 00 00 00 00 00
70: 00 00 00 00 00 00 00 00 00 00 00 00 ff ff ff 00
80: 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
90: 00 00 ff ff ff 00 40 00 00 00 00 00 00 00 00 00
a0: 00 00 00 00 00 00 00 00 ff ff ff 00 50 00 00 00
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff ff
c0: ff 00 60 00 00 00 00 00 00 00 00 00 00 00 00 00
d0: 00 00 00 00 ff ff ff 00 70 00 00 00 00 00 00 00
e0: 00 00 00 00 00 00 00 00 00 00 ff ff ff 00
【问题讨论】:
-
查看this link了解更多信息。
-
@Nerdtron,该链接直接与我的观察相矛盾 - 它声明自上而下的 DIB 将具有负高度,但在这种情况下它没有。
-
所以你得到一个正高度的自上而下的DIB?在你调用 LoadImage 之后,你用 HBITMAP 做什么来凭经验发现这一点?我猜您缺少一些细节,而不是 API 实际上返回了错误的数据。只是好奇你在加载后调用了哪些 API。
-
@Nerdtron,我使用了 GetObject 和 GetBitmapBits,并用我自己的代码将结果直接写回了一个文件。我还检查了调试器中的内存以进行仔细检查。
-
GetBitmapBits (here) 的文档说它“将指定设备相关位图的位图位复制到缓冲区中”。在这里,您已经加载了一个与设备无关的位图。所以它可能正在进行转换,因为 GetBitmapBits 的调用者期待自上而下的东西。我只是在猜测,因为我一直都叫 GetDIBits。请注意,我链接到的文档说你不应该调用它,你应该调用 GetDIBits。我敢打赌,如果你调用 GetDIBits,你会得到你所期望的。