16ビット及び32ビットのBMPファイルで用いられるビットフィールドの解説。
本文書では、ビットフィールドを用いる16ビットBMP及び32ビットBMPを総称してビットフィールドBMPと呼ぶ。
バイナリ構造のページのビットフィールドセクションでも述べた通り、ビットフィールドは以下の構成要素を持つ。
要素 | バイト数 |
---|---|
赤成分のカラーマスク | 4 |
緑成分のカラーマスク | 4 |
青成分のカラーマスク | 4 |
また、16ビットBMPと32ビットBMPそれぞれの既定値は以下の通りである。
要素 | 値 |
---|---|
赤成分のカラーマスク | 0x00007C00 |
緑成分のカラーマスク | 0x000003E0 |
青成分のカラーマスク | 0x0000001F |
要素 | 値 |
---|---|
赤成分のカラーマスク | 0x00FF0000 |
緑成分のカラーマスク | 0x0000FF00 |
青成分のカラーマスク | 0x000000FF |
これらの値の意味、及び処理の指針について以降のセクションで述べる。
ビットフィールドの構成要素である各色成分のカラーマスクについて、その意味と制約を以下に述べる。
各色成分のカラーマスクの値は、ピクセルデータのどのビットが何色にあたるかを示すものである。
例として、16ビットBMPにおける既定値であるRGB555の各構成要素値を16進数表記及び2進数表記した表を以下に示す。
なお、16ビットBMPでは各カラーマスク値の下位16ビットのみを用い、上位16ビットは無視する。
要素 | 16進数表記 | 2進数表記 |
---|---|---|
赤成分のカラーマスク | 0x00007C00 | 00000000 00000000 01111100 00000000 |
緑成分のカラーマスク | 0x000003E0 | 00000000 00000000 00000011 11100000 |
青成分のカラーマスク | 0x0000001F | 00000000 00000000 00000000 00011111 |
16ビットのピクセルデータをこれらのカラーマスク値を用いて解釈すると、以下のようになる。
各色成分値が5ビット(32階調)で表現されているが、これを通常の色表現で用いる8ビット(256階調)の値に変換する方法は、後述のビット数変換セクションで述べる。
もう1つの例として、32ビットBMPにおける既定値であるRGB888の各構成要素値を16進数表記及び2進数表記した表を以下に示す。
更に、このBMPの情報ヘッダがV4タイプで、α成分のカラーマスクも指定されているものとする。
要素 | 16進数表記 | 2進数表記 |
---|---|---|
赤成分のカラーマスク | 0x00FF0000 | 00000000 11111111 00000000 00000000 |
緑成分のカラーマスク | 0x0000FF00 | 00000000 00000000 11111111 00000000 |
青成分のカラーマスク | 0x000000FF | 00000000 00000000 00000000 11111111 |
α成分のカラーマスク | 0xFF000000 | 11111111 00000000 00000000 00000000 |
32ビットのピクセルデータをこれらのカラーマスク値を用いて解釈すると、以下のようになる。
各色成分のカラーマスクはどのような値でもよいわけではなく、以下に示す2つの制約がある。
1
のビット)は連続していなければならない。00000000 00000000 00001111 11100000
のカラーマスク値は 1
が連続しているため問題ないが、2進数表記で 00000000 00000000 00001110 11100000
のカラーマスク値は途中に 0
が入っているため不正な値である。00000000 00000000 11111110 00000000
で、緑成分のカラーマスク値が 00000000 00000000 00000011 11110000
の場合、22ビット目がどちらも 1
のため不正な値である。逆に、これらの制約を満たしてさえいればどのような値でもとることができ、有効ビット無し(値 0x00000000
)でも構わない。
カラーマスク値に有効ビットの無い色成分値は 0
として扱われる。ただし、α成分の場合は完全不透明として扱われる。
また、BMPの仕様とは関係ない制約であるが、Windows 95、Windows 98、Windows MeにおいてビットフィールドBMPを直にデバイスコンテキスト上に表示する場合、決まったビットフィールド以外は使用できない。
16ビットBMPの場合は前述のRGB555及び次に述べるRGB565、32ビットBMPの場合は前述のRGB888のみが使用できる。
RGB565は、以下の値を持つビットフィールドのことである。
要素 | 値 |
---|---|
赤成分のカラーマスク | 0x0000F800 |
緑成分のカラーマスク | 0x000007E0 |
青成分のカラーマスク | 0x0000001F |
各カラーマスク値が制約条件を満たしているかどうか調べる方法を以下に示す。
1
のビット)が連続しているか。0
で初期化する。0
ならばこの色成分は存在せず、次以降の処理を行う必要はない。1
ならば6番目の処理へ飛ぶ。1
を加え、 Mask を1ビット右シフトする。1
を加え、 Mask を1ビット右シフトする。0
ならば9番目の処理へ飛ぶ。0
ならば問題なし、 0
以外ならば不正なカラーマスク値である。0
ならば問題なく、 0
以外ならば不正である。&
演算子や And
演算子で表される。上述したチェック処理のC++言語でのコーディング例を以下に示す。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | - | | | | | | | | | | | | | | | | ! - - ! - | | | - - ! | - ! - | | ! | - ! - | | ! | - ! | - ! - | ! ! | - ! | ! | | ! |
|
なお、右シフト演算が行えない言語では、値を2で割ることで1ビット右シフトと同じ結果が得られる。
また、ある値の最下位ビットが 0
か 1
かを判定する方法として、値が偶数か奇数かによって見分ける方法もある。
偶数ならば最下位ビットは 0
、奇数ならば最下位ビットは 1
である。
カラーマスクの正当性を調べた際に取得したカラーマスク値のビット位置を基に、ピクセルデータから色成分値を取得する方法を以下に示す。
なお、ピクセルデータを代入した変数を Pixel 、カラーマスク値を代入した変数を Mask 、そのビット位置を Pos とする。
上述した取得処理のC++言語でのコーディング例を以下に示す。
なお、上述のカラーマスクの正当性セクションのコーディング例で記述した関数 check_colormasks
を用いている。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | - | | | | | | | | | | | | | | | | | | ! - - ! | - ! | - ! | - - ! - - ! | | - ! ! ! | - ! | | ! |
|
取得した各色成分値を8ビット(256階調)の値に変換する方法は、次のビット数変換セクションで述べる。
例えば、ある5ビット(32階調)の符号無し整数値 Src を8ビット(256階調)の符号無し整数値 Dest に相対変換することを考える。
相対変換であるので、例えば Src が最大値の 31
であった場合、変換した Dest は最大値の 255
になる。
単純に考えれば、次の式によって Dest を求めることができる。
なお、この式中の Round(N)
は N の小数点以下四捨五入を表す。
Dest=Round(Src×255÷31)
より一般的に言えば、ビット数が BitSrc の符号無し整数値 Src をビット数が BitDest の符号無し整数値 Dest に相対変換するには、 Src に BitDest ビットで表せる値の最大値を掛けた後、その値を BitSrc ビットで表せる値の最大値で割ればよい。
あるビット数 BitCount で表される数値の最大値は、 1
を BitCount ビット左シフトした後、その値から 1
を引くことで求められる。
あるビット数からあるビット数への相対変換処理のC++言語でのコーディング例を以下に示す。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | - | | | | | | | | | | | ! - - ! | | - | | ! ! |
|
変換したい数値データが大量にある場合、あらかじめ上のコードにおける max_from 及び max_to を算出しておき、それを利用して計算する方が効率的である。