[Digital image] BMP file format Detailed

BMP file format Detailed

-------------------------------------------------------------------------------------------------------

Lena

 

Wikipedia excerpt: BMP is the English Bitmap (bitmap) shorthand, it is the Windows operating system in a standard image file format, which can be a variety of Windows supported by the application.

BMP files are stored in the original BGR data format is very simple, Digital map entry required. Because the data without any compression, so BMP files are large.

 

BMP file format

  • File Information  -> BITMAPFILEHEADER
  • Image Information  -> BITMAPINFOHEADER
  • Palette      -> determined by the color index number
  • Image data  -> is determined by the image size

 

1. BITMAPFILEHEADER

typedef struct {

    WORD  bfType;

    DWORD bfSize;

    BECOME bfReserved1;

    WORD  bfReserved2;

    DWORD bfOffBits;

} BITMAP_FILE_HEADER;

 

WORD --> unsigned short

DWORD -> unsigned long (32 bit account . 4 bits 64 bit accounting . 8 bit )

 

variable name

Size ( bytes )

effect

bfType

2

File header BM

bfSize

4

The entire file size

bfReserved1

2

Retention

bfReserved2

2

Retention

bfOffBits

4

Offset, the offset length is generally BITMAPFILEHEADER + BITMAPINFOHEADER, if there is a palette with palette change in length

 

2.BITMAPINFOHEADER

typedef struct BITMAP_INFO_HEADER {

    DWORD size;

    int     biWidth;

    int     biHeight;

    WORD  biPlanes;

    WORD  biBitCount;

    DWORD biCompression;

    DWORD biSizeImage;

    int     biXPelsPerMeter;

    int     biYPelsPerMeter;

    DWORD biClrUsed;

    DWORD biClrImportant;

} BITMAP_INFO_HEADER;

 

Here int turned out to be Long , 64- under-bit change will go wrong next.

 

variable name

Size ( bytes )

effect

Size

4

sizeof(BITMAP_INFO_HEADER)

biWidth

4

width

biHeight

4

height

BMP文件图像是倒着存储的,所以如果biHeight>0表示图像是倒立的,如果biHeight<0表示图像是正的。

biPlanes

2

颜色平面数

biBitCount

2

位数(1,4,8,16,24,32)

biCompression

4

压缩

0 BI_RGB(BMP文件不压缩)

1 BI_RLE8

2 BI_RLE4

3 BI_BITFILELDS

4 BI_JPEG

5 BI_PNG

biSizeImage

4

图像数据大小

biXPelsPerMeter

4

水平分辨率

biYPelsPerMeter

4

垂直分辨率

biClrUsed

4

实际使用的颜色索引数

biClrImportant

4

对图像显示有重要影响的颜色索引的数目,如果是0表示都重要

 

3.调色板

调色板实际上是一种颜色索引表,因为常见的BMP文件都是2432位的,而2432位不需要调色板,所以这里不做过多研究。

 

4.图像数据

24位位图 -->  bgr,bgr,bgr

32位位图 -->  bgra,bgra,bgra

 

5.内存对齐

Windows默认是4字节对齐,如果不了解内存对齐可以研究一下,c语言sizeof(结构体)的大小。内存对齐的主要目的是为了加速,BMP文件也需要进行内存对齐处理,简单来说就是每一行的字节数%4==0,如果不足则由0补足。比如:一个24BMP,宽度为99,那么他的图像部分字节数位 99 * 3 ==> 297 % 4 = 1,需要补3个字节0

 

参考文章:

https://www.cnblogs.com/Matrix_Yao/archive/2009/12/02/1615295.html

 

 

/*****************************************************
   BMP文件读写 
   [email protected] 
*****************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef unsigned short WORD;
typedef unsigned int DWORD;

#pragma pack(1)
typedef struct {
    WORD  bfType;
    DWORD bfSize;
    WORD  bfReserved1;
    WORD  bfReserved2;
    DWORD bfOffBits;
} BITMAP_FILE_HEADER;

typedef struct BITMAP_INFO_HEADER { 
    DWORD biSize; 
    int   biWidth; 
    int   biHeight; 
    WORD  biPlanes; 
    WORD  biBitCount; 
    DWORD biCompression; 
    DWORD biSizeImage; 
    int   biXPelsPerMeter; 
    int   biYPelsPerMeter; 
    DWORD biClrUsed; 
    DWORD biClrImportant; 
} BITMAP_INFO_HEADER;
#pragma pack()

/**
 * 32->24
 */
static void bmp_remove_aplpha (unsigned char *data, unsigned char *buf, size_t *size, size_t w, size_t h) {
    size_t i = 0, j = 0, dst_fix = 0;

    dst_fix = 4 - ((w * 24)>>3) & 3;
    *size = ((((w * 24) + 31) >> 5) << 2) * h;

    for (j = 0; j < h; j++) {
        for (i = 0; i < w; i++) {
            memcpy(buf, data, 3);
            data += 4;
            buf += 3;
        }
        buf += dst_fix;
    }
}

/**
 * 倒转图像
 */
static void bmp_reverse (unsigned char *data, unsigned char *buf, size_t size, size_t w, size_t h) {
    unsigned char *src = NULL;
    int i = 0, j = 0, preline = 0;
    
    preline = size / h;
    for (i = 0, j = h - 1; j >= 0; i++, j--) {
        src = data + j * preline;
        memcpy(buf + i * preline, src, preline);
    }
}

/**
 * bmp_read
 * 
 * 读取一个BMP文件
 * 只支持24/32位,32位会转为24位,倒转的图像会摆正
 */
unsigned char *bmp_read (const char *path, size_t *size, size_t *w, size_t *h) {
    FILE *fp = NULL;
    BITMAP_FILE_HEADER file = {0};
    BITMAP_INFO_HEADER info = {0};
    unsigned char *data = NULL, *buf = NULL;
    
    if (!path || *path == 0 || !size || !w || !h)
        return NULL;
    
    if (!(fp = fopen(path, "rb")))
        return NULL;

    if (fread(&file, 1, sizeof(BITMAP_FILE_HEADER), fp) != sizeof(BITMAP_FILE_HEADER)) {
        fclose(fp);
        return NULL;
    }

    if (fread(&info, 1, sizeof(BITMAP_INFO_HEADER), fp) != sizeof(BITMAP_INFO_HEADER)) {
        fclose(fp);
        return NULL;
    }

    //非BM开头
    if (file.bfType != 0x4d42) {
        fclose(fp);
        return NULL;
    }

    //暂时只能支持24与32位
    if (info.biBitCount != 24 && info.biBitCount != 32) {
        fclose(fp);
        return NULL;
    }

    if (info.biSizeImage == 0) {
        info.biSizeImage = info.biWidth * abs(info.biHeight) * (info.biBitCount == 24 ? 3 : 4);
    }
    
    data = (unsigned char *)malloc(sizeof(unsigned char) * info.biSizeImage);
    buf = (unsigned char *)malloc(sizeof(unsigned char) * info.biSizeImage);
    if (!data || !buf) {
        if (data) free(data);
        if (buf) free(buf);
        fclose(fp);
        return NULL;
    }
    
    if (fread(data, 1, info.biSizeImage, fp) != info.biSizeImage) {
        free(data);
        free(buf);
        fclose(fp);
        return NULL;
    }
    
    fclose(fp);
    
    *size = info.biSizeImage;
    *w = info.biWidth;
    *h = abs(info.biHeight);
    
    //32转24
    if (info.biBitCount == 32) {
        bmp_remove_aplpha(data, buf, size, *w, *h);
        memcpy(data, buf, *size);
    }
    
    //图像倒转
    if (info.biHeight > 0) {
        bmp_reverse(data, buf, *size, *w, *h);
        memcpy(data, buf, *size);
    }

    free(buf);
    return data;
}

/**
 * bmp_write
 */
int bmp_write (unsigned char *data, size_t size, size_t w, size_t h, const char *path) {
    FILE *fp = NULL;
    BITMAP_FILE_HEADER file = {0};
    BITMAP_INFO_HEADER info = {0};
    unsigned char *src = NULL;
    int hsrc = 0, preline = 0;
    
    if (!data || size == 0 || w == 0 || h == 0 || !path || *path == 0)
        return 0;
    
    if (!(fp = fopen(path, "wb+")))
        return 0;

    file.bfType = 0x4d42;
    file.bfSize = sizeof(BITMAP_FILE_HEADER) + sizeof(BITMAP_INFO_HEADER) + size;
    file.bfReserved1 = 0;
    file.bfReserved2 = 0;
    file.bfOffBits = sizeof(BITMAP_FILE_HEADER) + sizeof(BITMAP_INFO_HEADER);
    
    info.biSize = sizeof(BITMAP_INFO_HEADER);
    info.biWidth = w;
    info.biHeight = h;
    info.biPlanes = 1;
    info.biBitCount = 24;
    info.biCompression = 0L;
    info.biSizeImage = size;
    info.biXPelsPerMeter = 0;
    info.biYPelsPerMeter = 0;
    info.biClrUsed = 0;
    info.biClrImportant = 0;
    
    fwrite(&file, 1, sizeof(BITMAP_FILE_HEADER), fp);
    fwrite(&info, 1, sizeof(BITMAP_INFO_HEADER), fp);
    
    //倒转写入图像数据
    preline = size / h;
    for (hsrc = h - 1; hsrc >= 0; hsrc--) {
        src = data + hsrc * preline;
        fwrite(src, 1, preline, fp);
    }
    
    fclose(fp);
    return 1;
}

int main (int argc, char *argv[]) {
    unsigned char *data = NULL;
    size_t size = 0, w = 0, h = 0;
    
    data = bmp_read("1.bmp", &size, &w, &h);
    bmp_write(data, size, w, h, "2.bmp");
    return 1;
}

 

Guess you like

Origin www.cnblogs.com/hatsusakana/p/12643850.html