ヘッダ情報の確認とバイナリエディタからの画像編集(BMP編)
前回の記事→「ヘッダ情報の確認とバイナリエディタからの画像編集(PNG編)」
今回はbmp画像の中身にはどんな情報が含まれているのかを理解するためにバイナリエディタを使用してbmpファイル形式の画像内部を見ていきます。
ファイル形式ごとのフォーマット
そもそも画像ファイルには、画像ビューアで画面に表示されているデータ以外にも、画像の幅・高さ、画像そのもの以外のデータサイズ、圧縮方式など様々な情報が含まれています。それらのフォーマットはファイル形式によって異なり、今回はbmpフォーマットの内容を解説した後にバイナリエディタを使って具体的に中身を見ていきます。
bmpのファイル構造
bmpの全体的なファイル構造は次のようになっています。
名称 | 内容 |
---|---|
ファイルヘッダ(BITMAPFILEHEADER) | 一番最初に現れるヘッダで、ファイルサイズやbmpファイルであることを示す値など、bmpファイルの基本的な情報が格納されています。 |
情報ヘッダ(BITMAPINFOHEADER) | ファイルヘッダに続いて現れるヘッダで、画像データの情報が格納されています。現状4種類存在しますが、ここではもっとも一般的で広く使われているinfoヘッダと呼ばれる情報ヘッダについて解説します。 |
ビットフィールド | ビットフィールド形式でピクセルデータが保存されている場合、このヘッダが必要です。ピクセルデータのどのビットが何色にあたるかという情報を得るために各色成分のカラーマスクの値が格納されています。 |
カラーパレット(RGBQUAD) | 各ピクセルの値と画像内で使用される色の関係を定義するためのRGB情報が格納されています。 |
イメージデータ | 画像内のピクセルを表すデータで、情報ヘッダによって3つの形式が存在します。カラーパレット内の色を指し示すもの、ビットフィールド形式で計算して算出するもの、青緑赤成分の値をそれぞれ保持するものの3つに分類されます。 |
ヘッダの格納順は、基本的には上記表と同じ順番に並んでいます。
続いて、各ヘッダの構造を詳しく見ていきます。
ファイルヘッダ
名称 | サイズ | 内容 |
---|---|---|
ファイルタイプ | 2バイト | BMPファイルであることを示すもので、必ず「BM」(0x42 0x4d)という2バイト |
ファイルサイズ | 4バイト | BMPファイル全体のバイト単位サイズ |
予約領域1 | 2バイト | 常に0 |
予約領域2 | 2バイト | 常に0 |
イメージデータオフセット | 4バイト | ファイルの最初からイメージデータまでのバイト単位オフセット |
情報ヘッダ(INFOタイプ)
名称 | サイズ | 内容 |
---|---|---|
ヘッダサイズ | 4バイト | 情報ヘッダのバイト単位でのサイズ(INFOタイプでは常に40) |
幅 | 4バイト | イメージデータの幅 |
高さ | 4バイト | イメージデータの高さ |
プレーン数(チャンネル数) | 2バイト | 実際の色深度をプレーン数を使用して計算する場合の値。しかし、現在は使われておらず、常に1 |
ピクセル毎のビット数 | 2バイト | 色深度(1pixelを表現するのに必要なビット数) |
圧縮タイプ | 4バイト | イメージデータの圧縮形式(6種類あるが、基本的には非圧縮の0または、ビットフィールド形式の非圧縮の3であることが多い) |
イメージデータサイズ | 4バイト | イメージデータのバイト単位でのサイズ(圧縮タイプが0または3である場合、この値は0でもよい) |
水平解像度 | 4バイト | イメージデータの横方向のピクセル数 |
垂直解像度 | 4バイト | イメージデータの縦方向のピクセル数 |
カラーインデックス数 | 4バイト | カラーパレットの色深度を指定 |
重要インデックス | 4バイト | カラーパレットの中で正確に表示すべき色を指定(先頭から指定した値までの色すべてを重要色に指定) |
ビットフィールド
ビットフィールドが使用できる条件は以下の通りです。
- 情報ヘッダがINFOタイプ
- 情報ヘッダサイズが40
- ピクセル毎のビット数が16または32
- 圧縮タイプが3
ピクセル毎のビット数が16の場合
名称 | サイズ | 値 |
---|---|---|
赤成分のカラーマスク | 4バイト | 0x00007C00 |
緑成分のカラーマスク | 4バイト | 0x000003E0 |
青成分のカラーマスク | 4バイト | 0x0000001F |
この値を持つビットフィールドはRGB555と呼ばれます。 |
ピクセル毎のビット数が32の場合
名称 | サイズ | 値 |
---|---|---|
赤成分のカラーマスク | 4バイト | 0x00FF0000 |
緑成分のカラーマスク | 4バイト | 0x0000FF00 |
青成分のカラーマスク | 4バイト | 0x000000FF |
この値を持つビットフィールドはRGB888と呼ばれます。 |
これらのカラーマスクとピクセルデータとのANDを取ることで、ピクセルの色を計算することができます。
カラーパレット(RGBQUAD)
カラーパレット(RGBQUAD)が使用できる条件は以下の通りです。
- INFOタイプのカラーインデックス数が1以上
- ピクセル毎のビット数が1,4,8のいずれかの値
名称 | サイズ | 値 |
---|---|---|
青成分 | 1バイト | 0~255 |
緑成分 | 1バイト | 0~255 |
赤成分 | 1バイト | 0~255 |
予約領域 | 1バイト | 常に0 |
色数はカラーインデックス数と同じですが、カラーインデックス数が0の場合はピクセル毎のビット数を2乗した値になります。
イメージデータ
非圧縮のイメージデータには、ピクセル毎のビット数(色深度)によって以下の3種類の形式があります。
1. パレットタイプ
ピクセル毎のビット数が1,4,8のいずれかの場合、イメージデータはカラーパレット内の色を指し示すインデックス値となります。
2. ビットフィールドタイプ
ピクセル毎のビット数が16または32の場合、イメージデータはビットフィールドの各カラーマスク値で算出された値となります。
3. カラータイプ
ピクセル毎のビット数が24の場合、カラーパレットの各色成分の値と同じになります。(カラーパレットの役割がここに移ったと考えて良い)
ここまででひと通りbmpの構造を説明しました。次は実際にbmp画像の中を確認し、上記説明通りの構造になっているかを確認します。
バイナリエディタからの画像編集
ここではバイナリエディタを使って、実際にbmp画像の中身を確認していきます。
今回は、ペイントを使用して16×16の赤で塗りつぶした画像を使用します。
1.1 サンプル画像 |
---|
上記の画像をバイナリエディタを使って見てみると、以下のようになります。
Offset: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000: 42 4D 36 03 00 00 00 00 00 00 36 00 00 00 28 00 BM6.......6...(.
00000010: 00 00 10 00 00 00 10 00 00 00 01 00 18 00 00 00 ................
00000020: 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 FF 00 00 FF 00 00 FF 00 ................
00000040: 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 ................
00000050: FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF ................
00000060: 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 ................
00000070: 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 ................
00000080: FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF ................
00000090: 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 ................
000000a0: 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 ................
000000b0: FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF ................
000000c0: 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 ................
000000d0: 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 ................
000000e0: FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF ................
000000f0: 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 ................
00000100: 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 ................
00000110: FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF ................
00000120: 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 ................
00000130: 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 ................
00000140: FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF ................
00000150: 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 ................
00000160: 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 ................
00000170: FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF ................
00000180: 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 ................
00000190: 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 ................
000001a0: FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF ................
000001b0: 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 ................
000001c0: 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 ................
000001d0: FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF ................
000001e0: 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 ................
000001f0: 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 ................
00000200: FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF ................
00000210: 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 ................
00000220: 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 ................
00000230: FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF ................
00000240: 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 ................
00000250: 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 ................
00000260: FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF ................
00000270: 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 ................
00000280: 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 ................
00000290: FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF ................
000002a0: 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 ................
000002b0: 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 ................
000002c0: FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF ................
000002d0: 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 ................
000002e0: 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 ................
000002f0: FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF ................
00000300: 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 ................
00000310: 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 ................
00000320: FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF 00 00 FF ................
00000330: 00 00 FF 00 00 FF ......
bmp構造の確認
ファイルヘッダ
offset | データ | 名称 | 内容 |
---|---|---|---|
00000000~00000001 | 42 4D | ファイルタイプ | BM |
00000002~00000005 | 36 03 00 00 | ファイルサイズ | 822(byte) |
00000006~00000007 | 00 00 | 予約領域1 | 0 |
00000008~00000009 | 00 00 | 予約領域2 | 0 |
0000000A~0000000D | 36 00 00 00 | イメージデータオフセット | 54 |
情報ヘッダ(INFOタイプ)
offset | データ | 名称 | 内容 |
---|---|---|---|
0000000E~00000011 | 28 00 00 00 | ヘッダサイズ | 40 |
00000012~00000015 | 10 00 00 00 | 幅 | 16 |
00000016~00000019 | 10 00 00 00 | 高さ | 16 |
0000001A~0000001B | 01 00 | プレーン数(チャンネル数) | 1 |
0000001C~0000001D | 18 00 | ピクセル毎のビット数 | 24 |
0000001E~00000021 | 00 00 00 00 | 圧縮タイプ | 0 |
00000022~00000025 | 00 03 00 00 | イメージデータサイズ | 768(byte) |
00000026~00000029 | 00 00 00 00 | 水平解像度 | 0 |
0000002A~0000002d | 00 00 00 00 | 垂直解像度 | 0 |
0000002E~00000031 | 00 00 00 00 | カラーインデックス数 | 0 |
00000032~00000035 | 00 00 00 00 | 重要インデックス | 0 |
イメージデータ
bmpのイメージデータは左下から右上に向かって格納されているため、今回の例ではわかりずらいですが、表示された画像の左下のピクセルから右上に向かって順番に並んでいます。
offset | データ | 名称 | 内容 |
---|---|---|---|
00000036 | 00 | 青成分 | 0 |
00000037 | 00 | 緑成分 | 0 |
00000038 | FF | 赤成分 | 255 |
・ | ・ | ・ | ・ |
・ | ・ | ・ | ・ |
・ | ・ | ・ | ・ |
00000333 | 00 | 青成分 | 0 |
00000334 | 00 | 緑成分 | 0 |
00000335 | FF | 赤成分 | 255 |
ピクセル毎のビット数が24なので、各色成分の値が直接イメージデータに格納されています。
bmp構造の編集
今回のbmp画像ではすべてのピクセルが同じ色のため、カラーパレットを使用することでイメージデータ部分を大きく圧縮できそうなので、さらにカラーパレットに指定する色を増やして、柄のある画像をバイナリエディタから作成してみます。
具体的には情報ヘッダのピクセル毎のビット数に2を指定し、指し示すパレットの色を設定します。(RGBQUADタイプのため予約領域に0を付加)
ここで、1点気を付ける必要があります。イメージデータにおいて画像の横1行分のデータの中では必ず4バイトの整数倍のサイズでなければいけません。
つまり、行データのバイト合計が4で割り切れない場合、0をパディングして一番近い4の整数倍の値にします。
Offset: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000: 42 4D 7E 00 00 00 00 00-00 00 3E 00 00 00 28 00 BM~.......>...(.
00000010: 00 00 10 00 00 00 10 00-00 00 01 00 01 00 00 00 ................
00000020: 00 00 40 00 00 00 10 00-00 00 10 00 00 00 02 00 ..@.............
00000030: 00 00 00 00 00 00 00 00-00 00 37 50 03 00 55 55 ..........%>..UU
00000040: 00 00 AA AA 00 00 55 55-00 00 AA AA 00 00 55 55 ......UU......UU
00000050: 00 00 AA AA 00 00 55 55-00 00 AA AA 00 00 55 55 ......UU......UU
00000060: 00 00 AA AA 00 00 55 55-00 00 AA AA 00 00 55 55 ......UU......UU
00000070: 00 00 AA AA 00 00 55 55-00 00 AA AA 00 00 ......UU......
1.2 サンプル画像 |
---|
カラーパレットに「00 00 00 00」(黒)と「37 50 03 00」(緑)を格納し、各イメージデータからインデックス0とインデックス1のカラーパレットを交互に参照するように変更しました。
各イメージデータはインデックスを指定すればよいので、3バイト(24ビット)から1ビットに減らすことができ、画像サイズは822byte
から126byte
まで縮小させることができました。また、それに伴ってファイルサイズやイメージデータオフセットなどのメタデータも変更しました。
イメージデータの指定は2進数で0または1を指定して、それを1行ごとに16進数で表します。さらに、1行が4バイトに満たない場合は0でパディングする必要があるので、今回は0と1を交互に格納した「55 55」と「AA AA」に0を付加して「55 55 00 00」と「AA AA 00 00」を順番に並べています。
結果として、「1.2 サンプル画像」をGIMPや他の画像ビューアで正常に表示することができました。
ちなみに、上記画像は単色であるためカラーパレットの色を変えることで画像全体の色を変えることができます。また、単色や色数が少ない場合はカラーパレットを指定したほうが圧倒的に画像サイズを小さくすることができることもわかりました。
さいごに
今回は、「ヘッダ情報の確認とバイナリエディタからの画像編集(BMP編)」について解説しました。bmp画像の構造を知ることができたと思います。
それでは引き続きよろしくお願いいたします。
目次は以下の記事からご覧になれます。