今回は、8ビット(256色)DIBを作ってみます。フルカラーの時は、色をRGBで直接指定していましたが、256色ではカラーテーブルに256色分の色を自分で作って、カラーテーブルの値で色を指定する事になります。
そのため、256色のカラーテーブルをどんな色で作るかが大問題で、うまく作らないと貧弱な「絵」しか描けません。ただ、1ピクセルに1バイトでアクセスできるので速度の面ではかなり有利です。
カラーパテーブルの問題はありますが、8ビットDIBを作る事自体は特に難しいことではありません。BITMAPINFOHEADER構造体の後に256色分のカラーテーブル配列を置いて、BITMAPINFO構造体のbmiColors に先頭のカラーテーブルを設定すれば、8ビットDIBの完成です。
なお、カラーテーブルの具体的な内容は以下の形のRGBQUAD型構造体です。
typedef struct tagRGBQUAD { BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; BYTE rgbReserved; } RGBQUAD;
この構造体が256個続き、その先頭がBITMAPINFOのbmiColors になっているわけです。と言う事は、結局256色DIBの操作に必要なのは、BITMAPINFOとカラーテーブル、それに各ピクセルの色情報を格納するビットマップバッファ、の3つを保持するポインタ、という事になります。
lpBuf=GlobalAlloc(GPTR,sizeof(BITMAPINFO)+255*sizeof(RGBQUAD)+128*128); lpInfo=(LPBITMAPINFO)lpBuf; lpRGB=(LPRGBQUAD)(lpBuf+sizeof(BITMAPINFOHEADER)); lpBit=(LPBYTE)(lpBuf+sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD));
このように、3つの配列やバッファ用のメモリまとめて確保した後、それぞれにポインタを設定すれば管理が楽になるでしょう。ここでカラーテーブルRGBQUAD を256個でなく255個分確保しているのは、BITMAPINFO にすでに先頭の1個が含まれているからです。
BITMAPINFO の設定は、
lpInfo->bmiHeader.biSize=sizeof(BITMAPINFOHEADER); // BITMAPINFO構造体 lpInfo->bmiHeader.biWidth=128; lpInfo->bmiHeader.biHeight=128; lpInfo->bmiHeader.biPlanes=1; lpInfo->bmiHeader.biBitCount=8; lpInfo->bmiHeader.biCompression=BI_RGB; lpInfo->bmiHeader.biSizeImage=0; lpInfo->bmiHeader.biXPelsPerMeter=0; lpInfo->bmiHeader.biYPelsPerMeter=0; lpInfo->bmiHeader.biClrUsed=0; lpInfo->bmiHeader.biClrImportant=0; lpInfo->bmiColors[0]=lpRGB[0]; // カラーテーブルの先頭
という感じになります。
・カラーテーブルの設定
カラーテーブルに色を設定するには、RGBQUADのrgbRed,rgbGreen,rgbBlue にRGBの数値を指定します。例えば、カラーテーブルの先頭に赤を設定するなら、
lpRGB[0].rgbRed=255; lpRGB[0].rgbGreen=0; lpRGB[0].rgbBlue=0;
という感じになるわけです。プログラムでは、以下のようにして黒ー白のグレースケールを作っています。
for (i=0;i<256;i++) lpRGB[i].rgbRed=lpRGB[i].rgbGreen=lpRGB[i].rgbBlue=i;
・プログラム
今回のプログラムは、128*128の256色DIBに256段階のグレースケールを描画します。なるべくフルカラーでご覧ください。
プログラムソース表示