カラーテーブルで色を変える

1ピクセル256色(8ビット)DIBでは、各ピクセルの色を指定するのにカラーテーブルを使います。このカラーテーブルは、例えば1番は青、2番は赤、 というふうに番号で色を指定する方式ですので、カラーテーブルの内容が違えば(例えば、1番は緑、2番は紫など)、同じ「番号」を指定しても違う色になってしまうわけです。
これはちょうど絵を描く時に「パレット」に色を作っておいて、それで絵を描くような感じですね。256色DIBでは、一つのパレットに256色置いておけるわけですが、このパレット(カラーテーブル)は当然自分で作る事も出来ます。

さて、ここで一度描いた「絵」のパレットを変えるとどうなるでしょうか? 256色DIBの「絵」の実体は、ビットマップバッファに貯えられた各ピクセルの色情報でした。 そして、この場合の色情報とは他ならぬ「カラーテーブル」の値、つまりカラーテーブルの1番が青、2番が赤なら(1、1)は1番の色(青)、(1、2)は2番の色(赤)、などとなっているわけです。
という事は、このカラーテーブルの色を変えてやれば、ビットマップの方を変えないでも「色」を変えられる事になります。そう、カラーテーブル1番の色を変えてやれば、ビットマップの中にある1番の色すべてを瞬時に変えられるのです。
これだとビットマップの色を全体的に変えたい時などは、ビットマップの各ピクセルをいちいち書き換える必要がないので、処理効率の面で圧倒的に有利ですね。

パレットの色は自分で自由に設定できるので、この性質をうまく使うといろいろ面白い効果を生み出せるでしょう。画面フラッシュや、フェードイン・フェードアウトなどにも応用できるかもしれません。まあそういった応用は今後ゆっくり試す事にして、今回は実際にカラーテーブルを変更して、DIBの色を変える実験をやってみましょう。

カラーテーブルの構造と設定

256色DIBのカラーテーブルは、以下の形のRGBQUAD 型が256個続いた配列になっています。

typedef struct tagRGBQUAD {
        BYTE    rgbBlue;   // 青成分
        BYTE    rgbGreen;  // 緑成分
        BYTE    rgbRed;    // 赤成分
        BYTE    rgbReserved;
} RGBQUAD;

この配列の先頭アドレスはBITMAPINFObmiColorsなので256色のパレットをカラーテーブルに設定するには、以下のような処理をすれば良い事になります。

・「パレット」をRGBQUAD[256] という配列に作る。

・作成したパレットをbmiColors からのsizeof(RGBQUAD)*256 バイトに転送してDIBのカラーテーブルに設定する。

・新たなカラーテーブルでDIBを画面に描画する。

カラーテーブルやパレットのRGBQUAD 構造体では、色の各成分を0ー255の256段階で指定するので、例えばグレースケール(黒ー白のグラデーション)のパレットを作成するには、

  for (i=0;i<256;i++) {

	grayPal[i].rgbRed=i; // グレースケールパレット作成
	grayPal[i].rgbGreen=i;
	grayPal[i].rgbBlue=i;

  }

という感じになります。これで、grayPal[0]からgrayPalette[255] に256段階グレースケールのパレットが出来ました。後は、

CopyMemory(lpRGB,grayPal,sizeof(RGBQUAD)*256);

 として、このパレットをDIBのカラーテーブルに転送して再描画すれば良いだけです(lpRGB はカラーテーブルの先頭アドレス)。

・プログラム

今回のプログラムは、最初グレースケールが描かれたビットマップをカラーテーブルを変更する事で、赤や緑、青のグラデーションに変える例です。Gray、Red、Green、Blue の各ボタンをクリックするとビットマップの色が変わります。

・ボタンクリックでカラーテーブルを変える処理

  case WM_COMMAND:

	switch (LOWORD(wParam)) {

		case 0: // Grayボタン
			CopyMemory(lpRGB,grayPal,sizeof(RGBQUAD)*256);
			break;

		case 1: // Redボタン
			CopyMemory(lpRGB,redPal,sizeof(RGBQUAD)*256);
					break;

		case 2: // Greenボタン
			CopyMemory(lpRGB,greenPal,sizeof(RGBQUAD)*256);
			break;

		case 3: // Blueボタン
			CopyMemory(lpRGB,bluePal,sizeof(RGBQUAD)*256);
			break;

	}

	InvalidateRgn(hwnd,NULL,FALSE);
	UpdateWindow (hwnd);             // 再描画

	return 0;

プログラムソース表示

起動したら、適当なbmpファイルを読み込んで、ボタンをクリックしてみてください。


DIB/Waveとグラフィック・音声処理実験室