填充24位rgb位图

时间:2010-04-08 15:52:05

标签: c padding bmp 24-bit

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

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

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

5 个答案:

答案 0 :(得分:7)

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

答案 1 :(得分:4)

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

  

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

关于Data Structure Padding的维基百科文章也是一篇有趣的读物,解释了填充在计算机科学中普遍使用的原因。

答案 2 :(得分: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];

请注意,如果 n 宽度为奇数(且 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),您的每一次 a b c 的负载都需要分解为自startRow以来的两个负载不能被4整除。在最坏的情况下(例如sun sparc)你的程序会因“总线错误”而崩溃。

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

答案 3 :(得分:1)

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

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

答案 4 :(得分:1)

短版

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

每字节8位∴ cell:32bit =4bytes∴ 像素:24bits = 3bytes

 // 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 ); 
  }

长版

  

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

- wiki: Word_(computer_architecture)

计算机系统基本上有一个首选的字长" (虽然这些天不那么重要)。标准数据单元允许在计算机系统的体系结构中进行各种优化(想想运输容器为运输行业做了什么)。有一个名为DWORD aka Double word (I guess)的32位标准 - 这就是典型的bitmap images优化的标准。

因此,如果每像素有24位,则会有各种"字面像素"行长度不能很好地适应32位。所以在这种情况下,请填写它。

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