Bitmap(*.bmp)ファイルフォーマット徹底解説！～基本から内部構造まで～

## はじめに

Bitmapファイル(*.bmp)は、画像データの先頭に画像の幅や高さ、ビット数などの情報を付加し、バイナリデータとしてファイルに保存されたファイルなので、画像データをプログラムから扱うのは、非常に便利なフォーマットです。

また、Bitmapファイルは、Jpegファイルのように画像ファイルに保存→読込をすることで、保存前の画像データとの誤差も生じないため、画像処理をする画像データを保存するには、Bitmapファイルフォーマットが良く用いられます。

最近では、C++ではOpenCV、C#では.NETのBitmapクラスなどがあるので、Bitmapファイルの中身を意識することなく、Bitmapファイルに保存／読込ができます。

工業用のカメラでは、１画素あたり10bit、12bitのグレースケールに対応したカメラがかなり普及してきていますが、OpenCVや.NETのライブラリでは、10bitや12bitの画像に対応していないことの方が多いのですが、ビットフィールと呼ばれる少々特殊な設定をすることで、Bitmapファイルでも対応することが可能となります。

そのため、Bitmapファイルの中身の構造を理解しておくことが重要となります。



## Bitmapファイルの内部構造

Bitmapファイルは、決まった位置に特定の情報が配置されたメモリを、バイナリファイルとして保存することで、Bitmapファイル(*.bmp)となります。

この配置位置と、それぞれの意味について説明します。



### Bitmapファイル全体の構造

まず、Bitmapファイルがどのようなブロックで構成されているか、全体像を把握しましょう。

|         **BITMAPFILEHEADER**         | **ビットマップファイルヘッダー<br />ファイル全体の情報を格納** | **14バイト**    |
| :----------------------------------: | ------------------------------------------------------------ | --------------- |
|         **BITMAPINFOHEADER**         | **ビットマップインフォヘッダー<br />幅、高さ、ビット数などの画像データに関する情報を格納** | **40バイト**    |
| **カラーパレット（無い場合もあり）** | **画像データをどの色でモニタ上に表示するか？の設定**         | **4 x index数** |
|            **画像データ**            | **画像データが、通常、画像の左下を原点として格納されている。<br />24bitカラー画像の場合は、<font color="Blue">B</font>, <font color="Green">G</font>, <font color="Red">R</font>, <font color="Blue">B</font>, <font color="Green">G</font>, <font color="Red">R</font>・・の順番** |                 |



それでは、各ブロックの詳細を見ていきましょう。



### 1. ファイルヘッダー (BITMAPFILEHEADER): 14バイト固定
* ファイルの先頭に必ず存在し、ファイルがBMPであることや、ピクセルデータまでのオフセットなどを示します。

    | オフセット(byte) | サイズ(byte) | フィールド名  | 説明                                                         |
    | :--------------- | :----------- | :------------ | :----------------------------------------------------------- |
    | 0                | 2            | `bfType`      | ファイルタイプ。必ず "BM" (0x4D42)                           |
    | 2                | 4            | `bfSize`      | ファイル全体のサイズ (バイト)                                |
    | 6                | 2            | `bfReserved1` | 予約領域 (通常 0)                                            |
    | 8                | 2            | `bfReserved2` | 予約領域 (通常 0)                                            |
    | 10               | 4            | `bfOffBits`   | ファイル先頭からピクセルデータの開始位置までのオフセット (バイト) |



### 2. 情報ヘッダー (BITMAPINFOHEADER): 40バイト固定

* 画像の詳細情報（幅、高さ、色深度、圧縮形式など）を格納します。

    | オフセット(byte) | サイズ(byte) | フィールド名      | 説明                                                         |
    | :--------------- | :----------- | :---------------- | :----------------------------------------------------------- |
    | 14               | 4            | `biSize`          | この情報ヘッダーのサイズ (バイト)。通常 40 (0x28)。          |
    | 18               | 4            | `biWidth`         | 画像の幅 (ピクセル)                                          |
    | 22               | 4            | `biHeight`        | 画像の高さ (ピクセル)。<br />**正の値**はボトムアップ形式 (左下原点)<br />**負の値**はトップダウン形式 (左上原点)<br />使用するプログラムによっては、負の値に対応していない場合もあります。 |
    | 26               | 2            | `biPlanes`        | プレーン数 (常に 1)                                          |
    | 28               | 2            | `biBitCount`      | 1ピクセルあたりのビット数 (色深度)。1, 4, 8, 16, 24, 32 など。 |
    | 30               | 4            | `biCompression`   | 圧縮形式 (下記参照)                                          |
    | 34               | 4            | `biSizeImage`     | ピクセルデータ部分のサイズ (バイト)。<br />無圧縮(BI_RGB)の場合、0でも可 (パディング込みで計算可能)。 |
    | 38               | 4            | `biXPelsPerMeter` | 水平解像度 (ピクセル/メートル)。通常 0。                     |
    | 42               | 4            | `biYPelsPerMeter` | 垂直解像度 (ピクセル/メートル)。通常 0。                     |
    | 46               | 4            | `biClrUsed`       | カラーパレット内の色数。<br />0の場合、`biBitCount`に基づいて最大色数が使われる (例: 8bitなら256色)。 |
    | 50               | 4            | `biClrImportant`  | 重要な色の数。0の場合、全ての色が重要。                      |



### 3. カラーパレット (Color Palette) または ビットマスク: オプション、可変長

   * `biBitCount` が 1, 4, 8 の場合に存在します (インデックスカラー)。
        * `biClrUsed` で指定された数、または `biBitCount` から計算される最大色数分の `RGBQUAD` 構造体の配列です。
        * `RGBQUAD` 構造体 (4バイト): 青(B), 緑(G), 赤(R), 予約(通常0) の順で各1バイト。

* **カラーパレット:** BMPファイル、特に色数が少ない画像（1bit, 4bit, 8bit）を効率的に格納するために「カラーパレット」という仕組みを利用します。これは「インデックスカラー」方式とも呼ばれます。

    **カラーパレットが存在する条件:**

    * 情報ヘッダーの `biBitCount` (1ピクセルあたりのビット数) が **1, 4, 8** のいずれかであり、かつ `biCompression` が `BI_RGB` または `BI_RLE8`, `BI_RLE4` の場合に、カラーパレットが**必須**となります。
    * `biBitCount` が 16, 24, 32 の場合は、基本的にピクセルデータに直接色情報が含まれるため、カラーパレットは**通常使用しません**。
    

    **カラーパレットの構造:**

    * カラーパレットは、**情報ヘッダー (`BITMAPINFOHEADER` など) の直後**、かつ**ピクセルデータの前**に配置されます。
    * パレットは、**`RGBQUAD`** という構造体の配列で構成されます。`RGBQUAD` は1つの色を定義するための4バイトのデータです。

        ```c
        typedef struct tagRGBQUAD {
          BYTE rgbBlue;      // 青成分 (0-255)
          BYTE rgbGreen;     // 緑成分 (0-255)
          BYTE rgbRed;       // 赤成分 (0-255)
          BYTE rgbReserved;  // 予約領域 (通常は 0)
        } RGBQUAD;
        ```

        * `rgbBlue`, `rgbGreen`, `rgbRed` で色の三原色を各8ビット(0-255)で指定します。
        * `rgbReserved` は通常0ですが、ファイル形式やアプリケーションによってはアルファ値（不透明度）として解釈される可能性もゼロではありません（ただしBMPの標準的な仕様ではありません）。

    **パレットのサイズ (色数):**

    * パレットに格納される `RGBQUAD` 構造体の数（＝パレットの色数）は、情報ヘッダーの `biClrUsed` フィールドによって決まります。
        * **`biClrUsed` が 0 より大きい値の場合:** その値がパレットの色数となります。例えば `biClrUsed` が 100 なら、100個の `RGBQUAD` (計 400バイト) がパレットとして存在します。ただし、`biBitCount` で表現可能な最大色数を超えることはできません (例: 4bit画像なら `biClrUsed` は16以下)。
        * **`biClrUsed` が 0 の場合:** `biBitCount` が示す最大の色数がパレットサイズとなります。
            * `biBitCount` = 1 : 2色 (2^1) のパレット (通常、白と黒)
            * `biBitCount` = 4 : 16色 (2^4) のパレット
            * `biBitCount` = 8 : 256色 (2^8) のパレット
            この場合、パレットの合計バイト数は `(2^biBitCount) * sizeof(RGBQUAD)` となります。

    **ピクセルデータとの関係:**

    * `biBitCount` が 1, 4, 8 の場合、ピクセルデータには実際のRGB値ではなく、**カラーパレットのインデックス（番号）**が格納されています。
    * 例えば、8bit画像 (`biBitCount`=8) の場合、ピクセルデータは1バイト単位で読み込まれ、そのバイト値 (0～255) がそのままカラーパレットのインデックスとなります。値が `10` であれば、カラーパレットの11番目 (0から数えるため) の `RGBQUAD` で定義された色が、そのピクセルの色となります。
    * 4bit画像 (`biBitCount`=4) の場合、1バイトに2ピクセル分の情報が含まれます。通常、上位4ビットが1ピクセル目のインデックス (0～15)、下位4ビットが2ピクセル目のインデックス (0～15) となります。
    * 1bit画像 (`biBitCount`=1) の場合、1バイトに8ピクセル分の情報が含まれます。各ビットがインデックス (0または1) に対応します。

* **ビットマスク (`BI_BITFIELDS` 指定時):**

    * 情報ヘッダーの `biCompression` フィールドに **`BI_BITFIELDS` (値: 3)** が指定されている場合、これは通常 16bpp または 32bpp のダイレクトカラーモードで使用されます。
    * このモードでは、ピクセルデータ内のビットがどの色成分（赤、緑、青、場合によってはアルファ）に対応するかを定義するための**ビットマスク**が必要となります。
    * **重要:** `BI_BITFIELDS` が指定された場合、**カラーパレットは存在しません**。カラーパレットが配置されるべき場所（情報ヘッダーの直後）には、代わりに **RGB のビットマスク**が配置されます。
    * 具体的には、情報ヘッダーの直後に、以下の**3つの `DWORD` (符号なし4バイト整数、計12バイト)** がこの順序で格納されます。
        1.  **Red Mask:** ピクセルデータ内の赤成分に対応するビットを示すマスク (例: 16bit 5-6-5 なら `0xF800`)。
        2.  **Green Mask:** ピクセルデータ内の緑成分に対応するビットを示すマスク (例: 16bit 5-6-5 なら `0x07E0`)。
        3.  **Blue Mask:** ピクセルデータ内の青成分に対応するビットを示すマスク (例: 16bit 5-6-5 なら `0x001F`)。
    * これらのマスクがあるため、ソフトウェアはピクセルデータ（16bit または 32bit の値）から正確な RGB 値を抽出できます。



### 4. ピクセルデータ (Pixel Data):
* 実際の画像データが格納されます。
    この開始位置はファイルヘッダーの `bfOffBits` で示されます。
* **格納順序:**
    * `biHeight` が**正**の場合: **ボトムアップ形式**。画像の**一番下の行**から**一番上の行**へ、各行は左から右へ格納されます。<font color="Red">基本的にこちらを使う</font>
    ![ImageData.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3996436/6712247a-3635-40ec-a9b1-cf7d96d7e6b5.png)

    * `biHeight` が**負**の場合: **トップダウン形式**。画像の**一番上の行**から**一番下の行**へ、各行は左から右へ格納されます。（比較的新しい形式で、`biCompression` が `BI_RGB` または `BI_BITFIELDS` の場合にのみ有効）

:::note warn
負の値に対応していないプログラムもあるので注意
:::

* **パディング (Padding):**
    * 各行のデータサイズ（バイト数）は、必ず**4バイトの倍数**になるように、末尾に0x00などのパディングデータが付加されます。これはメモリアクセス効率のためです。
    * 計算式: `stride = floor((biBitCount * biWidth + 31) / 32) * 4`
    * ピクセルデータ全体のサイズ (`biSizeImage`) は、無圧縮の場合 `stride * abs(biHeight)` で計算できます。
    **(例) 8bitモノクロ 802 x 600画素の画像の場合**
     メモリ上は 804 x 600画素分用意し、行の最後（右側）の２画素分の値は０にします。
    
* **色深度ごとのデータ形式:**
    * **1-bit:** 1ピクセルを1ビットで表現。8ピクセルで1バイト。値はカラーパレットのインデックス0または1に対応。バイト内のビット順は通常、最上位ビット(MSB)が左端のピクセルに対応。
    * **4-bit:** 1ピクセルを4ビットで表現。2ピクセルで1バイト。通常、1バイトの上位4ビットが左側のピクセル、下位4ビットが右側のピクセルのインデックス(0-15)に対応。
    * **8-bit:** 1ピクセルを8ビット(1バイト)で表現。値はカラーパレットのインデックス(0-255)。
    * **16-bit:** 1ピクセルを16ビット(2バイト)で表現。
        * `biCompression` = `BI_RGB`: 通常 RGB 5-5-5 形式 (最上位ビットは予約)。赤・緑・青 各5ビット。
        * `biCompression` = `BI_BITFIELDS`: ヘッダー直後のビットマスクに従って RGB 値を格納。一般的なのは RGB 5-6-5 形式（赤5, 緑6, 青5ビット）。
    * **24-bit:** 1ピクセルを24ビット(3バイト)で表現。**<font color="Blue">B</font>, <font color="Green">G</font>, <font color="Red">R</font>** の順で各8ビット。カラーパレットは使用しない (フルカラー)。
    * **32-bit:** 1ピクセルを32ビット(4バイト)で表現。
        * `biCompression` = `BI_RGB`: 通常 **<font color="Blue">B</font>, <font color="Green">G</font>, <font color="Red">R</font>, 予約(未使用, A)** の順で各8ビット。予約バイトはC言語では0を指定する場合が多かったか、.NETではアルファ値（透過率）として使われ、不透明の場合255を指定する。
        * `biCompression` = `BI_BITFIELDS`: ヘッダー直後のビットマスクに従って RGB(A) 値を格納。

* **圧縮形式 (`biCompression` フィールドの値):**
    * `0` (`BI_RGB`): 無圧縮 (最も一般的)
    * `1` (`BI_RLE8`): 8-bit Run-Length Encoding (8bppボトムアップ画像用)
    * `2` (`BI_RLE4`): 4-bit Run-Length Encoding (4bppボトムアップ画像用)
    * `3` (`BI_BITFIELDS`): ビットフィールド指定 (16bpp, 32bpp画像用)。
      カラーマスクが情報ヘッダ直後 (カラーパレットの代わり) に配置される。トップダウン形式も可能。
    * `4` (`BI_JPEG`): JPEG圧縮されたデータを含む (埋め込みJPEG、稀)
    * `5` (`BI_PNG`): PNG圧縮されたデータを含む (埋め込みPNG、稀)

## モノクロ10～16bit画像の場合
**ビットフィールド**の設定を用います。

`BITMAPFILEHEADER`の`bfOffBits`を66 (= 14 + 40 + 4 x 3)
`BITMAPINFOHEADER`の`biBitCount`を16
`BITMAPINFOHEADER`の`biCompression`を`BI_BITFIELDS`
に設定します。
さらに、カラーパレットとして`RGBQUAD`を3つ分使用します。
ここでは、カラーパレットというよりも、1画素のデータのビット数（16bit）に対して、どのビットが有効なのか？を示すビットマスクとして用います。

`RGBQUAD`の３つのうち、
bmiColors[0]がR（赤）
bmiColors[1]がG（緑）
bmiColors[2]がB（青）
の画像表示色のビットマスクとなります。

例えば、モノクロ10bitの場合、16bit中下位10bitが有効データとなります。
ビットで表現すると **0000001111111111** となります。
16進数で32bitの値として表現すると **0x0003FF** となります。

これを`RGBQUAD`で表すと、`RGBQUAD`全体32bit中の上位ビットから順に

`rgbReserved`, `rgbRed`, `rgbGreen`, `rgbBlue`

の順番で並んでいるので、最終的にカラーパレットは

```cpp
// Rのビットマスク
bmiColors[0].rgbReserved = 0x00
bmiColors[0].rgbRed = 0x00
bmiColors[0].rgbGreen = 0x03
bmiColors[0].rgbBlue = 0xFF
// Gのビットマスク
bmiColors[1].rgbReserved = 0x00
bmiColors[1].rgbRed = 0x00
bmiColors[1].rgbGreen = 0x03
bmiColors[1].rgbBlue = 0xFF
// Bのビットマスク
bmiColors[2].rgbReserved = 0x00
bmiColors[2].rgbRed = 0x00
bmiColors[2].rgbGreen = 0x03
bmiColors[2].rgbBlue = 0xFF
```
となります。

:::note warn
ビットフィールドの設定は、あまり一般的に用いられてません。
そのためビットフィールドに対応していないプログラム、ライブラリが多くありますが、Windowsのフォトアプリでは、ビットフィールドの値が反映され、画像が表示されます。
:::
:::note warn
モノクロの10～16bitで保存したBitmap画像ファイルはWindowsのエクスプローラでは32bitと表示されます。
:::
![2025-04-12_18h24_42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3996436/872757d3-bd3d-4c04-a90e-4b3bada53c1e.png)


## おまけ。便利ツールの紹介
Bitmapファイルは、画像データにヘッダ情報が付いたただのバイナリファイルなので、Bitmapファイルの構造を確認するには、バイナリエディタがあると便利です。

私が良くお世話になっているのは、 TSXBIN というソフト
これ、かなりおススメです。
https://www.vector.co.jp/soft/dl/winnt/util/se513258.html

下記の画像は、モノクロ10bitのBitmapファイルを、TSXBINで表示した時の画面です。
![2025-04-12_18h17_41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3996436/84298fca-4007-42f2-ac59-2cae555107c2.png)