BMP文件结构

BMP(Bitmap)文件是一种常见的 无损位图图像格式,主要用于存储 像素数据,支持单色、16色、256色和真彩色(24/32位)等模式。以下是其详细结构解析:


一、BMP文件整体结构

BMP文件由 4个主要部分 组成,按顺序排列如下:

  1. 文件头(Bitmap File Header)
    • 文件类型、大小等信息。
  2. 信息头(Bitmap Information Header/DIB Header)
    • 图像的尺寸、颜色格式等元数据。
  3. 调色板(Color Palette,可选)
    • 仅存在于 颜色索引模式(如8位/256色)。
  4. 像素数据(Pixel Data)
    • 实际的图像像素阵列,存储顺序为 从下到上(左下角为起点)。

二、详细结构(以24位真彩色BMP为例)

1. 文件头(14字节)
#pragma pack(push, 1) // 禁用内存对齐
typedef struct {
    uint16_t bfType;      // 文件标识,必须为 "BM"(0x4D42)
    uint32_t bfSize;      // 文件总大小(字节)
    uint16_t bfReserved1; // 保留字段(必须为0)
    uint16_t bfReserved2; // 保留字段(必须为0)
    uint32_t bfOffBits;   // 像素数据偏移量(从文件头到像素数据的字节数)
} BITMAPFILEHEADER;
#pragma pack(pop)
2. 信息头(40字节,BITMAPINFOHEADER版本)
typedef struct {
    uint32_t biSize;          // 本结构体大小(通常为40)
    int32_t  biWidth;         // 图像宽度(像素)
    int32_t  biHeight;        // 图像高度(像素),正数表示从下到上存储
    uint16_t biPlanes;        // 颜色平面数(必须为1)
    uint16_t biBitCount;      // 每像素位数(1/4/8/16/24/32)
    uint32_t biCompression;   // 压缩方式(0表示不压缩)
    uint32_t biSizeImage;     // 像素数据大小(字节),压缩时需填写
    int32_t  biXPelsPerMeter; // 水平分辨率(像素/米)
    int32_t  biYPelsPerMeter; // 垂直分辨率(像素/米)
    uint32_t biClrUsed;       // 实际使用的调色板颜色数(0表示全部)
    uint32_t biClrImportant;  // 重要颜色数(0表示所有颜色均重要)
} BITMAPINFOHEADER;
3. 调色板(仅索引颜色模式需要)
  • 颜色表(Color Table):每个条目为4字节(BGR+保留字节),例如8位BMP有256个条目:
    typedef struct {
        uint8_t rgbBlue;     // 蓝色分量
        uint8_t rgbGreen;    // 绿色分量
        uint8_t rgbRed;      // 红色分量
        uint8_t rgbReserved; // 保留(通常为0)
    } RGBQUAD;
    
4. 像素数据
  • 排列方式
    • 每行像素按 从左到右 存储。
    • 行数据需 4字节对齐(每行末尾可能填充0以满足对齐)。
    • 图像数据从 左下角 开始(高度为正值时)。
  • 24位BMP示例
    每个像素占3字节(按 BGR 顺序存储,无调色板)。

三、关键特性

  1. 无压缩(通常)
    • 多数BMP文件使用 BI_RGB(压缩方式=0),像素数据未压缩。
  2. 颜色深度
    • biBitCount=24:真彩色(BGR各8位)。
    • biBitCount=8:256色(需调色板)。
  3. 行对齐
    • 每行字节数计算公式:
      int rowSize = ((biWidth * biBitCount + 31) / 32) * 4; // 对齐到4字节
      

四、代码示例:读取24位BMP文件

#include <stdio.h>
#include <stdint.h>

// 定义结构体(确保内存布局紧凑)
#pragma pack(push, 1)
typedef struct { /* 文件头和信息头定义同上 */ } BITMAPFILEHEADER, BITMAPINFOHEADER;
#pragma pack(pop)

int main() {
    FILE* file = fopen("image.bmp", "rb");
    if (!file) return 1;

    // 读取文件头和信息头
    BITMAPFILEHEADER fileHeader;
    BITMAPINFOHEADER infoHeader;
    fread(&fileHeader, sizeof(fileHeader), 1, file);
    fread(&infoHeader, sizeof(infoHeader), 1, file);

    // 检查是否为24位无压缩BMP
    if (fileHeader.bfType != 0x4D42 || infoHeader.biBitCount != 24 || infoHeader.biCompression != 0) {
        fclose(file);
        return 1;
    }

    // 分配像素内存(注意行对齐)
    uint8_t* pixels = malloc(infoHeader.biSizeImage);
    fseek(file, fileHeader.bfOffBits, SEEK_SET);
    fread(pixels, 1, infoHeader.biSizeImage, file);

    // 处理像素数据(BGR顺序)
    // ...

    free(pixels);
    fclose(file);
    return 0;
}

五、常见问题

  1. 为什么BMP文件较大?
    • 未压缩的像素数据导致体积远大于JPEG/PNG。
  2. 如何支持透明通道?
    • 使用32位BMP(Alpha通道存储在调色板或像素的第四个字节)。
  3. 高度为负值?
    • 表示像素数据 从上到下 存储(罕见,多数BMP从下到上)。

如果需要解析其他格式(如16位或压缩BMP),可以进一步探讨!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值