Windows NT/2000/XPでは、32ビットDIBの色形式をビットフィールドを使って定義できます。これは、各ピクセル32ビットの中でRGB各成分が占める位置を自由に設定できる機能で、たとえばRを21-30ビット目、Gを11-20ビット目、Bを1-10ビット目、とするとRGB各10ビット、1024段階の精度を持つDIBになるわけです。
といっても、実際には8ビット以上にしても表示能力が追いつかないので、表示品質が向上するわけではありません。しかし、精度を上げるために10ビットで画像処理をしたり、各種機器から出力されるRGB各10ビットの高精度な画像データを読み込む、という場面では精度を落とすことなくそのまま画像データを保持・表示できるという利点はあるでしょう。
今回は、このビットフィールドを定義してRGB各10ビットの精度を持つ32ビットDIBを作ってみることにします。
32ビットDIBにビットフィールドを指定するには、BITMAPINFOHEADERのbiCompressionをBI_BITFIELDSにして、BITMAPINFOHEADERに続く12バイト(BITMAPINFOのbmiColors以下)にRGBのビットフィールドをそれぞれ32ビットで指定します。
ビットフィールドでは、その色成分の占めるビットを1で指定しますが、各色のビットが重ならないようにする必要があるので、注意が必要です。今回は、RGB各10ビットずつなので、1023(2進数で10個の1の並び、&B1111111111)をシフトしながらビットフィールドを設定してみました。
lpDIB = (LPBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFO) + 512 * 512 * 4); /* BITMAPINFOのポインタ設定 */ lpbiInfo = (LPBITMAPINFO)lpDIB; /* ビットフィールドのポインタ設定 */ lpBitFields = (LPDWORD)(lpbiInfo->bmiColors); /* ピクセル列のポインタ設定 */ lpPixel = (LPDWORD)(lpBitFields + 3); /* BITMAPINFO内のBITMAPINFOHEADER設定 */ lpbiInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); lpbiInfo->bmiHeader.biWidth = 512; lpbiInfo->bmiHeader.biHeight = -512; lpbiInfo->bmiHeader.biPlanes = 1; lpbiInfo->bmiHeader.biBitCount = 32; lpbiInfo->bmiHeader.biCompression = BI_BITFIELDS; /* R成分ビットフィールド */ lpBitFields[0] = 1023 << 20; /* G成分ビットフィールド */ lpBitFields[1] = 1023 << 10; /* B成分ビットフィールド */ lpBitFields[2] = 1023;
これで512*512ピクセル、RGB各10ビットの精度を持つ32ビットDIBができました。
続いてピクセル列に書き込んでみましょう。今回のピクセル列は、各ピクセル32ビットでそのうち下位30ビットにRGBが10ビットずつ配置されています。よって、RGB各成分を0-1023の範囲にしておけば、以下の式で32ビットの値が求まることになります。
(r << 20) + (g << 10) + b
今回のプログラムでは、以下のようにしてR/G/B/RGBの各成分を512-1023に変化させていく512段階のグラデーションを描いてみました。
/* 赤のグラデーション */ for (i = 0;i < 128;i++) { for (j = 0;j < 512;j++) { lpPixel[j + i * 512] = (j + 512) << 20; } } /* 緑のグラデーション */ for (i = 128;i < 256;i++) { for (j = 0;j < 512;j++) { lpPixel[j + i * 512] = (j + 512) << 10; } } /* 青のグラデーション */ for (i = 256;i < 384;i++) { for (j = 0;j < 512;j++) { lpPixel[j + i * 512] = (j + 512); } } /* 白黒のグラデーション */ for (i = 384;i < 512;i++) { for (j = 0;j < 512;j++) { r = g = b = (j + 512); lpPixel[j + i * 512] = (r << 20) + (g << 10) + b; } }
実行すると、グラデーションが描かれた512*512ピクセルのビットマップが表示されます。マウスをビットマップの領域に移動させるとマウスカーソル直下のピクセルのRGB値がタイトルバーに表示されるので、グラデーションとRGBの対応を確認し実際にRGBが10ビット(1024段階)で表現されていることを確かめてください。
なお、今回のプログラムはWindows NT/2000/XP専用です。95/98/Meではビットマップが正常に表示されません。
戻る |