BMPファイルをバイナリエディタで見る

2022年6月5日TIPS,学習

コンテンツ

はじめに

 プログラミングをしている時ファイルの読み込みはどうやって行っているのか気になったことはないでしょうか。どのプログラミング言語も基本的なライブラリは十分で画像の読み込みがしたければ、それ用のライブラリを探して導入すればすぐに実現可能です。しかし、仕組みぐらいは知っておいた方がいいのではないかとよく思います。というか…自分は低級(高級言語の高級の対義語としての低級)なことにも興味がある質で、そもそもどうなっているのかということが結構気になってしまいます。ファイルといってもテキスト、音声、画像、動画、実行ファイル、特定のソフトウェア(エクセル)のファイル等様々です。今回は初歩の初歩のそもそもファイルってどんな構造になっているかの一例を調べたのでそのメモです。今回調べたファイルは画像ファイルのビットマップ(bmp : bitmap)ファイルです

バイナリエディタでbmpファイルをみる

バイナリエディタの見方

バイナリエディタでファイルをあまり見たことがなかったので見方のポイントをまとめておきます。

バイナリエディタとは

バイナリエディタとは、任意の形式のバイナリファイルの内容を読み込んで表示し、編集することができるソフトウェア。データを16進数(hexadecimal)の数値列として表示する方式が一般的なため、英語では “hex editor” と呼ばれる。

IT用語辞典 e-Words

e-wordsでは以上のようになっています。バイナリファイルと呼ばれるものを16進数で表示して編集するソフトです。バイナリファイルとは、いづれかの文字コードで文字にデコード(単語の使い方が正しいか不明…0,1の数列を文字コードを元に文字にする)したときに人が理解できないようなデータ(バイナリデータ)のファイルを指します。文字にしたとき人が読めるようなデータはテキストデータといい、そのファイルがテキストファイルです。テキストファイルも所詮はバイナリですが、一般的にバイナリファイルというときはテキストファイル以外のファイルを指すことが多いようです。

実際の画面

以下の画像をバイナリエディタで開いた画像をその下に記載しました。バイナリエディタは、Visual Studio Code に Hex Editor というプラグインを入れたもの使用しています。

koukaku no pandora 10
紅殻のパンドラ #10 恐怖-フィア- より

visual studio code hex editor

バイナリを見るのに覚えておきたいこと

バイト(Byte)

コンピュータで情報(数値)を扱うには、2値(binary)が便利なためコンピュータでは2進法(binary notation)が用いられています。2進法とは、0と1のみで数字を表すことです。人が普段使用しているのは、0~9を使って数字を表す10進法です。2進法の1桁のことを1bit(Binary digit や bits of informationが語源らしい)といい、コンピュータなどが処理する基本単位のbit数を表すのがByte(Bite:噛むをもじった造語の説がある)です。現在は 1Byte = 8bit が一般的です(6,7,9bitなどを処理の基本単位とする計算機もある…った?)。

バイナリエディタでは、1Byteすなわち8bit毎を16進数で表示します。16進数は0,…,9,A,…,Fの16の記号で数字を表します。1Byteは8bitなので2桁の16進数で表されます(0~255は16進数では2桁)。10進数で表示はエディタの機能についていたりするのですが、2進数や8進数の変換の簡単な方法を以下にメモしておきます。

  • 16進数 ← → 2進数
  • 4 | 2 ← → 0100 | 0010 (10進数で 66)

    16進数から2進数への変換は各桁を4bitの2進数にしてつなげます。2進数から16進数への変換は2進数を4bitに区切り、各フィールドを16進数の数値に変換してつなげます

  • 8進数 ← → 2進数
  • 1 | 0 | 2 ← → (0)01 | 000 | 010 (10進数で 66、 8bitを下の桁から3bitに区切る)

    8進数から2進数への変換は各桁を3bitの2進数にしてつなげます。2進数から8進数への変換は2進数を3bitに区切り、各フィールドを8進数の数値(0~7)に変換してつなげます

オフセット(アドレス)

コンピュータ関連の用語としてのオフセットは所定の位置までの、先頭からの距離を示す数です。以下の画像の左側(縦軸)の数値(16進数)と上側(横軸)の数値(16進数)を足した数が先頭から何バイト目かを表します。たまにこれをアドレスとしているバイナリエディタもあり、ファイルの先頭のバイトをアドレス0(16進数)としてそこから10バイト目をアドレスA(16進数)というような感じです。どちらでも問題ないですが考え方的にオフセットの方がしっくりきます。

バイナリエディタのオフセットの説明

ASCII(American Standard Code for Information Interchange)

現代英語や西ヨーロッパ言語で使われるラテン文字を中心とした文字コード

ウィキペディア ASCII

以上のようにASCIIは文字コードです。バイナリエディタでは、上記の画像右側のようにASCIIでデコードされたテキストが表示されます。

エンディアン(バイトオーダ)

2Byte以上のデータをメモリに格納するときや転送するときにはバイト毎に行い、そのバイトの順番をエンディアン(バイトオーダ)といいます。エンディアンには2種類あり、最下位のバイトから順番(メモリならアドレスが昇順)に格納または送信する方法をリトルエンディアンで、最上位のバイトから順番に格納または送信する方法をビックエンディアンです。

エンディアンの図

bmpファイルの構造

バイナリエディタはファイルを解析したいがために使うのが普通かもしれませんが、今回はファイルの構造を知ったうえでバイナリエディタで見ます。

ファイルの仕様書は公開されているものもあれば、非公開のものもあります。公開されているファイルの仕様はオープンフォーマットと呼ばれるため「オープンフォーマット」で検索するとどんなファイルの仕様が公開されているがわかるものもあります。例えば、PNGは仕様が公開されています( PNGの仕様 )。

bmpファイルはというと公開されている仕様書がないと思われるので、有志の方が公開してくれている構造を参考に見ます。bmpは、windowsが標準で対応している形式なのでwindowsのドキュメントに、bmpに関連するクラスなどが載っており、それを参考にしているようです(windows app development)。

全体像

bmpファイルの構造は順番から次のようになっています。

順番 要素 サイズ 備考
1 ヘッダ 14byte BMPファイルであることやファイルサイズなどの基本的な情報が記述されている
2 情報ヘッダ 12~124byte 画像データ扱う上での必要な情報が記述されている
いくつかの種類があってサイズがことなる
3 ビットフィールド 4byte 特定の形式のBMPファイルの場合に必要な情報が記述されている
必要がなければ存在しない
4 カラーパレット カラーインデックスによる 特定の形式のBMPファイルの場合に必要な情報が記述されている
必要がなければ存在しない
5 画像データ 画像のピクセル数による いくつかの形式がある(情報ヘッダに記述されいてる)

また、BMPファイルの整数値データはリトルエンディアンになっている。以下でヘッダ、情報ヘッダ、画像データについて簡単に説明します。

ヘッダ

ヘッダは以下で構成されています。ファイルそのものの情報が格納されています。

オフセット 要素 サイズ 備考
0x00 ファイルタイプ 2byte 1byte目に「B」、2byte目に「M」が格納されている。BMPファイルを示す。
0x02 ファイルサイズ 4byte ファイル全体のサイズ(符号なし整数)
0x06 予約領域1 2byte 将来の拡張用
0x08 予約領域2 2byte 将来の拡張用
0x0A 画像データまでのオフセット 4byte BMPファイルの先頭から画像データまでのオフセット(符号なし整数)

情報ヘッダ

情報ヘッダはいくつか種類があるようですが、以下はよく使われているinfoヘッダと呼ばれる情報ヘッダの構成です。

オフセット 要素 サイズ 備考
0x0E ヘッダのサイズ 4byte 情報ヘッダの種類に関わらず情報ヘッダの初めの4byteは情報ヘッダのサイズ(0x28)
0x12 画像の幅 4byte 画像の幅(符号つき整数)
0x16 画像の高さ 4byte 画像の高さ(符号つき整数)
0x1A プレーン数 2byte 常に1
0x1C 1ピクセルのbit数 2byte 1ピクセルの色を表すのに必要なbit数(符号なし整数)
0x1E 圧縮形式 4byte 画像データの圧縮形式
0,1,2,3,4,5で0が非圧縮(1,2,…参考ページ参照)
0x22 画像データサイズ 4byte 画像データのサイズ(符号なし整数、単位はbyte)
0x26 水平方向の解像度 4byte 水平方向の解像度(符号なし整数、ピクセル/m)
0x2a 垂直方向の解像度 4byte 垂直方向の解像度(符号なし整数、ピクセル/m)
0x2e カラーインデックス数 4byte カラーパレットの色数(符号なし整数)
0x32 重要な色数 4byte カラーパレットの色で正確に表せなければならない色数。0はすべて正確に表す

画像データ

情報ヘッダに記述されている形式で画像データが格納されている。形式は非圧縮、ランレングス符号での圧縮、JPEG、PNGがある。BMPファイルの画像データは行ごとのデータ(行はピクセルからなる)からなり、幅や高さが正の整数のときは、画像の下から上にかけての順で並んでいます。反対に幅や高さが負の整数のときは、画像の上から下にかけての順で並んでいます。

例えば、1ピクセルのbit数が24で圧縮形式が0の場合は画像データは、一番左下のピクセルの青成分の値(1byte)、一番左下のピクセルの緑成分の値(1byte)、一番左下のピクセルの赤成分の値(1byte)、一番下の左から2番目のピクセルの青成分の値、…となっている。

実際にBMPファイルをみる

BMPファイルのヘッダ、情報ヘッダ、画像データ部分をバイナリで見てます。

ヘッダ

BMPファイルのヘッダの最初はファイルタイプとなっており、以下の画像のように「BM」となっていることが確認できました。

BMP header

ファイルタイプ「BM」の次はファイルサイズが格納されています。オフセットは0x02~0x05でリトルエンディアンなので、値は0x000222F6となっており、エクスプローラのプロパティ表示のサイズと一致しています。

BMP header file size

ファイルサイズのあとは、予約領域がありそのあとに画像データまでのオフセットが4byteで格納されています。ヘッダが14byte、情報ヘッダが40byteでオフセットは54byteになります。

BMP header image data offset

情報ヘッダ

BMPファイルの情報ヘッダの最初は情報ヘッダのサイズとなっており、最初の4byteに40が格納されています。

BMP end of info header

情報ヘッダのサイズの後ろには、画像の幅と高さが格納されています。見るとエクスプロラーのプロパティ表示と一致する値がちゃんと格納されていました。

BMP info header image size

画像の幅、高さのあとはプレーン数が2byteで格納されており、その後ろに1ピクセルを何bitで表すかの値が入っています。

BMP info header pixel bit

画像データ

今回の画像は圧縮形式(オフセット 0x1E)が 0 で非圧縮となっていて、1ピクセルが24bitとなっているので、一番左下のピクセルの青、緑、赤成分の値から画像データが始まります。以下で確認できました。

BMP image data pixel bit

参考

Posted by 3流PG