8ビットDIBを作る

概要:カラーテーブルによる色表現

8ビットDIBの色表現は32ビットや24ビット等のようにRGB成分そのものを指定するのではなく、
カラーテーブルのインデックスを指定する事で、間接的にRGB成分を指定します。
今回はその概念の違いをしっかりと理解して下さい。

8ビットDIBは消費メモリーが少なく、
任意の256色を使うことができるのでゲーム等によく使われます。

■カラーテーブル

32ビットや24ビットと異なるのはピクセル列に格納されている数値の意味です。
32ビットや24ビットの場合はRGB成分そのものでした。
しかし、8ビットの場合はカラーテーブルのインデックスです。

カラーテーブルにはRGB成分そのものが格納されています。
つまり、何番の色と指定すれば、
間接的にその番号に対応したRGB成分を指定した事になるのです。

カラーテーブルにはカラーパレットのインデックスが格納されている事もありますが、
今のところカラーパレットについて解説する予定はありません。

■カラーテーブルの作成

それではカラーテーブルはどこにあるのかというと、
BITMAPINFO 構造体の bmiColors メンバーがカラーテーブルの先頭を指しています。
ただし BITMAPINFO 構造体自体が1個のカラーテーブルを所有しています。
bmiColors[1] は先頭のカラーテーブルです。

従って、256個のカラーテーブルを作成したい場合は、
残り255個分のバッファを確保しなければなりません。

カラーテーブルのバッファは BITMAPINFO 構造体のバッファの
直ぐ後ろに確保すればいいでしょう。
bmiColors は BITMAPINFO 構造体の最後尾に位置しているので、
その直ぐ後ろにバッファを確保すれば、
予め用意されている1番目のカラーテーブルと2番目以降のカラーテーブルが
連続した領域にあることになり、アドレスの計算が楽です。

typedef struct tagBITMAPINFO {
  BITMAPINFOHEADER bmiHeader;
  RGBQUAD bmiColors[1];
} BITMAPINFO;

#define WIDTH   197
#define HEIGHT  100

#define BIT     8
#define COLOR   ((DWORD)pow(2,BIT))

static LPBYTE lpPixel;
static LPBITMAPINFO lpBmpInfo;
static int length;

//4の倍数に補正
if(WIDTH%4) length=WIDTH+(4-WIDTH%4);
else length=WIDTH;

lpPixel=(LPBYTE)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
    length*HEIGHT+sizeof(BITMAPINFO)+sizeof(RGBQUAD)*(COLOR-1));
lpBmpInfo=(LPBITMAPINFO)(lpPixel+length*HEIGHT);

■RGBQUAD構造体

カラーテーブルはRGBQUAD構造体で表現されます。

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


rgbReserved は予約されているので 0 を指定して下さい。

int i;

//カラーテーブルを設定する
for(i=0;i<COLOR;i++){
    lpBmpInfo->bmiColors[i].rgbBlue=i%128;
    lpBmpInfo->bmiColors[i].rgbGreen=128-i%128;
    lpBmpInfo->bmiColors[i].rgbRed=i%256;
}

カラーテーブルは先頭ほどよく使う色を設定するのがマナーになっていますが、
絶対のルールではありません。

■DIBの情報を設定する

32ビットや24ビットと同じですが、
BITMAPINFOHEADER 構造体の biClrUsed メンバーに
実際に使うカラーテーブルの数を指定することができます。
0 を指定すれば最大数を意味します。

また BITMAPINFOHEADER 構造体の biBitCount メンバーに8(ビット)以下の値を指定することで
カラーテーブルが参照されるようになります。

//DIBの情報を設定する
lpBmpInfo->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
lpBmpInfo->bmiHeader.biWidth=WIDTH;
lpBmpInfo->bmiHeader.biHeight=HEIGHT;
lpBmpInfo->bmiHeader.biPlanes=1;
lpBmpInfo->bmiHeader.biBitCount=BIT;
lpBmpInfo->bmiHeader.biCompression=BI_RGB;
//lpBmpInfo->bmiHeader.biClrUsed=COLOR;

■描画

ピクセル列に格納するのはカラーテーブルのインデックスです。
RGB成分そのものではありません。
また、0 に初期化されているピクセル列の初期色はカラーテーブルの 0 番に対応する色になります。

int x,y;

//描画
for(i=0,y=25;y<=50;y++){
    for(x=25;x<=50;x++){
        lpPixel[x+y*length]=(++i)%COLOR;
    }
}

■表示&解放

カラーテーブルを使用しているか、いないかは、
BITMAPINFOHEADER 構造体に設定されているビット数で判定されます。

case WM_PAINT:
    hdc=BeginPaint(hWnd,&ps);
    //表画面へ転送
    StretchDIBits(hdc,0,0,WIDTH,HEIGHT,
        0,0,WIDTH,HEIGHT,lpPixel,lpBmpInfo,DIB_RGB_COLORS,SRCCOPY);
    EndPaint(hWnd,&ps);
    return 0;
case WM_DESTROY:
    HeapFree(GetProcessHeap(),0,lpPixel);
    PostQuitMessage(0);
    return 0;

★☆ ソースファイル表示 ☆★


戻る / ホーム