如何计算位图大小?

时间:2018-02-23 23:42:44

标签: c++ winapi math bitmap

开始研究专门针对Windows的屏幕捕获软件。在MSDN上查看Capturing an Image的示例时,我发现自己有点困惑。

当我提到不包含与实际文件相关联的标题等的位图大小时,请记住。我正在谈论原始像素数据。我原以为公式应该是(width*height)*bits-per-pixel。但是,根据示例,这是计算大小的正确方法:

DWORD dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;

和或:((width*bits-per-pixel + 31) / 32) * 4 * height

我不明白为什么会有涉及31324的额外计算。也许填充?我不确定,但任何解释都会非常感激。我已经尝试过谷歌搜索,但没有找到任何特别有用的结果。

2 个答案:

答案 0 :(得分:6)

表示位图像素的位按行打包。通过填充将每行的大小向上舍入为4个字节(32位DWORD)的倍数。

(bits_per_row + 31)/ 32 * 4确保向上舍入到下一个32位的倍数。答案是以字节为单位,而不是因此* 4而不是* 32。

请参阅:https://en.wikipedia.org/wiki/BMP_file_format

答案 1 :(得分:4)

Bitmap Header Types下,您会发现以下内容:

  

扫描线 DWORD 对齐[...]。它们必须填充扫描线宽,以字节为单位,不能被四[...]整除。例如,10×10像素的24-bpp位图在每条扫描线的末尾将有两个填充字节。

公式

((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4

建立DWORD - 对齐(以字节为单位)。尾部* 4实际上是* 32 / 8的结果,其中乘以32产生的值是32的倍数(以位为单位),除以8将其转换回字节。

虽然这确实产生了预期的结果,但我更喜欢不同的实现。 DWORD是32位,即2的幂。舍入到2的幂可以使用以下公式实现:

(value + ((1 << n) - 1)) & ~((1 << n) - 1)

添加(1 << n) - 1调整初始值以超过下一个 n 次幂2(除非它已经是 n 次幂2 )。 (1 << n) - 1求值为一个值,其中 n 最低有效位置位,~((1 << n) - 1)否定该值,即除 n 最低有效位之外的所有位已设定。这用作去除调整后的初始值的 n 最低有效位的掩码。

应用于此特定情况,其中DWORD为32位,即 n 为5,(1 << n) - 1的计算结果为31. value 是原始扫描线宽度,以位为单位:

auto raw_scanline_width_in_bits{ bmpScreen.bmWidth * bi.biBitCount };
auto aligned_scanline_width_in_bits{ (raw_scanline_width_in_bits + 31) & ~31 };
auto aligned_scanline_width_in_bytes{ raw_scanline_width_in_bits / 8 };

这会产生相同的结果,但会提供不同的视角,某些人可能更容易理解。