8ビットBMPの読み込み

8ビットDIB/BMPはフルカラーの中から(最大)256色のカラーテーブル(パレット)を作成し、このカラーテーブルの中の色を使って画像を表現しています。ピクセル列はカラーテーブルのインデックスを表す1ピクセル8ビットで表され、カラーテーブルさえうまく設計すれば実用上十分な表現力を持つので、ゲームやアニメ調の絵でよく使われる(今となっては使われていた、かな)形式ですね。今回は8ビットBMPを読み込んで、その画像を32ビットフルカラーDIBに描いてみましょう。

カラーテーブルの作成

8ビットBMPのカラーテーブルは、BITMAPINFOHEADERの後(BITMAPINFObmiColors)にRGBQUADの配列として格納されています。ピクセル列の各ピクセルの値はこのカラーテーブルのインデックスになっており、例えば(1、 1)が0なら、それは(1、 1)のピクセルがカラーテーブル0番の色である事を表します。実際に使用されている色数が256未満の場合は、カラーテーブルを実際の色数分だけ用意しその数をBITMAPINFOHEADERbiClrUsedで指定できますが、biClrUsedを0にすると使用色数が256色とみなされます。
 カラーテーブルの各RGBを表すRGBQUADは、RGBそれぞれ1バイトと未使用1バイトの4バイトで構成され、メモリ上の形式は32ビットDIBRGB値と同じみたいです。という事は、このカラーテーブルの先頭ポインタをLPDWORD型ポインタに代入すれば、そのポインタを32ビットDIBRGBに対応したカラーテーブルとして利用できる事になりますね。

 実際のカラーテーブルの作成は簡単で、まずファイルを読み込みlpbiHeadBITMAPINFOのポインタを設定したらlpbiHead->bmiColorsLPDWORD型変数に入れるだけです。

  fh=CreateFile(lpszFn,GENERIC_READ,0,NULL,OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL,NULL); /* ファイルオープン */

  /* BMP読み込みバッファ確保 */
  lpBuf=(LPBYTE)GlobalAlloc(GPTR,GetFileSize(fh,NULL));

  ReadFile(fh,lpBuf,GetFileSize(fh,NULL),&dummy,NULL);

  lpbiHead=(LPBITMAPINFO)(lpBuf+sizeof(BITMAPFILEHEADER));

  offset=*(LPDWORD)(lpBuf+10);
  lpBMP=lpBuf+offset; /* ビットマップバッファの先頭アドレス */

  /* カラーテーブルdwColors設定 */
  dwColors=(LPDWORD)lpbiHead->bmiColors;

 これで、dwColorsに32ビットDIBRGB値としてそのまま使える形でカラーテーブルが格納されたので、後はBMP内の各ピクセルの番号に対応するRGBを32ビットDIBのピクセルに設定していくだけ。

  /* ビットマップの大きさ保存 */
  iWidth=lpbiHead->bmiHeader.biWidth;
  iHeight=lpbiHead->bmiHeader.biHeight;

  /* 32ビットDIB用バッファ確保 */
  lpDIB=(LPBYTE)GlobalAlloc(GPTR,(sizeof(BITMAPINFO)+iWidth*iHeight*4));

  /* 32ビットDIBのヘッダ・ピクセル列ポインタ設定 */
  lpbiInfo=(LPBITMAPINFO)lpDIB;
  lpPixel=(LPDWORD)(lpDIB+sizeof(BITMAPINFO));

  /* BITMAPINFO構造体設定 */
  lpbiInfo->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
  lpbiInfo->bmiHeader.biWidth=iWidth;
  lpbiInfo->bmiHeader.biHeight=iHeight;
  lpbiInfo->bmiHeader.biPlanes=1;
  lpbiInfo->bmiHeader.biBitCount=32;

  /* カラーテーブルdwColors設定 */
  dwColors=(LPDWORD)lpbiHead->bmiColors;

  if ((iWidth) % 4==0) /* バッファの1ラインの長さを計算 */
      iLength=iWidth;
  else
      iLength=iWidth+(4-(iWidth) % 4);

  /* カラーテーブルを参照して各ピクセルのRGBを設定 */
  for (i=0;i<iHeight;i++)
      for (j=0;j<iWidth;j++)
          lpPixel[j+i*iWidth]=dwColors[lpBMP[j+i*iLength]];

 上の例では、lpPixel[j+i*iWidth]が32ビットDIBのピクセルでlpBMP[j+i*iLength]が8ビットBMPのピクセルですね。8ビットビットマップの各ピクセルはカラーテーブルのインデックスなので、その値でカラーテーブルの配列を参照すれば(dwColors[lpBMP[j+i*iLength]]RGB値を取得できます。

プログラム

プログラムソース表示

 ドロップされた8ビットBMPから32ビットDIBを作成し、表示します。


プログラミング資料庫 > DIB/Waveによる音声画像処理実験室