BMP image reading

Posted by DJM on Wed, 05 Jan 2022 16:23:14 +0100

0. Introduction to BMP format

According to Baidu Encyclopedia BMP We know that BMP is the abbreviation of Bitmap and the standard image file format in the Windows operating system. It is characterized by rich image information because it is hardly compressed, but it also occupies a large disk space.

1 file format

The bitmap file consists of four parts:

  1. Bitmap file header
  2. Bitmap information header
  3. Color table: use the index to represent the image. At this time, the color table is the mapping table between the index and its corresponding color (that is, find the corresponding pixel information by combining the index value with the color table)
  4. Bitmap data (data bits)

The above different parts have different data structures. The data structures of the first three parts are introduced below.

Data segment nameCorresponding Windows structure definitionSize (Byte)
bmp file headerBITMAPFILEHEADER       14
bmp header     BITMAPINFOHEADER        40
color tableDetermined by color index number
bmp dataDetermined by image size

2 bitmap header file

In this paper, the file format of BMP image is analyzed according to the above figure. Before analyzing the image data, it should be emphasized that in the BMP file, the data storage mode is small endian, that is, assuming that a data needs multiple bytes to represent, the order of data storage bytes is "low address stores status data, high address stores high-level data". In hexadecimal, a number occupies 4 bits, so each byte can store 2 hexadecimal digits.

Therefore, the storage order of data 0x1756 in memory is:

The structure of bitmap header file is defined as follows:

typedef struct tagBITMAPFILEHEADER 
{  
    UINT16 bfType;    // 19778 must be a BM string, the corresponding hexadecimal is 0x4d42 and the decimal is 19778, otherwise it is not a bmp format file
    DWORD bfSize; // File size in bytes (2-5 bytes)
    UINT16 bfReserved1; // Reserved, must be set to 0 (6-7 bytes)
    UINT16 bfReserved2; // Reserved, must be set to 0 (8-9 bytes)
    DWORD bfOffBits;    // Offset from file header to pixel data (10-13 bytes)
} BITMAPFILEHEADER;

In VScode, BMP image data can be viewed in binary form by installing the hexdump plug-in.

You can see by comparing the structure and file data:

0-1: 0x4d42='BM ', indicating that this is a bitmap format supported by Windows

2-5: 0x000088EA indicates the file size

6-9: reserved segment, 0

A-D: 0x00000436 = 1078, indicating that 1078 bytes need to be offset from the file header to the bitmap data

[note] when opening a file with fopen to get the file handle and read the corresponding data, there is a problem that the structure memory is aligned, which will cause errors in subsequent data reading.

What is memory alignment? For details, please refer to the article: Alignment of structure members in memory

The specific performance of the above problems can be realized through the following code:

#include <stdio.h>

typedef struct tagBITMAPFILEHEADER 
{  
    unsigned short bfType;    // 19778 must be a BM string, the corresponding hexadecimal is 0x4d42, and the decimal is 19778. Otherwise, it is not a bmp format file (0-4)
    int bfSize; // File size in bytes (2-5 bytes) (4-8)
    unsigned short bfReserved1; // Reserved, must be set to 0 (6-7 bytes) (8-10)
    unsigned short bfReserved2; // Reserved, must be set to 0 (8-9 bytes) (10-12)
    int bfOffBits;    // Offset from file header to pixel data (10-13 bytes) (12-16)
} BITMAPFILEHEADER;

int main(int argc, char* argv[])
{
    printf("sizeof(BITMAPFILEHEADER) = %lu\n", sizeof(BITMAPFILEHEADER));
    return 0;
}

// sizeof(BITMAPFILEHEADER) = 16

There are two ways to turn off memory alignment of structures: add preprocessing instruction #pragma pack(1) or__ attribute__ ((packed)). The difference between the two methods is:

  • #pragma pack(1) preprocessing instruction is to close the memory alignment mode of the whole file
  • __ attribute__ ((packed)) instruction is for the specified structure
#include <stdio.h>

// #pragma pack(1)

typedef struct tagBITMAPFILEHEADER 
{  
    unsigned short bfType;    // 19778 must be a BM string, the corresponding hexadecimal is 0x4d42, and the decimal is 19778. Otherwise, it is not a bmp format file (0-4)
    int bfSize; // File size in bytes (2-5 bytes) (4-8)
    unsigned short bfReserved1; // Reserved, must be set to 0 (6-7 bytes) (8-10)
    unsigned short bfReserved2; // Reserved, must be set to 0 (8-9 bytes) (10-12)
    int bfOffBits;    // Offset from file header to pixel data (10-13 bytes) (12-16)
}__attribute__ ((packed)) BITMAPFILEHEADER;

int main(int argc, char* argv[])
{
    printf("sizeof(BITMAPFILEHEADER) = %lu\n", sizeof(BITMAPFILEHEADER));
    return 0;
}

// sizeof(BITMAPFILEHEADER) = 14

3 bitmap header

The structure of bitmap header is defined as follows:

typedef struct tagBITMAPINFOHEADER
{
    unsigned int    biSize;          // Size of this structure (14-17 bytes)
    long            biWidth;         // Width of image (18-21 bytes)
    long            biHeight;        // Image height (22-25 bytes)
    unsigned short  biPlanes;        // It indicates the plane of bmp image. Obviously, the display has only one plane, so it is equal to 1 (26-27 bytes)
    unsigned short  biBitCount;      // The number of bits occupied by a pixel, usually 24 (28-29 bytes)
    unsigned int    biCompression;   // Describes the type of image data compression. 0 is not compressed. (30-33 bytes)
    unsigned int    biSizeImage;     // The size of pixel data, which should be equal to bfsize bfoffbits (34-37 bytes) in the file header structure above
    long            biXPelsPerMeter; // Indicates the horizontal resolution in pixels per meter. Generally 0 (38-41 bytes)
    long            biYPelsPerMeter; // Indicates the vertical resolution in pixels per meter. Generally 0 (42-45 bytes)
    unsigned int    biClrUsed;       // Indicates the number of color indexes in the color table actually used by the bitmap (if set to 0, all palette items are used). (46-49 bytes)
    unsigned int    biClrImportant;  // Indicates the number of color indexes that have an important impact on image display. If it is 0, it means that they are important. (50-53 bytes)
} BITMAPINFOHEADER;

4 color table

The color table is essentially a query table, which queries the corresponding color through the color serial number. The layout in the file is similar to a two-dimensional array palette[N][4] The four elements represent the corresponding values of B, G, R and Alpha, and each component accounts for one byte. N is generally equal to 256.

There are 256 colors in total. Each color occupies 4 bytes, that is, 1024 bytes in total. Plus the 54 bytes of the previous file information header and bitmap information header, the total is 1078 bytes.

5. Bitmap data

In bitmap data, each pixel occupies one byte. Take the number of bytes as the color index, go to the color table to query the corresponding color and display it.

6. Reference links

c realize BMP to JPG with source code_ Etc. jzy's blog - CSDN blog_ c language BMP to jpg

The idea and details of reading and writing bitmap (BMP) with c and cpp - et3_tsy - blog Park (cnblogs.com)

C language realizes the reading and writing function of BMP image_ C language_ Script house (jb51.net)

Reading BMP files with C language - Zhihu (zhihu.com)

BMP file format - Yao Weifeng - blog Park (cnblogs.com)

Alignment of structure members in memory – My Code

Topics: Computer Vision image processing BMP