Categories
Uncategorized

Audio and video entry -04-BMP image four-byte alignment issues

* Audio and video how-to articles directories *

BMP images four-byte alignment

Bit bitmap BMP represents the pixel is aligned in units of storage, the size of each row are rounded up to a multiple of 4 bytes (32-bit DWORD) a. If the height of the image is greater than 1, via a plurality of rows to achieve alignment padding pixel array is formed.

Number of bytes required to store a complete row of pixels can be calculated by this formula:

  • End of each line so that the length of the line by filling a plurality of bytes of data (not necessarily zero) is a multiple of 4 bytes. The pixel array is read into memory, the start address of each row must be a multiple of four. The only restriction for the pixel array in memory, for the storage time, the size of each row is only required for the multiple of 4 bytes, there is no restriction on the offset in the file.

  • For example: For a 24-bit color bitmaps, and if its width is 1 pixel, each row of data in addition to (blue, green, red) representing requires 3 bytes, the byte 1 will be filled; and if the width is 2 pixels, the 2-byte padding is required; is 3 pixels wide, requires 3 bytes of padding; a width of 4 pixels is not required when filling.

  • Under the same conditions the image, a bitmap image file is typically much larger than the other image files using the compression algorithm.

Four-byte alignment problem – find

No 700×700 BMP-aligned four-byte file

Before using RGB spell rainbow picture a 700×700 and save as BMP file successfully.

It did not carry out four-byte alignment, saved as BMP files no problem.

the reason:
    The four-byte alignment requirements, 700 x 3 = 2100,2100 / 4 = 525, the pixel data row has a four-byte alignment.

What happens if there is no alignment

Change the picture size to 711×711:

#include 
#include 

// 彩虹的七种颜色
u_int32_t rainbowColors[] = {
        0XFF0000, // 红
        0XFFA500, // 橙
        0XFFFF00, // 黄
        0X00FF00, // 绿
        0X007FFF, // 青
        0X0000FF, // 蓝
        0X8B00FF  // 紫
};

/*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) {

        // 当前颜色
        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];
        }
        // 当前颜色 R 分量
        u_int8_t R = (currentColor & 0xFF0000) >> 16;
        // 当前颜色 G 分量
        u_int8_t G = (currentColor & 0x00FF00) >> 8;
        // 当前颜色 B 分量
        u_int8_t B = currentColor & 0x0000FF;

        for (int j = 0; j < height; ++j) {
            // 按 BGR 顺序写入一个像素 RGB24 到文件中
            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;
}

Rainbow picture has been unable to show out:

Four-byte alignment problem - solving

Computing a row of pixels, the number of bytes after the four-byte alignment

// 计算每一行像素 4 字节对齐后的字节数
int caculateLineBytes(int width) {
    //******* 四字节对齐 *******
    return (24 * width + 31)/32 *4;
    //******* 四字节对齐 *******
}

Data is written to 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;

    // 存储一行像素数据的数组
    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, file);
}

The full code

#include 
#include 

// 彩虹的七种颜色
u_int32_t rainbowColors[] = {
        0XFF0000, // 红
        0XFFA500, // 橙
        0XFFFF00, // 黄
        0X00FF00, // 绿
        0X007FFF, // 青
        0X0000FF, // 蓝
        0X8B00FF  // 紫
};

/*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;

// 计算每一行像素 4 字节对齐后的字节数
int caculateLineBytes(int width) {
    //******* 四字节对齐 *******
    return (24 * width + 31)/32 *4;
    //******* 四字节对齐 *******
}

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

        // 当前颜色
        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];
        }
        // 当前颜色 R 分量
        u_int8_t R = (currentColor & 0xFF0000) >> 16;
        // 当前颜色 G 分量
        u_int8_t G = (currentColor & 0x00FF00) >> 8;
        // 当前颜色 B 分量
        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;
}

711x711 的彩虹图片也显示出来了:


Code:

04-rgb-to-bmp-fix

References:

BMP images four-byte alignment issues

Wikipedia -BMP

non-dword-aligned-pixel-to-dword-aligned-bitmap

generate-bmp-file-from-array-of-rgb-values

Content is incorrect? Contact the author:


Leave a Reply