【问题标题】:Padding in 24-bits rgb bitmap在 24 位 rgb 位图中填充
【发布时间】:2011-02-05 18:42:49
【问题描述】:

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

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

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

【问题讨论】:

    标签: c padding bmp 24-bit


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        【解决方案3】:

        我认为这是设计决策,以调整更好的内存模式,同时不浪费太多空间(对于 319 像素宽的图像,您将浪费 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 字节)。

        【讨论】:

          【解决方案4】:

          短版

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

          每字节 8 位 ∴ 单元格: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 位字长的计算机。检查您的处理器。

          【讨论】:

            【解决方案5】:

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

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

            Data Structure Padding 上的维基百科文章也是一篇有趣的文章,它解释了填充通常用于计算机科学的原因。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2018-04-01
              • 2011-12-01
              • 2012-07-17
              • 1970-01-01
              • 1970-01-01
              • 2011-11-22
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多