11

有人可以向我解释为什么在 24 位 rgb 位图文件中我必须添加一个填充,其大小取决于图像的宽度?做什么的 ?

我的意思是我必须将此代码添加到我的程序中(在 C 中):

 if( read % 4 != 0 ) {
   read = 4 - (read%4);
   printf( "Padding: %d bytes\n", read );
   fread( pixel, read, 1, inFile );
  }
4

5 回答 5

8

因为 24 位是奇数字节 (3),并且由于各种原因,所有图像行都需要从 4 字节的倍数的地址开始。

于 2010-04-08T15:54:50.007 回答
6

根据Wikipedia,位图文件格式指定:

表示位图像素的位被打包成行。每行的大小通过填充四舍五入为 4 字节(32 位 DWORD)的倍数。填充字节(不一定是 0)必须附加到行的末尾,以便将行的长度增加到四个字节的倍数。当像素阵列加载到内存中时,每行必须从 4 的倍数的内存地址开始。此地址/偏移限制仅对加载到内存中的像素阵列是强制性的。出于文件存储目的,只有每行的大小必须是 4 字节的倍数,而文件偏移量可以是任意的。Width=1 的 24 位位图,每行将有 3 个字节的数据(蓝色、绿色、红色)和 1 个字节的填充,而 Width=2 将有 2 个字节的填充,Width=3 将有 3 个字节的填充填充,而 Width=4 根本没有任何填充。

关于数据结构填充的维基百科文章也是一篇有趣的读物,它解释了填充通常用于计算机科学的原因。

于 2016-11-16T07:46:22.877 回答
3

我认为这是设计决策,以调整更好的内存模式,同时不浪费那么多空间(对于 319px 宽的图像,你会浪费 3 个字节或 0.25%)

想象一下,您需要直接访问一些奇怪的行。您可以通过执行以下操作访问第 n 行的前 4 个像素:

uint8_t *startRow = bmp + n * width * 3; //3 bytes per pixel
uint8_t r1 = startRow[0];
uint8_t g1 = startRow[1];
//... Repeat
uint8_t b4 = startRow[11];

请注意,如果nwidth是奇数(并且bmp是偶数),则startRow将是奇数。

现在,如果您尝试执行以下加速:

uint32_t *startRow = (uint32_t *) (bmp + n * width * 3);
uint32_t a = startRow[0]; //Loading register at a time is MUCH faster
uint32_t b = startRow[1]; //but only if address is aligned
uint32_t c = startRow[2]; //else code can hit bus errors!

uint8_t r1 = (a & 0xFF000000) >> 24;
uint8_t g1 = (a & 0x00FF0000) >> 16;
//... Repeat
uint8_t b4 = (c & 0x000000FF) >>  0;

你会遇到很多问题。在最好的情况下(即 intel cpu),您的abc的每个负载都需要分成两个负载,因为 startRow 不能被 4 整除。在最坏的情况下(例如 sun sparc),您的程序将崩溃“总线错误”。

在较新的设计中,通常强制行至少与 L1 缓存行大小对齐(intel 上为 64 字节,nvidia gpus 上为 128 字节)。

于 2015-09-24T14:49:14.323 回答
3

精简版

因为 bmp 文件格式指定行必须完全适合 32 位“内存单元”。因为像素是 24 位的,某些像素组合不会完美地位于 32 位“单元”中。在这种情况下,单元被“填充”到完整的 32 位。

每字节 8 位 ∴ 单元:32 位 = 4 字节 ∴ 像素:24 位 = 3 字节

 // If doesn't fit perfectly in 4 byte "cell"
 if( read % 4 != 0 ) {
   // find the difference between the "cell", and "the partial fit"
   read = 4 - (read%4); 
   printf( "Padding: %d bytes\n", read ); 
   // skip the difference 
   fread( pixel, read, 1, inFile ); 
  }

长版

在计算中,单词是特定处理器设计使用的自然数据单位。字是由指令集或处理器硬件作为一个单元处理的固定大小的数据

-维基:Word_(计算机架构)

计算机系统基本上有一个首选的“字长”(尽管这些天并不那么重要)。标准数据单元允许对计算机系统的架构进行各种优化(想想集装箱为航运业做了什么)。有一个 32 位标准,称为DWORD aka Double word(我猜) ——这就是典型的位图图像的优化目标。

因此,如果每个像素有 24 位,则会有各种“文字像素”行长度不能很好地适应 32 位。所以在这种情况下,把它垫出来。

注意:今天,您可能使用的是 64 位字长的计算机。检查你的处理器。

于 2016-06-22T14:57:36.600 回答
1

每行末尾是否有填充取决于格式。

3 x 8 位通道图像确实没有太多理由,因为 I/O 无论如何都是面向字节的。对于像素打包成小于一个字节(例如 1 位/像素)的图像,填充很有用,因此每一行都从一个字节偏移量开始。

于 2010-04-08T16:18:15.487 回答