RGB各10ビットの32ビットDIB

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にビットフィールドを指定するには、BITMAPINFOHEADERbiCompressionBI_BITFIELDSにして、BITMAPINFOHEADERに続く12バイト(BITMAPINFObmiColors以下)に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ではビットマップが正常に表示されません。

プログラムソース表示

戻る