DelphiによるDIB操作

 Delphiには、ビットマップを扱うTBitmapコンポーネントがあります。このコンポーネントは、HandleTypeプロパティの値をbmDIBにする事でDIBを扱えるようになるので、DIBに対してもCanvasを利用した描画が可能になるわけです。ちょうど、DIBSectionのような感覚で扱えるわけですね(というか内部の処理はDIBSectionそのものらしい)。
 今回は、このTBitmapDIBを扱う例としてフルカラービットマップの白黒化をやってみましょう。

TBitmapのDIB

 TBitmapDIBを扱うには、TBitmapオブジェクトを作成してからHandleTypebmDIBに設定し、PixelFormatプロパティでDIBの形式を設定します。今回の場合はフルカラーですが、処理の都合上(32ビットならInteger型でアクセスできる)24ビットではなく32ビットに設定しました。

  bmp:=TBitmap.Create; // ビットマップ作成
  bmp.HandleType:=bmDIB; // ビットマップの形式をDIBに設定
  bmp.PixelFormat:=pf32bit; // DIBの形式を32ビットに設定

 ビットマップコンポーネントを作成したら、ファイルからビットマップを読み込んでビットマップコンポーネントに描画しましょう。ただし、ここではビットマップコンポーネントに直接読み込むのではなく、一度作業用ビットマップに読み込んでからその作業用ビットマップをビットマップコンポーネントに描画するようにします。これは、読み込んだビットマップとビットマップコンポーネントの形式が一致しない時のための対策です。

  wBMP:=TBitmap.Create; // 作業用ビットマップ作成
  wBMP.LoadFromFile(FileName);

  bmp.Width:=wBMP.Width;
  bmp.Height:=wBMP.Height;
  bmp.Canvas.Draw(0,0,wBMP);

  wBMP.Free; // 作業用ビットマップ破棄

ビットマップとポインタ

 ビットマップを読み込んだら、白黒化します。白黒化するには、各ピクセルに対してRGB成分から明るさを計算し、RGBをすべてその明るさの値に設定しなおす、という処理をするわけですが、ビットマップコンポーネントのPixlesプロパティは速度的に不利なので、ピクセルを読み書きする時はポインタを使うと効果的です。具体的には、ビットマップ(DIB)の指定した横一列の先頭アドレスを返すScanLineプロパティを使って読み書きするピクセルのアドレスを計算してください。これを使うと、32ビットDIBbmpのピクセル(x ,y)は以下のアドレスに格納されている事になります。

  ptr(Integer(bmp.ScanLine[y])+x*4)

 整数型ポインタには、直接値を加減算できない点に注意してください。アドレスを計算する時には、一度ポインタをIntegerにキャストして「数値」にしてからアドレスを計算し、またptrで計算結果の数値をポインタに戻す操作が必要です。

 ポインタで示される場所にアクセスするには、ポインタ変数の後に^をつけます。これは、Cの*みたいなものですね。ただし、ある型のポインタを宣言する時には、^を型名の前につけて宣言するので注意してください。
 以上でビットマップにアクセスする方法は確認できましたので、ビットマップを白黒化する関数を作成します。処理自体は、Cでやった時とまったく同じですね。

procedure TForm1.grayScale(sBmp:TBitmap); // DIBを白黒化
var
  cl,i,j,r,g,b:Integer;
  p,pp:^Integer;
begin

  for i:=0 to sBmp.Height-1 do
  begin

    p:=sBmp.ScanLine[i]; // ビットマップ座標(0,i)のポインタ

    for j:=0 to sBmp.Width-1 do
    begin

      pp:=ptr(Integer(p)+j*4); // (j,i)のポインタ
      cl:=pp^; // clに(j,i)の値を32ビットで取得

      r:=cl and $ff; // RGB成分に分解
      g:=cl and $ff00 shr 8;
      b:=cl and $ff0000 shr 16;

      cl:=Round(r*0.3+g*0.59+b*0.11); // 明るさを計算

      pp^:=cl+cl shl 8+cl shl 16; // (j,i)に明るさを書き戻す

    end;

  end;

end;

 上のプログラムで、ポインタppへの読み書き(pp^の部分)をbmp.Canvas.Pixels[j,i]に変えると、Pixelsプロパティでピクセルにアクセスした場合の速度を調べる事が出来ます。ポインタでメモリに直接アクセスした場合との差を比べてみましょう。

プログラム

 実行したら、「開く」メニューで適当なビットマップファイルを読み込んでください。その後「白黒化」メニューをクリックすると読み込んだビットマップを白黒化します。

 ダウンロードしたプログラムをコンパイルするには、Delphi3以上が必要です。

プログラムダウンロード(delmono.lzh 137KB)

戻る