---
title: "BMP图片格式"
source: https://www.iowill.com/blog/2024/09/bmp-image-format/
date: 2024-09-20
updated: 2026-10-14
tags: [BMP, 图像格式]
categories: [编程开发]
---

# BMP图片格式

BMP 位图文件把图像尺寸、像素格式和像素数据放在同一文件中。下面以 Windows 常见的 **40 字节 BITMAPINFOHEADER、24 位、BI\_RGB 未压缩**格式为例；调色板、位域掩码和压缩 BMP 需要按各自格式另外解析。

## 文件从哪里开始读

常见布局为文件头、DIB 信息头、可选颜色信息、像素数据。文件头中的 `bfOffBits`给出像素区相对文件起点的偏移，不能一律假定像素从第 54 字节开始。信息头也有多个版本，应先读 `biSize` 再决定解析方式。参见微软的[位图头类型说明](https://learn.microsoft.com/en-us/windows/win32/gdi/bitmap-header-types)。

![BMP 位图文件结构示意图](https://s2.loli.net/2024/09/20/hmtQkegKV2XfE45.png)

## 14 字节文件头

下表偏移以文件起点为零。整数按小端读取：低有效字节在前，例如 `36 00 00 00` 表示十进制 54。文件开头的两个字节为 `42 4D`，对应 ASCII 字符 `BM`。

| 偏移 | 大小 | 字段 | 含义 |
| --- | --- | --- | --- |
| 0 | 2 字节 | bfType | 文件标识，数值为 0x4D42 |
| 2 | 4 字节 | bfSize | 文件总大小，单位为字节 |
| 6 | 2 字节 | bfReserved1 | 保留，必须为 0 |
| 8 | 2 字节 | bfReserved2 | 保留，必须为 0 |
| 10 | 4 字节 | bfOffBits | 像素数据的起始偏移 |

字段定义见 [BITMAPFILEHEADER](https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapfileheader)。读取二进制文件时还要检查实际长度，不能只信任头部声明的大小。

## 40 字节信息头

本例信息头紧跟文件头，下表偏移仍从文件起点计算。

| 偏移 | 大小 | 字段 | 本例中的含义 |
| --- | --- | --- | --- |
| 14 | 4 字节 | biSize | 信息头本身的大小，为 40 |
| 18 | 4 字节 | biWidth | 有符号整数，图像宽度，单位为像素 |
| 22 | 4 字节 | biHeight | 有符号整数，绝对值为高度，符号决定行方向 |
| 26 | 2 字节 | biPlanes | 必须为 1 |
| 28 | 2 字节 | biBitCount | 每像素位数，本例为 24 |
| 30 | 4 字节 | biCompression | BI\_RGB 为 0，表示本例像素未压缩 |
| 34 | 4 字节 | biSizeImage | 像素区大小；未压缩 RGB 允许填 0，需据尺寸计算 |
| 38、42 | 各 4 字节 | biXPelsPerMeter、biYPelsPerMeter | 水平、垂直分辨率，单位为像素/米 |
| 46、50 | 各 4 字节 | biClrUsed、biClrImportant | 使用的颜色数与重要颜色数；本例无颜色表，均为 0 |

字段与方向说明见 [BITMAPINFOHEADER](https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader)。24 位像素以蓝、绿、红（BGR）三个字节存储，每通道 8 位，没有独立的透明度通道。

## 行对齐和图像方向

24 位像素每行的有效数据是 `width × 3` 字节，文件中的每行要补齐到 4 字节的整数倍。补齐字节不属于下一个像素。可按下列公式计算行跨度与像素区大小：

```plaintext
stride = ((width * 24 + 31) // 32) * 4
pixel_bytes = stride * abs(height)
```

例如宽度 3、高度 2：每行像素占 9 字节，需要补 3 字节，行跨度为 12 字节，像素区共 24 字节。在本例没有额外颜色信息、像素偏移为 54 的前提下，文件总大小为 `54 + 24 = 78` 字节。这是按格式计算的示例值。

对本例的未压缩 RGB，`biHeight > 0` 表示文件先存最下面一行；`biHeight < 0` 表示先存最上面一行。每行内部仍从左往右排列。逐行读取时，应同时处理行跨度和高度符号，否则容易出现错行或上下颠倒。相关布局见 [BITMAPINFO 的说明](https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfo)。

## 解析时核对什么

-   确认 BM 标识、信息头大小、位深与压缩类型属于解析器支持的范围。
-   确认宽度为正、高度非零，并限制允许的尺寸，检查乘法和偏移计算是否溢出。
-   确认像素偏移在头部之后且位于文件范围内，再核对 `bfOffBits + pixel_bytes` 不超过实际文件长度。
-   不要把 24 位 BI\_RGB 的 BGR 顺序、大小计算或第 54 字节的例子直接套用到调色板、压缩或其他信息头版本。
