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ではビットマップが正常に表示されません。
| 戻る |