LoginSignup
4
3

More than 1 year has passed since last update.

【画像処理】ヘッダ情報の確認とバイナリエディタからの画像編集(BMP編)

Last updated at Posted at 2021-07-07

ヘッダ情報の確認とバイナリエディタからの画像編集(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バイト カラーパレットの中で正確に表示すべき色を指定(先頭から指定した値までの色すべてを重要色に指定)

ビットフィールド

ビットフィールドが使用できる条件は以下の通りです。

  1. 情報ヘッダがINFOタイプ
  2. 情報ヘッダサイズが40
  3. ピクセル毎のビット数が16または32
  4. 圧縮タイプが3

ピクセル毎のビット数が16の場合

名称 サイズ
赤成分のカラーマスク 4バイト 0x00007C00
緑成分のカラーマスク 4バイト 0x000003E0
青成分のカラーマスク 4バイト 0x0000001F
この値を持つビットフィールドはRGB555と呼ばれます。

ピクセル毎のビット数が32の場合

名称 サイズ
赤成分のカラーマスク 4バイト 0x00FF0000
緑成分のカラーマスク 4バイト 0x0000FF00
青成分のカラーマスク 4バイト 0x000000FF
この値を持つビットフィールドはRGB888と呼ばれます。

これらのカラーマスクとピクセルデータとのANDを取ることで、ピクセルの色を計算することができます。

カラーパレット(RGBQUAD)

カラーパレット(RGBQUAD)が使用できる条件は以下の通りです。

  1. INFOタイプのカラーインデックス数が1以上
  2. ピクセル毎のビット数が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 サンプル画像
image.png

上記の画像をバイナリエディタを使って見てみると、以下のようになります。

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の整数倍の値にします。

1.2サンプル画像
  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画像の構造を知ることができたと思います。

それでは引き続きよろしくお願いいたします。

目次は以下の記事からご覧になれます。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3