开发者

Padding in 24-bits rgb bitmap

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 t开发者_StackOverflow中文版his 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 );
  }


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.


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.


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).


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜