开始研究专门针对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
我不明白为什么会有涉及31
,32
和4
的额外计算。也许填充?我不确定,但任何解释都会非常感激。我已经尝试过谷歌搜索,但没有找到任何特别有用的结果。
答案 0 :(得分:6)
表示位图像素的位按行打包。通过填充将每行的大小向上舍入为4个字节(32位DWORD)的倍数。
(bits_per_row + 31)/ 32 * 4确保向上舍入到下一个32位的倍数。答案是以字节为单位,而不是因此* 4而不是* 32。
答案 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 };
这会产生相同的结果,但会提供不同的视角,某些人可能更容易理解。