Directory of Audio and Video Introduction Articles
Four-byte alignment of BMP images
The bits representing the pixels in BMP bitmaps are aligned in action units, and the size of each row is taken up as a multiple of 4 bytes (32-bit DWORD). If the height of the image is greater than 1, multiple lines aligned by filling form an array of pixels.
The number of bytes required for a full stored row of pixels can be calculated by this formula:
- The end of each line multiplies the length of the line by filling in several bytes of data (not necessarily zero). When an array of pixels is read into memory, the starting address of each row must be a multiple of 4. This restriction is only for the array of pixels in memory. For storage, it only requires the size of each row to be a multiple of 4 bytes, and there is no restriction on file offset.
- For example, for a 24-bit color bitmap, if its width is 1 pixel, it will fill 1 byte in addition to 3 bytes for each row of data (blue, green, red). For a 2-pixel width, it will need 2 bytes; for a 3-pixel width, it will need 3 bytes; and for a 4-pixel width, it will not. Fill it up.
- Under the same image condition, the bitmap image file is usually much larger than the image file using other compression algorithms.
Four-byte alignment problem-discovery
700 x700 BMP file without four-byte alignment
before With RGB, a 700x700 rainbow image was spelled out and successfully saved into a BMP file.
Four-byte alignment was not performed at that time, and the saved BMP file was no problem.
<br/>
Reason:
According to the four-byte alignment requirement, 700 x 3 = 2100, 2100/4 = 525, row pixel data has been four-byte aligned.
What happens if there is no alignment
Change the image size to 711x711:
#include <stdio.h> #include <stdlib.h> // Seven Colors of Rainbow u_int32_t rainbowColors[] = { 0XFF0000, // red 0XFFA500, // orange 0XFFFF00, // yellow 0X00FF00, // green 0X007FFF, // young 0X0000FF, // blue 0X8B00FF // purple }; /*bmp file header*/ typedef struct { unsigned int bfSize; /* Size of file */ unsigned short bfReserved1; /* Reserved */ unsigned short bfReserved2; /* ... */ unsigned int bfOffBits; /* Offset to bitmap data */ } BitmapFileHeader; /*bmp info header*/ typedef struct { unsigned int biSize; /* Size of info header */ int biWidth; /* Width of image */ int biHeight; /* Height of image */ unsigned short biPlanes; /* Number of color planes */ unsigned short biBitCount; /* Number of bits per pixel */ unsigned int biCompression; /* Type of compression to use */ unsigned int biSizeImage; /* Size of image data */ int biXPelsPerMeter; /* X pixels per meter */ int biYPelsPerMeter; /* Y pixels per meter */ unsigned int biClrUsed; /* Number of colors used */ unsigned int biClrImportant; /* Number of important colors */ } BitmapInfoHeader; void writeRGBToBmp(char *filename, int width, int height) { FILE *bitmapFile = fopen(filename, "wb"); if(!bitmapFile) { printf("Could not write file \n"); return; } uint16_t bfType = 0x4d42; BitmapFileHeader fileHeader; fileHeader.bfReserved1 = 0; fileHeader.bfReserved2 = 0; fileHeader.bfSize = 2 + sizeof(BitmapFileHeader) + sizeof(BitmapInfoHeader) + width*height*3; fileHeader.bfOffBits = 0x36; BitmapInfoHeader infoHeader; infoHeader.biSize = sizeof(BitmapInfoHeader); infoHeader.biWidth = width; infoHeader.biHeight = -height; infoHeader.biPlanes = 1; infoHeader.biBitCount = 24; infoHeader.biSizeImage = 0; infoHeader.biCompression = 0; infoHeader.biXPelsPerMeter = 5000; infoHeader.biYPelsPerMeter = 5000; infoHeader.biClrUsed = 0; infoHeader.biClrImportant = 0; fwrite(&bfType, sizeof(bfType), 1, bitmapFile); fwrite(&fileHeader, sizeof(fileHeader), 1, bitmapFile); fwrite(&infoHeader, sizeof(infoHeader), 1, bitmapFile); for (int i = 0; i < width; ++i) { // Current color u_int32_t currentColor = rainbowColors[0]; if(i < 100) { currentColor = rainbowColors[0]; } else if(i < 200) { currentColor = rainbowColors[1]; } else if(i < 300) { currentColor = rainbowColors[2]; } else if(i < 400) { currentColor = rainbowColors[3]; } else if(i < 500) { currentColor = rainbowColors[4]; } else if(i < 600) { currentColor = rainbowColors[5]; } else if(i < 700) { currentColor = rainbowColors[6]; } // Current color R component u_int8_t R = (currentColor & 0xFF0000) >> 16; // Current color G component u_int8_t G = (currentColor & 0x00FF00) >> 8; // Current color B component u_int8_t B = currentColor & 0x0000FF; for (int j = 0; j < height; ++j) { // Write a pixel RGB24 to a file in BGR order fwrite(&B, 1, 1, bitmapFile); fwrite(&G, 1, 1, bitmapFile); fwrite(&R, 1, 1, bitmapFile); } } fclose(bitmapFile); } int main() { writeRGBToBmp("/Users/hubin/Desktop/rainbow-711x711.bmp", 711, 711); return 0; }
<br/>
Rainbow pictures can no longer be displayed:
Four-byte alignment problem-solving
Calculate the number of bytes in a row of pixels aligned with four bytes
// Calculate the number of bytes after 4-byte alignment of each row of pixels int caculateLineBytes(int width) { //********* Four-byte Alignment********** return (24 * width + 31)/32 *4; //********* Four-byte Alignment********** }
Write data to a row of pixels
// Calculate the number of bytes required for four-byte alignment of a row of pixels int lineBytes = caculateLineBytes(width); for (int i = 0; i < width; ++i) { u_int32_t currentColor = rainbowColors[i]; u_int8_t R = (currentColor & 0xFF0000) >> 16; u_int8_t G = (currentColor & 0x00FF00) >> 8; u_int8_t B = currentColor & 0x0000FF; // An array that stores a row of pixel data u_int8_t lineBytesArray[lineBytes]; for (int j = 0; j < height; ++j) { int currentIndex = 3*j; lineBytesArray[currentIndex] = B; lineBytesArray[currentIndex+1] = G; lineBytesArray[currentIndex+2] = R; } // Write a line of four-byte aligned pixel data to a file fwrite(lineBytesArray, sizeof(lineBytesArray), 1, file); }
Complete code
#include <stdio.h> #include <stdlib.h> // Seven Colors of Rainbow u_int32_t rainbowColors[] = { 0XFF0000, // red 0XFFA500, // orange 0XFFFF00, // yellow 0X00FF00, // green 0X007FFF, // young 0X0000FF, // blue 0X8B00FF // purple }; /*bmp file header*/ typedef struct { unsigned int bfSize; /* Size of file */ unsigned short bfReserved1; /* Reserved */ unsigned short bfReserved2; /* ... */ unsigned int bfOffBits; /* Offset to bitmap data */ } BitmapFileHeader; /*bmp info header*/ typedef struct { unsigned int biSize; /* Size of info header */ int biWidth; /* Width of image */ int biHeight; /* Height of image */ unsigned short biPlanes; /* Number of color planes */ unsigned short biBitCount; /* Number of bits per pixel */ unsigned int biCompression; /* Type of compression to use */ unsigned int biSizeImage; /* Size of image data */ int biXPelsPerMeter; /* X pixels per meter */ int biYPelsPerMeter; /* Y pixels per meter */ unsigned int biClrUsed; /* Number of colors used */ unsigned int biClrImportant; /* Number of important colors */ } BitmapInfoHeader; // Calculate the number of bytes after 4-byte alignment of each row of pixels int caculateLineBytes(int width) { //********* Four-byte Alignment********** return (24 * width + 31)/32 *4; //********* Four-byte Alignment********** } void writeRGBToBmp(char *filename, int width, int height) { FILE *bitmapFile = fopen(filename, "wb"); if(!bitmapFile) { printf("Could not write file \n"); return; } uint16_t bfType = 0x4d42; int lineBytes = caculateLineBytes(width); BitmapFileHeader fileHeader; fileHeader.bfReserved1 = 0; fileHeader.bfReserved2 = 0; fileHeader.bfSize = 2 + sizeof(BitmapFileHeader) + sizeof(BitmapInfoHeader) + lineBytes*height; fileHeader.bfOffBits = 0x36; BitmapInfoHeader infoHeader; infoHeader.biSize = sizeof(BitmapInfoHeader); infoHeader.biWidth = width; infoHeader.biHeight = -height; infoHeader.biPlanes = 1; infoHeader.biBitCount = 24; infoHeader.biSizeImage = 0; infoHeader.biCompression = 0; infoHeader.biXPelsPerMeter = 5000; infoHeader.biYPelsPerMeter = 5000; infoHeader.biClrUsed = 0; infoHeader.biClrImportant = 0; fwrite(&bfType, sizeof(bfType), 1, bitmapFile); fwrite(&fileHeader, sizeof(fileHeader), 1, bitmapFile); fwrite(&infoHeader, sizeof(infoHeader), 1, bitmapFile); for (int i = 0; i < width; ++i) { // Current color u_int32_t currentColor = rainbowColors[0]; if(i < 100) { currentColor = rainbowColors[0]; } else if(i < 200) { currentColor = rainbowColors[1]; } else if(i < 300) { currentColor = rainbowColors[2]; } else if(i < 400) { currentColor = rainbowColors[3]; } else if(i < 500) { currentColor = rainbowColors[4]; } else if(i < 600) { currentColor = rainbowColors[5]; } else if(i < 700) { currentColor = rainbowColors[6]; } // Current color R component u_int8_t R = (currentColor & 0xFF0000) >> 16; // Current color G component u_int8_t G = (currentColor & 0x00FF00) >> 8; // Current color B component u_int8_t B = currentColor & 0x0000FF; u_int8_t lineBytesArray[lineBytes]; for (int j = 0; j < height; ++j) { int currentIndex = 3*j; lineBytesArray[currentIndex] = B; lineBytesArray[currentIndex+1] = G; lineBytesArray[currentIndex+2] = R; } fwrite(lineBytesArray, sizeof(lineBytesArray), 1, bitmapFile); } fclose(bitmapFile); } int main() { writeRGBToBmp("/Users/staff/Desktop/rainbow-711x711-fix.bmp", 711, 711); return 0; }
<br/>
Rainbow images of 711x711 are also shown:
Code:
Reference material:
Four-byte alignment of BMP images
non-dword-aligned-pixel-to-dword-aligned-bitmap
generate-bmp-file-from-array-of-rgb-values
Is the content wrong? Contact author: