24 位 RGB 位图中的填充

发布于 2024-08-27 19:12:04 字数 256 浏览 7 评论 0原文

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

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

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

could somebody explain to me why in 24-bit rgb bitmap file I have to add a padding which size depends on width of image ? What for ?

I mean I must add this code to my program (in C):

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

疧_╮線 2024-09-03 19:12:04

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

Because 24 bits is an odd number of bytes (3) and for a variety of reasons all the image rows are required to start at an address which is a multiple of 4 bytes.

趴在窗边数星星i 2024-09-03 19:12:04

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

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

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

According to Wikipedia, the bitmap file format specifies that:

The bits representing the bitmap pixels are packed in rows. The size of each row is rounded up to a multiple of 4 bytes (a 32-bit DWORD) by padding. Padding bytes (not necessarily 0) must be appended to the end of the rows in order to bring up the length of the rows to a multiple of four bytes. When the pixel array is loaded into memory, each row must begin at a memory address that is a multiple of 4. This address/offset restriction is mandatory only for Pixel Arrays loaded in memory. For file storage purposes, only the size of each row must be a multiple of 4 bytes while the file offset can be arbitrary. A 24-bit bitmap with Width=1, would have 3 bytes of data per row (blue, green, red) and 1 byte of padding, while Width=2 would have 2 bytes of padding, Width=3 would have 3 bytes of padding, and Width=4 would not have any padding at all.

The wikipedia article on Data Structure Padding is also an interesting read that explains the reasons that paddings are generally used in computer science.

归属感 2024-09-03 19:12:04

我认为这是设计决策,旨在对齐更好的内存模式,同时不浪费那么多空间(对于 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;

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

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

I presume this was design decision to align for better memory patterns while not wasting that much space (for 319px wide image you would waste 3 bytes or 0.25%)

Imagine you need to access some odd row directly. You could access first 4 pixels of n-th row by doing:

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];

Note that if n and width are odd (and bmp is even), startRow is going to be odd.

Now if you tried to do following speedup:

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;

You'd run into lots of problems. In best case scenario (that is intel cpu) your every load of a, b and c would need to be broken into two loads since startRow is not divisible by 4. In worst case scenario (eg. sun sparc) your program would crash with "bus error".

In newer designs it is common to force rows to be aligned to at least L1 cache line size (64 bytes on intel or 128 bytes on nvidia gpus).

泡沫很甜 2024-09-03 19:12:04

简短版本

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

每字节 8 位 ∴
单元:32位=4字节∴
像素: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)

计算机系统基本上都有一个首选的“字长”(尽管现在不那么重要)。标准数据单元允许对计算机系统的架构进行各种优化(想想集装箱为航运业所做的事情)。有一个 32 位标准,称为 DWORD 又名双字(I猜测) - 这就是典型的位图图像的优化目标。

因此,如果每个像素有 24 位,则会出现各种“文字像素”行长度,无法很好地适应 32 位。所以在这种情况下,请将其填充掉。

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

Short version

Because the bmp file format specifies rows must perfectly fit in a 32bits "memory cells". Because pixels are 24bits, some combinations of pixels will not perfect sit in 32bit "cells". In this case, the cell is "padded up to" the full 32bits.

8bits per byte ∴
cell: 32bit = 4bytes ∴
pixel: 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 ); 
  }

Long version

In computing, a word is the natural unit of data used by a particular processor design. A word is a fixed-sized piece of data handled as a unit by the instruction set or the hardware of the processor

-wiki: Word_(computer_architecture)

Computer systems basically have a preferred "word length" (though not so important these days). A standard data unit allows all sorts of optimisations in the architecture of the computer system (think what shipping containers did for the shipping industry). There is a 32 bit standard called DWORD aka Double word (I guess) - and thats what typical bitmap images are optimised for.

So if you have 24bits per pixel, there will be various "literal pixels" row lengths that will not fit nicely into the 32bits. So in that case, pad it out.

Note: today, you are probably using a computer with a 64bit word size. Check your processor.

浅唱々樱花落 2024-09-03 19:12:04

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

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

It depends on the format whether or not there is padding at the end of each row.

There really isn't much reason for it for 3 x 8 bit channel images since I/O is byte oriented anyway. For images with pixels packed into less than a byte (1 bit / pixel for example), padding is useful so that each row starts at a byte offset.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文