ホーム 主筆 その他ソフト その他情報 Syuhitu.org English

Windows関連

スクリーンセーバー作成法

半透明ウインドウの性能

bootfont.bin

キャビネット形式

ウインドウスタイルをいじる

Java製ソフトをServiceに登録する

イベントログにメッセージを出力する

コントロールパネルにアイコンを追加する

スクリプトによる拡張1

スクリプトによる拡張2

ガジェットの作成

大容量メモリ

メモリ搭載量の下限に挑む

スパースファイルにする

Solaris関連

OpenGL

Solaris設定

ディレクトリの読み込み

主筆プラグイン開発

マルチスレッドでの開発

door

音を出す

Blade100の正しい虐め方

パッケージの作成

画像入出力

BMPファイル

ICOファイル

ANIファイル

JPEGファイル

減色アルゴリズム

減色アルゴリズムの並列化

その他アルゴリズムなど

自由軸回転

Base64

文字列操作

CPU利用率の取得

正規表現ライブラリ

メタボールを作る

メタボールを作る2

正規表現とNFA・DFA

C言語の構文解析

液晶ディスプレイを解体してみた

iSCSIの理論と実装

BMPファイル形式

Windowsで広く使用されているビットマップファイルの、ファイルフォーマットについての解説です。

Windows上でBMPファイルを使用する限りであれば、特に自力で解析する必要はないし、むしろそうすべきではありません。しかし、Windows以外の環境、例えばUNIX系OSでBMPファイルを取り扱う必要がある場合には、全てを独力で処理しなければなりません。

ファイル形式の概略

ファイルは主に以下のような構造をしています。

BITMAPFILEHEADER構造体
BITMAPINFOHEADER構造体
RGBQUAD構造体の配列
ピクセルのデータ

まず、BITMAPFILEHEADERとBITMAPINFOHEADERを読み込み、ファイルの種類を判定し、必要ならカラーテーブルを読み込み、ピクセルデータを読み込むという手順になります。

また、下記で使用する構造体や定数はwindows.hをインクルードすると、その中(でインクルードされている「Wingdi.h」というヘッダファイル内で)定義されています。

BITMAPFILEHEADER構造体

BITMAPFILEHEADER構造体は以下のような形式をしています。

typedef struct tagBITMAPFILEHEADER {
    WORD bfType;
    DWORD bfSize;
    WORD bfReserved1;
    WORD bfReserved2;
    DWORD bfOffBits;
} BITMAPFILEHEADER;
  • bfTypeにはBMという値が格納されています。PC上のリトルエンディアンな環境では0x4D42という値と比較して、開いたファイルがビットマップ形式かどうかを判断することになります。
  • bfSizeにはビットマップファイルのサイズが記録されています。しかし、Windows付属のペイントはこの値を参照していません(私の経験上)。信用しない方がいいと思います。
  • bfReserved1bfReserved2は0が記録されています。
  • bfOffBitsにはBITMAPFILEHEADER構造体の開始位置からピクセルのデータの開始位置までのバイト数が記録されています。つまり、sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ) + ( sizeof( RGBQUAD ) * カラーテーブル数 )の値が記録されています。

この構造体に記録されている情報で興味があるのはbfTypeぐらいです。とりあえず読み込んだらファイルの種別を判別した方がいいでしょう。

BITMAPINFOHEADER構造体

BITMAPINFOHEADER構造体は以下の様な形式をしています。

typedef struct tagBITMAPINFOHEADER {
    DWORD  biSize;
    LONG   biWidth;
    LONG   biHeight;
    WORD   biPlanes;
    WORD   biBitCount;
    DWORD  biCompression;
    DWORD  biSizeImage;
    LONG   biXPelsPerMeter;
    LONG   biYPelsPerMeter;
    DWORD  biClrUsed;
    DWORD  biClrImportant;
} BITMAPINFOHEADER;
  • biSizeにはsizeof( BITMAPINFOHEADER )の値が記録されています。
  • biWidthには画像の横幅(ピクセル数)が記録されています。
  • biHeightには画像の縦幅(ピクセル数)が記録されています。
  • biPlanesには「ターゲットのデバイスに対する面の数」を記録するそうですが、必ず「1」が記録されています。
  • biBitCountには1ピクセルあたりのビット数が記録されています。つまり1,4,8,24のいずれかです。
  • biCompressionには画像の圧縮方法が記録されています。ビットマップ形式の場合は「BI_RGB(0Lとして定義されてる)」が記録されています。
  • biSizeImageには画像のバイト数を記録することになっていますが、ビットマップ形式の場合は0が記録されています。
  • biXPelsPerMeterには「ビットマップを表示する対象のデバイスの1メートルあたりのピクセル数」(要は解像度)を記録することになっていますが、ペイントで生成したファイルの場合は1が記録されています。
  • biYPelsPerMeterもbiXPelsPerMeterと同じく1が記録されています。
  • biClrUsedには記録されているカラーテーブルの内、実際に使用しているカラーテーブルの数が記録されています。0が指定されている場合は全てのカラーテーブルを使用します。というより、いつも0が記録されています。
  • biClrImportantにはカラーテーブルの内「重要な」色のカラーテーブルの数が記録されています。0が記録されている場合は全ての色が重要であることを示します。というより、いつも、0が記録されています。

この構造体で興味がある情報はbiWidthとbiHeight・biBitCountです。

また、この構造体にはいろいろな種類があり、それぞれサイズが異なります。そのため、サポートするファイルの種類を増やしたい場合はこのサイズを見て次のデータの読み込む位置を決定してください。でも、現実的にはあまり気にしなくても何とかなります。

RGBQUAD構造体の配列

RGBQUAD構造体は以下のような構造をしています。

typedef struct tagRGBQUAD {
    BYTE rgbBlue; 
    BYTE rgbGreen; 
    BYTE rgbRed; 
    BYTE rgbReserved; 
} RGBQUAD;

ほぼ説明不要な構造体です。ファイル中にこの構造体の配列が記録されています。記録されている数はBITMAPINFOHEADERのbiBitCountの値から求めます。

biBitCount RGBQUADの数
1 2
4 16
8 256
24 0

biBitCountが24の場合はカラーテーブルはありません。それ以降に記録されているピクセルのデータがそのまま色を示しています。それ以外の場合は、読み込んだ「ピクセルのデータ」は、このカラーテーブルのインデックスとなっています。たとえばbiBitCountが8の時にピクセルデータとして0x01を読み込んだとしたら、カラーテーブルの1番目の色を参照します。

ピクセルのデータ

後は各ピクセルごとのデータを読み込むだけです。と言ってもこれが一番の曲者です。

各ピクセルごとのビット数

これは当然のことながらBITMAPINFOHEADERのbiBitCountの値です。もしこれが1とか4とかだった場合は1ビットごと・4ビットごとに読み込まなくてはなりません。

データの記録されている順番

ピクセルのデータはなぜか左下から右方向に向かって記録されています。つまりファイル中のピクセルデータの先頭は画像の左下であり、ファイル末尾に向かうにつれ画像を右に向かってゆき、右端に達したら1ピクセル上の行の左端に移動します。

画像のデータは左下から右上に向かって順に記録されています。

 

パディング

もう、最悪です。1行は必ず4バイト単位で記録されています。そして、もしBITMAPINFOHEADERのbiWidthが4で割り切れない場合は右端にパディングがあります。

1行ごとに4バイトの倍数になるようパディングされています。

たとえば24ビットカラーで横に10ピクセルあったとした場合、1行が32バイトで記録されていて31バイト目と32バイト目は意味のないデータだと言うことです。また、これが8ビットカラーだった場合は1行が12バイトで末尾の2バイトはパディングになります。

24ビットカラーにおける注意点

24ビットカラーの場合はカラーテーブルは使いません。その代わりに各ピクセルごと・各色ごとの強さが直接記録されています。

この際、通常ならばRGBが8ビットずつ記録されていると思いたくなりますが、ビットマップ形式の場合はBGRで記録されています。色の順番が逆なので気をつけてください。

読み込んでみる

以上のことをふまえてビットマップ形式のファイルを読み込んでみたいと思います。

ここでは、ビットマップを読み込み、HTMLを出力するものとします。ビットマップの各ピクセルを1つのセルとしたテーブルに変換致します。データ量が壮絶なことになりますが。

BmpIoLic.cとBITest.cをコンパイル・リンクして、実行形式のファイルを生成してください。

なお、ビッグエンディアンな環境で実行したい場合には、「BmpIoLib.c」中で定義している「ISLITTLEENDIAN」に”0”を指定してください。現状ではリトルエンディアン用となっています。


連絡先 - サイトマップ - 更新履歴
Copyright (C)  2000 - 2013 nabiki_t All Rights Reserved.