レガシー Windows API(概要)について

ここで紹介しているAPIは、Windows95、Windows NT3.5時代のAPI群であり、最新のAPIは含まれていないことに注しして欲しい。なお、当時の解説書は現在よりもより詳細に解説しているため、参考になるはずである。

  • レイアウトを変換する際、崩れているページがあります。
  • 概要およびSampleコードはありますが、APIの解説はありません。

ご要望があれば旧版のWin32 API(HELP形式)をお譲りします。問い合わせフォームより申し込みください。

Windows API ビットマップの概要

ビットマップは強力なグラフィック オブジェクトで、 イメージの作成や操作 (スケーリング、 スクロール、 回転、 ペイント) やディスクへのイメージの格納に使われます。

ビットマップは、 デバイス コンテキストで選択可能な7種類のオブジェクトの1つです。ビットマップ以外のオブジェクトには、 ペン、 ブラシ、 フォント、 リージョン、 論理パレット、 描画面があります。

次に示すトピックでは、 Win32のビットマップについて説明しています。

 

2つの種類のビットマップ

ビットマップとデバイス コンテキスト

ビットマップの回転

ビットマップのスケーリング

ブラシとしてのビットマップ

ビットマップの記憶域

ビットマップによるイメージのキャプチャ

ビットマップによるイメージのスケーリング

ビットマップによるイメージの格納

ビットマップ関数

Microsoft(R) Win32(R) アプリケーション プログラミング インターフェイス (API) では、 ビットマップを使用するアプリケーションの例として、 コントロール パネルがあります。ユーザーがデスクトップの壁紙を選択するとき、 実際にはビットマップが選択され、 Windowsはそのビットマップを使ってデスクトップの背景を描画します。

Windowsは、 32x32ピクセルのパターンをデスクトップに繰り返し描画することによって、 このパターンを作成します。このパターンは、 ビットマップとしてREDBRICK.BMPに格納されています。

ユーザーから見ると、 ビットマップは、 表示イメージを構成するピクセルでできた長方形です。しかし、 プログラマから見ると、 「ビットマップ」は、 次に示す要素を示す構造体の集合です。

・ ピクセルの長方形が作成されたデバイスの解像度や長方形の寸法、 ビットの配列のサイズなどを記述するヘッダー

・ 論理パレット

・ ビットマップ イメージのピクセルと論理パレットのエントリの関係を定義するビットの配列

 

次の図は、 プログラムから見たREDBRICK.BMPファイルのビットマップを示しています。パレット配列、 32x32ピクセルの長方形、 長方形に含まれるピクセルにパレットの色がマップされるインデックス配列が、 それぞれ示されています。

上記の例では、 ピクセルの長方形は、 16色のパレットを使ってVGAディスプレイで作成されています。16色のパレットには、 4ビットのインデックスが必要です。このため、 パレットの色をピクセルの色にマップする配列も、 4ビットのインデックスで構成されます。論理カラー パレットについて詳しくは、 色の概要を参照してください。

Windowsは、 インデックスからピクセルへのマッピングを、 長方形領域のいちばん下の走査行から開始して、 いちばん上の走査行まで行います (「走査行」とは、 ビデオ ディスプレイ上の1行の隣り合う「ピクセル」のことです)。上記の例では、 配列の最初の行 (0行目) は、 いちばん下のピクセル行 (走査行31) に対応します。

 

2種類のビットマップ - ビットマップの種類

ビットマップには、 デバイスに依存するビットマップ (DDB) とデバイスに依存しないビットマップ (DIB) の2種類があります。DDBは以前の (3.0よりも前の) バージョンのWindowsでは一般的でした。実際、 利用可能なビットマップはDDBだけでした。しかし、 ディスプレイ技術が改良され、 Windowsで使われるディスプレイ デバイスの種類が増加するにつれて、 DDBでは問題が起きてきました。たとえば、 ビットマップを作成したときのディスプレイの解像度を格納 (または取得) する方法がないため、 描画アプリケーションは、 現在使われているディスプレイ デバイスにそのビットマップが適しているかどうかを即座に判断できません。この問題を解決するため、 MicrosoftではDIBを規定しました。

 

デバイスに依存しないビットマップ

DIBには、 次に示す色情報と寸法情報が含まれます。

・ 長方形イメージが作成されたデバイスのカラー形式

・ 長方形イメージが作成されたデバイスの解像度

・ 長方形イメージが作成されたデバイスのパレット

・ RGBの組み合わせを長方形イメージのピクセルにマップするビットの配列

・ ビット配列のサイズを減らすために使われるデータ圧縮方法を示すデータ圧縮識別子

この情報は、 BITMAPINFOHEADER構造体と2つ以上のRGBQUAD構造体で構成されるBITMAPINFO構造体に格納されます。BITMAPINFOHEADERは、 ピクセル長方形の寸法、 デバイスの発色技術、 ビットマップのサイズを減らすために使われている圧縮方法を示します。RGBQUAD構造体は、 ピクセル長方形中のピクセルの表示色を示します。

DIBには、 原点が右下隅にある「ボトムアップ」DIBと原点が左上隅にある「トップダウン」DIBの2種類があります。BITMAPINFOHEADER構造体のbiHeightメンバで示されるDIBの高さが正の値ならば、 ボトムアップDIBであり、 負の値ならばトップダウンDIBです。トップダウンDIBは圧縮できません。

カラー形式は、 カラー プレーンとカラー ビットの数で示されます。カラー プレーンの個数は常に1です。カラー ビットの個数は、 モノクロ ビットマップでは1、 VGAビットマップでは4、 そのほかのカラー デバイスのビットマップでは8、 16、 24、 32などになります。特定のディスプレイ (またはプリンタ) で使われるカラー ビットの個数を取得するには、 BITSPIXELを2番目のパラメータに指定してGetDeviceCaps関数を呼び出してください。

ディスプレイ デバイスの解像度は、 メートル当たりのピクセル数で示されます。ディスプレイやプリンタの水平解像度を取得するには、 次に示す3つの手順に従ってください。

1. HORZRESを2番目のパラメータに指定して、 GetDeviceCaps関数を呼び出します。

2. HORZSIZEを2番目のパラメータに指定して、 GetDeviceCaps関数をもう一度呼び出します。

3. 最初の戻り値を2番目の戻り値で割ります。

垂直解像度を取得するには、 HORZRESの代わりにVERTRESHORZSIZEの代わりにVERTSIZEを指定して、 同じ手順を実行してください。

パレットは、 RGBQUAD構造体の配列で表現されます。この構造体は、 ディスプレイ デバイスのカラー パレットの色の赤、 緑、 青の各輝度要素を示します。パレット配列の各カラー インデックスは、 ビットマップに関連付けられている長方形領域の特定のピクセルにマップされます。この配列のビット単位のサイズは、 長方形のピクセル単位の幅と高さを掛けた値にデバイスのカラー ビット数を掛けた値に等しくなります。デバイスのパレットのサイズを取得するには、 NUMCOLORS定数を2番目の引数に指定して、 GetDeviceCaps関数を呼び出してください。

Win32 APIは、 ピクセル当たり8ビットのDIBとピクセル当たり4ビットのDIBのパレット配列の圧縮をサポートしています。パレット配列は、 ラン レングス符号化 (RLE) 法を使って圧縮されます。RLE法では、 2バイトの値を使用します。最初のバイトは1つのカラー インデックスを使用する連続するピクセルの個数を示し、 2番目のバイトはそのカラー インデックスを示します。ビットマップの圧縮について詳しくは、 BITMAPINFOHEADER構造体の説明を参照してください。

DIBを作成するには、 必要な構造体を初期化して、 CreateDIBitmap関数を呼び出してください。それから、 SetDIBits関数を呼び出して、 インデックスの配列を初期化してください。デバイスがこの関数をサポートしているかどうかを判断するには、 RASTERCAPSフラグにRC_DI_BITMAPを指定して、 GetDeviceCaps関数を呼び出してください。

DIBを使ってディスプレイ デバイスにピクセルを設定するには、 SetDIBitsToDevice関数またはBitBlt関数を呼び出してください。デバイスがSetDIBitsToDevice関数をサポートしているかどうかを判断するには、 RASTERCAPSフラグにRC_DIBTODEVを指定してGetDeviceCaps関数を呼び出してください。

単に既存のDIBを表示するだけでよいアプリケーションは、 SetDIBitsToDevice関数を使ってください。たとえば、 表計算アプリケーションは、 既存のグラフをオープンして、 SetDIBitsToDevice関数を使ってウィンドウにそのグラフを表示できます。ウィンドウにビットマップを繰り返し再描画するときは、 BitBlt関数を使ってください。BitBlt関数はSetDIBitsToDevice関数よりも高速なため、 たとえば、 アニメーション グラフィックとサウンドを同時に再生するマルチメディア アプリケーションでは、 BitBlt関数を使った方がよいでしょう。

 

デバイスに依存するビットマップ

デバイスに依存するビットマップは、 バージョン3.0以前のWindows用に作成されたアプリケーションとの互換性を保つためだけにサポートされています。新しいアプリケーションを作成するときや、 以前のバージョン用のアプリケーションをWin32プラットフォームに移植するときは、 DIBを使用してください。

DDBは、 BITMAP構造体だけで記述されます。この構造体のメンバは、 長方形領域のピクセル単位の幅と高さ、 デバイス パレットのエントリをピクセルにマップする配列の幅、 カラー プレーン数とピクセル当たりのビット数で表現されたデバイスのカラー形式を示します。デバイスのカラー形式を取得するには、 適切な定数を指定して、 GetDeviceCaps関数を呼び出してください。

DDBには、 廃棄可能と廃棄不可能の2種類があります。廃棄可能DDBは、 そのビットマップがDCで選択されておらず、 システム メモリが不足している場合にWindowsによって廃棄されます。CreateDiscardableBitmap関数は、 廃棄可能ビットマップを作成します。CreateBitmap関数、 CreateCompatibleBitmap関数、 CreateBitmapIndirect関数は、 廃棄不可能ビットマップを作成します。

ビットマップとデバイス コンテキスト

ビットマップ、 デバイス コンテキスト、 描画面

「デバイス コンテキスト」(DC) とは、 グラフィック オブジェクト、 それに関する属性、 デバイスへの出力に影響を与えるグラフィック モードを定義するデータ構造体です。DCを作成するには、 CreateDC関数を呼び出してください。ウィンドウ マネージャのデバイス コンテキストを取得するには、 GetDC関数を呼び出してください。

 

描画面

ウィンドウ マネージャは、 DCを識別するハンドルを返す前に、 描画面をDCで選択します。アプリケーションがCreateDC関数を呼び出してVGAディスプレイのデバイス コンテキストを作成すると、 この描画面の寸法は640x480ピクセルになります。アプリケーションがGetDC関数を呼び出すと、 寸法にはクライアント領域のサイズが反映されます。

CreateDCGetDCで取得したハンドルをグラフィック デバイス インターフェイス (GDI) 描画関数に渡すと、 要求された出力は、 そのデバイス コンテキストで選択されている描画面に表示されます。

 

互換デバイス コンテキスト

出力を実際のデバイスに送らずにメモリに置けるようにするため、 Windowsでは、 「互換デバイス コンテキスト」と呼ばれる、 ビットマップ操作用の特別なデバイス コンテキストを用意しています。Windowsは、 互換DCによって、 メモリの一部を仮想デバイスとして扱うことができます。この仮想デバイスは、 メモリ中のビット配列で、 通常の描画面で作成したビットマップの色データを一時的に格納するのに使うことができます。

互換DCを作成するには、 CreateCompatibleDC関数を呼び出して、 通常のデバイス コンテキストを識別するハンドルを取得してください。Windowsは、 配列の一時的な1ビットのプレースホルダを作成します。アプリケーションは、 互換DCハンドルを使って描画操作を行う前に、 この配列のサイズを増やしてください。配列のサイズを増やすには、 CreateBitmap関数やCreateBitmapIndirect関数、 CreateCompatibleBitmap関数を使って適切な寸法のビットマップを作成し、 SelectObject関数を呼び出して、 そのビットマップをDCで選択してください。ビットマップを互換DCで選択すると、 Windowsは、 指定されたピクセル長方形の色情報を格納できるサイズの配列で1ビット配列を置き換えます。

CreateCompatibleDCで取得したハンドルをGDI描画関数のいずれかに渡すと、 要求された出力は、 デバイスの描画面には表示されません。しかし、 Windowsは、 関数の出力結果の直線や曲線、 テキスト、 リージョンなどをビット配列に格納します。メモリに格納されたイメージを描画面にコピーするには、 転送元デバイス コンテキストとして互換DC、 転送先デバイス コンテキストとしてウィンドウまたは画面のDCを指定して、 BitBlt関数を呼び出してください。

 

ビットマップの回転

Windowsでは、 ビットマップを平行四辺形にコピーする関数を用意しています。このPlgBlt関数は、 転送元デバイス コンテキストの長方形から転送先デバイス コンテキストの平行四辺形へのビット ブロック転送を行います。ビットマップを回転するには、 平行四辺形の頂点を示す座標をワールド座標系で指定してください (回転とワールド座標系について詳しくは、 座標空間および座標変換の概要を参照してください)。

 

ビットマップのスケーリング

Windowsは、 ビットマップをスケール変更するための関数も用意しています。このStretchBlt関数は、 転送元デバイス コンテキストの長方形から転送先デバイス コンテキストの長方形へのビット ブロック転送を行います。しかし、 転送元長方形の寸法を転送先長方形にそのまま使うBitBlt関数とは異なり、 StretchBltでは、 転送元長方形と転送先長方形の寸法を指定できます。転送先ビットマップが転送元ビットマップよりも小さいときは、 Windowsは、 ビットマップの色データの行や列を統合してから、 対応するイメージをディスプレイ デバイスに表示します。Windowsは、 指定されている伸縮モードに従って色データを統合します。伸縮モードは、 SetStretchBltMode関数を呼び出して定義できます。転送先ビットマップが転送元ビットマップよりも大きいときは、 Windowsは、 転送先イメージの各ピクセルを拡大します。

 

ブラシとしてのビットマップ

Windowsは、 デバイス コンテキストで現在選択されているブラシを使ってビットマップ操作を行うための関数を用意しています。たとえば、 PatBlt関数は、 ウィンドウ内の長方形領域をブラシを使って描画します。また、 FloodFill関数は、 ウィンドウ内の指定された色で囲まれた領域をブラシで描画します (PatBltと異なり、 FloodFillは長方形でない図形を塗りつぶします)。

PatBlt関数の名前 (パターン ブロック転送) は、 指定された長方形が塗りつぶされるまでブラシ (またはパターン) を単に複製し続けることに由来しています。しかし、 この関数は実際にはより強力です。この関数は、 ブラシを複製する前に、 パターンの色データとディスプレイの既存のピクセルの色データをラスタ オペレーション (ROP) を使って組み合わせます。ROPとは、 複製されるブラシの色データやディスプレイ デバイスの転送先長方形の色データのビットに適用されるビット単位の操作です。Windowsには、 256個のROPがあります。しかし、 PatBlt関数は、 パターンと転送先を必要とするROPだけを認識します (転送元を必要とするROPは認識しません)。よく使われる5つのROPを次の表に示します。

ROP 説明

PATCOPY パターンを転送先ビットマップにコピーします。

PATINVERT 論理XOR演算子を使って、 転送先ビットマップとパターンを組み合わせます。

DSTINVERT 転送先ビットマップを反転します。

BLACKNESS 出力をすべて2進の0にします。

WHITENESS 出力をすべて2進の1にします。

FloodFill関数は、 指定された色で囲まれた領域内でブラシを複製します。しかし、 PatBlt関数とは異なり、 FloodFillはブラシの色データとディスプレイ ピクセルの色データを組み合わせません。この関数は、 ディスプレイのある領域内のすべてのピクセルの色を、 デバイス コンテキストで現在選択されているブラシの色に設定するだけです。

 

ビットマップの記憶域

ビットマップは、 Windowsで規定されている形式で格納し、 名前には.BMP拡張子を付けてください。Windows形式を次の図に示します。Windows規定の形式は、 BITMAPFILEHEADER構造体とその後に続くBITMAPINFOHEADER構造体で構成されています。RGBQUAD構造体 (カラー テーブル) の配列が、 BITMAPINFOHEADER構造体に続きます。カラー テーブルの後に、 カラー テーブルのインデックスの2番目の配列 (実際のビットマップ データ) が続きます。

Window形式を次の図に示します。

BITMAPFILEHEADER構造体のメンバは、 ビットマップのファイル、 ファイルのバイト単位のサイズ、 ヘッダーの最初のバイトからビットマップ データの最初のバイトまでのオフセットを示します。BITMAPINFOHEADER構造体のメンバは、 ビットマップのピクセル単位の幅と高さ、 ビットマップを作成したときのディスプレイ デバイスのカラー形式 (プレーン数とピクセル当たりのビット数)、 ビットマップ データが圧縮されているかどうかと使われている圧縮の種類、 ビットマップデータのバイト数、 ビットマップを作成したときのディスプレイ デバイスの解像度、 データで使われている色数を示します。RGBQUAD構造体は、 デバイスのパレットの各色のRGB輝度値を示します。カラー インデックス配列は、 RGBQUAD配列のインデックス値をディスプレイ上の長方形領域内のピクセルにマップします。

次に示す16進出力は、 REDBRICK.BMPファイルの内容を示しています。

0000 42 4d 76 02 00 00 00 00 00 00 76 00 00 00 28 00
0010 00 00 20 00 00 00 20 00 00 00 01 00 04 00 00 00
0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0030 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80
0040 00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80
0050 00 00 80 80 80 00 c0 c0 c0 00 00 00 ff 00 00 ff
0060 00 00 00 ff ff 00 ff 00 00 00 ff 00 ff 00 ff ff
0070 00 00 ff ff ff 00 00 00 00 00 00 00 00 00 00 00
0080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 09 00
0090 00 00 00 00 00 00 11 11 01 19 11 01 10 10 09 09
00a0 01 09 11 11 01 90 11 01 19 09 09 91 11 10 09 11
00b0 09 11 19 10 90 11 19 01 19 19 10 10 11 10 09 01
00c0 91 10 91 09 10 10 90 99 11 11 11 11 19 00 09 01
00d0 91 01 01 19 00 99 11 10 11 91 99 11 09 90 09 91
00e0 01 11 11 11 91 10 09 19 01 00 11 90 91 10 09 01
00f0 11 99 10 01 11 11 91 11 11 19 10 11 99 10 09 10
0100 01 11 11 11 19 10 11 09 09 10 19 10 10 10 09 01
0110 11 19 00 01 10 19 10 11 11 01 99 01 11 90 09 19
0120 11 91 11 91 01 11 19 10 99 00 01 19 09 10 09 19
0130 10 91 11 01 11 11 91 01 91 19 11 00 99 90 09 01
0140 01 99 19 01 91 10 19 91 91 09 11 99 11 10 09 91
0150 11 10 11 91 99 10 90 11 01 11 11 19 11 90 09 11
0160 00 19 10 11 01 11 99 99 99 99 99 99 99 99 09 99
0170 99 99 99 99 99 99 00 00 00 00 00 00 00 00 00 00
0180 00 00 00 00 00 00 90 00 00 00 00 00 00 00 00 00
0190 00 00 00 00 00 00 99 11 11 11 19 10 19 19 11 09
01a0 10 90 91 90 91 00 91 19 19 09 01 10 09 01 11 11
01b0 91 11 11 11 10 00 91 11 01 19 10 11 10 01 01 11
01c0 90 11 11 11 91 00 99 09 19 10 11 90 09 90 91 01
01d0 19 09 91 11 01 00 90 10 19 11 00 11 11 00 10 11
01e0 01 10 11 19 11 00 90 19 10 91 01 90 19 99 00 11
01f0 91 01 11 01 91 00 99 09 09 01 10 11 91 01 10 91
0200 99 11 10 90 91 00 91 11 00 10 11 01 10 19 19 09
0210 10 00 99 01 01 00 91 01 19 91 19 91 11 09 10 11
0220 00 91 00 10 90 00 99 01 11 10 09 10 10 19 09 01
0230 91 90 11 09 11 00 90 99 11 11 11 90 19 01 19 01
0240 91 01 01 19 09 00 91 10 11 91 99 09 09 90 11 91
0250 01 19 11 11 91 00 91 19 01 00 11 00 91 10 11 01
0260 11 11 10 01 11 00 99 99 99 99 99 99 99 99 99 99
0270 99 99 99 99 99 90
次の表は、 ビットマップ ファイル内の各構造体を構成するデータ バイトを示しています。

構造体 対応するバイト

BITMAPFILEHEADER 0x00から0x0D

BITMAPINFOHEADER 0x0Eから0x31

RGBQUAD配列 0x32から0x75

カラー インデックス配列 0x76から0x275

 

ビットマップの使用

次に示す処理をクリックすると、 その処理の実行方法が表示されます。

イメージのキャプチャ

イメージのスケーリング

イメージの恒久的な格納

 

ビットマップによるイメージのキャプチャ

イメージのキャプチャ

ビットマップを使うことによって、 イメージをキャプチャしたり、 キャプチャしたイメージをメモリに格納しておいて、 ウィンドウのほかの位置に表示したり、 ほかのウィンドウに表示することができます。

場合によっては、 イメージをキャプチャして一時的に格納しておきたいときがあります。たとえば、 描画アプリケーションで作成した画像をスケール変更したり「ズーム」するときは、 イメージの通常表示を一時的に保存しておいて、 ズーム表示を表示しなければなりません。後でユーザーが通常表示を選択したら、 保管しておいた通常表示のコピーでズーム イメージを置き換えなければなりません。

イメージを一時的に格納しなければならないときは、 現在のウィンドウDCと互換性があるDCを作成してください。これは、 CreateCompatibleDC関数を呼び出して行います。互換DCを作成したら、 CreateCompatibleBitmap関数を呼び出して適切な寸法のビットマップを作成し、 SelectObject関数を呼び出して、 そのビットマップを互換DCで選択してください。

互換デバイス コンテキストを作成し、 適切なビットマップをそのDCで選択したら、 イメージをキャプチャできます。Windowsには、 イメージをキャプチャするためのBitBlt関数が用意されています。この関数は、 ビット ブロック転送 (転送元ビットマップから転送先ビットマップへのデータのコピー) を行います。この関数はビットマップからデータをコピーするため、 この関数の2つの引数はビットマップのハンドルではないかと考える人もいるでしょう。しかし、 実際にはそうではなく、 BitBlt関数は、 2つのデバイス コンテキストを識別するハンドルを受け取り、 転送元DCで選択されているビットマップのビットマップ データを転送先DCにコピーします。この場合、 転送先DCは互換DCであるため、 BitBlt関数が転送を完了したとき、 イメージはメモリに格納されています。イメージを再表示するには、 互換デバイス コンテキストを転送元DCに、 ウィンドウ (またはプリンタ) のデバイス コンテキストを転送先DCに指定して、 もう一度BitBlt関数を呼び出してください。

デスクトップ全体のイメージをキャプチャするアプリケーションから抜粋した次に示すコード例は、 互換デバイス コンテキストと適切な寸法のビットマップを作成して、 そのビットマップを互換DCで選択し、 BitBlt関数を使ってイメージをコピーします。

次に示すコードの例はデスクトップ全体のイメージをキャプチャして、 互換デバイス コンテキストと適当な寸法のビットマップを作成し、 互換DCにビットマップを選択してBitBlt関数を使ってイメージをコピーするものです。

/*
* Create a normal DC and a memory DC for the entire screen. The
* normal DC provides a "snapshot" of the screen contents. The
* memory DC keeps a copy of this "snapshot" in the associated
* bitmap.
*/

hdcScreen = CreateDC("DISPLAY", NULL, NULL, NULL);
hdcCompatible = CreateCompatibleDC(hdcScreen);

/* Create a compatible bitmap for hdcScreen. */

hbmScreen = CreateCompatibleBitmap(hdcScreen,
GetDeviceCaps(hdcScreen, HORZRES),
GetDeviceCaps(hdcScreen, VERTRES));

if (hbmScreen == 0)
errhandler("hbmScreen", hwnd);

/* Select the bitmaps into the compatible DC. */

if (!SelectObject(hdcCompatible, hbmScreen))
errhandler("Compatible Bitmap Selection", hwnd);

/* Hide the application window. */

ShowWindow(hwnd, SW_HIDE);

/*
* Copy color data for the entire display into a
* bitmap that is selected into a compatible DC.
*/

if (!BitBlt(hdcCompatible,
0,0,
bmp.bmWidth, bmp.bmHeight,
hdcScreen,
0,0,
SRCCOPY))

errhandler("Screen to Compat Blt Failed", hwnd);

/* Redraw the application window. */

ShowWindow(hwnd, SW_SHOW); 

ビットマップによるイメージのスケーリング

イメージのスケーリング

アプリケーションは、 イメージをスケール変更する (拡大または縮小したイメージを表示する) ことがあります。たとえば、 描画アプリケーションでは、 ユーザーが画像をピクセル単位で表示したり編集できるようにするための画像をズーム機能を用意する場合があります。

イメージをスケール変更するには、 StretchBlt関数を呼び出します。StretchBltは、 BitBlt関数のように、 転送元DCで選択されているビットマップのビットマップ データを転送先DCのビットマップにコピーします。しかし、 StretchBltは、 BitBlt関数とは異なり、 指定された転送元と転送先の長方形の寸法に基づいて、 イメージをスケール変更します。転送元長方形が転送先長方形よりも大きいときは、 作成されるイメージは縮小されたイメージです。また、 転送元長方形が転送先長方形よりも小さいときは、 作成されるイメージは拡大されたイメージです。

転送先長方形が転送元長方形よりも小さいときは、 StretchBltは、 指定されている伸縮モードに従って、 イメージから色データを間引きします。伸縮モードを次の表に示します。

 

伸縮モード 使われる方法

BLACKONWHITE 間引きするピクセルの色データと残されるピクセルの色データに対して論理AND操作を実行します。

WHITEONBLACK 間引きするピクセルの色データと残されるピクセルの色データに対して論理OR操作を実行します。

COLORONCOLOR 間引きするピクセルの色データを完全に削除します。

HALFTONE 転送元の色データを転送先にできるだけ反映します。

伸縮モードを設定するには、 SetStretchBltMode関数を呼び出します。

次に示すコード例は、 イメージを元のサイズまたは元の2倍のサイズで表示するアプリケーションから抜粋したものです (このアプリケーションは、 デフォルトの伸縮モードを使用します)。

hdcScaled = CreateCompatibleDC(hdcScreen);

hbmScaled = CreateCompatibleBitmap(hdcScreen,
GetDeviceCaps(hdcScreen, HORZRES) * 2,
GetDeviceCaps(hdcScreen, VERTRES) * 2);

if (hbmScaled == 0)
errhandler("hbmScaled", hwnd);

/* Select the bitmaps into the compatible DC. */

if (!SelectObject(hdcScaled, hbmScaled))
errhandler("Scaled Bitmap Selection", hwnd);

case WM_COMMAND: /* message: command from application menu */
switch(wParam) {

case IDM_SCALEX1:
if (fBlt){
fScaled = FALSE;
hdcWin = GetDC(hwnd);
BitBlt(hdcWin,
0,0,
bmp.bmWidth, bmp.bmHeight,
hdcCompatible,
0,0,
SRCCOPY);
ReleaseDC(hwnd, hdcWin);
}
break;

case IDM_SCALEX2:
if (fBlt){
fScaled = TRUE;
StretchBlt(hdcScaled,
0, 0,
bmp.bmWidth * 2, bmp.bmHeight * 2,
hdcCompatible,
0, 0,
bmp.bmWidth, bmp.bmHeight,
SRCCOPY);

hdcWin = GetDC(hwnd);
BitBlt(hdcWin,
0,0,
bmp.bmWidth, bmp.bmHeight,
hdcScaled,
0,0,
SRCCOPY);
ReleaseDC(hwnd, hdcWin);
}
break;
 

ビットマップによるイメージの格納

イメージの格納

イメージを恒久的に格納するには、 ファイルがよく使われます。たとえば、 描画アプリケーションは画像を、 表計算アプリケーションはグラフを、 CADアプリケーションは図面をファイルに格納します。

ビットマップ イメージをファイルに格納するアプリケーションを作成するときは、 ビットマップの記憶域で説明したWindowsファイル形式を使ってください。ビットマップをこの形式で格納するには、 (BITMAPFILEHEADER構造体とRGBQUAD構造体の配列で構成される) BITMAPINFO構造体と、 パレット インデックスの配列を初期化してください。

次のコード例は、 BITMAPINFOHEADER構造体のメモリを割り当ててメンバを初期化する関数を定義しています。

PBITMAPINFO CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp) {
BITMAP bmp;
PBITMAPINFO pbmi;
WORD cClrBits;

/* Retrieve the bitmap's color format, width, and height. */

if (!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp))
errhandler("GetObject", hwnd);

/* Convert the color format to a count of bits. */

cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);

if (cClrBits == 1)
cClrBits = 1;
else if (cClrBits <= 4)
cClrBits = 4;
else if (cClrBits <= 8)
cClrBits = 8;
else if (cClrBits <= 16)
cClrBits = 16;
else if (cClrBits <= 24)
cClrBits = 24;
else
cClrBits = 32;

/*
* Allocate memory for the BITMAPINFO structure. (This structure
* contains a BITMAPINFOHEADER structure and an array of RGBQUAD data
* (structures.)
*/

if (cClrBits != 24)
pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * cClrBits);

/*
* There is no RGBQUAD array for the 24-bit-per-pixel format.
*/

else
pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
sizeof(BITMAPINFOHEADER));


/* Initialize the fields in the BITMAPINFO

pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = bmp.bmWidth;
pbmi->bmiHeader.biHeight = bmp.bmHeight;
pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;


/* If the bitmap is not compressed, set the BI_RGB flag. */

pbmi->bmiHeader.biCompression = BI_RGB;

/*
* Compute the number of bytes in the array of color
* indices and store the result in biSizeImage.
*/

pbmi->bmiHeader.biSizeImage = (pbmi->bmiHeader.biWidth + 7) /8
* pbmi->bmiHeader.biHeight
* cClrBits;

/*
* Set biClrImportant to 0, indicating that all of the
* device colors are important.
*/

pbmi->bmiHeader.biClrImportant = 0;

return pbmi;

}

The following example code defines a function that initializes the remaining structures, retrieves the array of palette indices, opens the file, copies the data, and closes the file.


void CreateBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi,
HBITMAP hBMP, HDC hDC)
{

HANDLE hf; /* file handle */
BITMAPFILEHEADER hdr; /* bitmap file-header */
PBITMAPINFOHEADER pbih; /* bitmap info-header */
HANDLE hmem; /* memory handle */
LPBYTE lpBits; /* memory pointer */
DWORD dwTotal; /* total count of bytes */
DWORD cb; /* incremental count of bytes */
BYTE *hp; /* byte pointer */
DWORD dwTmp;


pbih = (PBITMAPINFOHEADER) pbi;

lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);
if (!lpBits)
errhandler("GlobalAlloc", hwnd);

/*
* Retrieve the color table (RGBQUAD array) and the bits
* (array of palette indices) from the DIB.
*/

if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight,
lpBits, pbi, DIB_RGB_COLORS))
errhandler("GetDIBits", hwnd);

/* Create the .BMP file. */

hf = CreateFile(pszFile,
GENERIC_READ | GENERIC_WRITE,
(DWORD) 0,
(LPSECURITY_ATTRIBUTES) NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
(HANDLE) NULL);

if (hf == INVALID_HANDLE_VALUE)
errhandler("CreateFile", hwnd);

hdr.bfType = 0x4d42; /* 0x42 = "B" 0x4d = "M" */

/* Compute the size of the entire file. */

hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) +
pbih->biSize + pbih->biClrImportant
* sizeof(RGBQUAD) + pbih->biSizeImage);

hdr.bfReserved1 = 0;
hdr.bfReserved2 = 0;

/* Compute the offset to the array of color indices. */

hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) +
pbih->biSize + pbih->biClrImportant
* sizeof (RGBQUAD);

/* Copy the BITMAPFILEHEADER into the .BMP file. */

if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER),
(LPDWORD) &dwTmp, (LPOVERLAPPED) NULL))
errhandler("WriteFile", hwnd);

/* Copy the BITMAPINFOHEADER and RGBQUAD array into the file. */

if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER)
+ pbih->biClrImportant * sizeof (RGBQUAD),
(LPDWORD) &dwTmp, (LPOVERLAPPED) NULL))
errhandler("WriteFile", hwnd);

/* Copy the array of color indices into the .BMP file. */

dwTotal = cb = pbih->biSizeImage;
hp = lpBits;
while (cb > MAXWRITE) {
if (!WriteFile(hf, (LPSTR) hp, (int) MAXWRITE,
(LPDWORD) &dwTmp, (LPOVERLAPPED) NULL))
errhandler("WriteFile", hwnd);
cb-= MAXWRITE;
hp += MAXWRITE;
}
if (!WriteFile(hf, (LPSTR) hp, (int) cb,
(LPDWORD) &dwTmp, (LPOVERLAPPED) NULL))
errhandler("WriteFile", hwnd);

/* Close the .BMP file. */

if (!CloseHandle(hf))
errhandler("CloseHandle", hwnd);

/* Unlock and free memory. */

GlobalUnlock(hmem);
GlobalFree(hmem);
}

 

ビットマップ関数

ビットマップに関する関数を次に示します。

BitBlt

CreateBitmap

CreateBitmapIndirect

CreateCompatibleBitmap

CreateDIBitmap

CreateDIBSection

CreateDiscardableBitmap

ExtFloodFill

FloodFill

GetBitmapBits

GetBitmapDimensionEx

GetDIBColorTable

GetDIBits

GetPixel

GetStretchBltMode

LoadBitmap

MaskBlt

PatBlt

PlgBlt

SetBitmapBits

SetBitmapDimensionEx

SetDIBColorTable

SetDIBits

SetDIBitsToDevice

SetPixel

SetPixelV

StretchBlt

StretchDIBits

SetStretchBltMode

使われなくなったか、 または削除された関数

GetBitmapDimension

SetBitmapDimension

 

▲ページトップに戻る

【本を読んでもよくらからない】 … 個別指導でわかりやすくお教えします