DIB操作関数を作る第2回

 前回に続いてDIB操作関数を作りましょう。 今回は、まず指定した点に指定した色で点を打つ関数を作ります。 関数の形は、

 int psetIBMP(HIBMP hb,int x,int y,int c)

 として、(x,y)c で指定した色の点を打つようにします。 ただし、指定した点がDIBの範囲を超えていたら、エラーとして0を返しましょう。 色の指定は、 下位24ビットでRGBをそれぞれ8ビットで指定するおなじみの方式です (上位8ビットは無視)。この数値からRGB各成分を取り出すには、

	b=(c & 0x00ff0000)>>16; // B(青)成分
	g=(c & 0x0000ff00)>>8; // G(緑)成分
	r=c & 0x000000ff; // R(赤)成分

 と各成分のビットのみを取り出してから、シフトして1バイトに収めます。

 前回作ったDIB構造体には、ビットマップのバッファへのポインタlpBMP とビットマップの横幅width、高さheight が格納されていますから、 ビットマップhbの点(x,y) にアクセスするには、 hb.lpBMP[(y*hb.width+x)*3] からの3バイトを参照すれば良いですね。 以上の事から、 「指定した点に指定した色の点を打つ」関数は以下のようになります。

  int psetIBMP(HIBMP hb,int x,int y,int c) {

	  BYTE r,g,b;

	  if (x>hb.width-1 || y>hb.height-1) // 範囲外ならエラー
		  return 0;

	  b=(c & 0x00ff0000)>>16; // B(青)成分を分離
	  g=(c & 0x0000ff00)>>8; // G(緑)成分を分離
	  r=c & 0x000000ff; // R(赤)成分を分離

	  hb.lpBMP[(y*hb.width+x)*3]=b;
	  hb.lpBMP[(y*hb.width+x)*3+1]=g;
	  hb.lpBMP[(y*hb.width+x)*3+2]=r;

	  return 1;

  }

・DIBにDIBを描く

 次にDIBを他のDIBの上に描く(上書き)関数を作ってみましょう。 DIBのビットマップは単なる配列として扱えるので、 やる事は単純な配列のコピーだけです。 配列の大きさは、width、height を見ればわかるので、 描画するDIBの全範囲を描画対象のDIBの指定位置から、 横幅width 高さheight だけコピーする事になります。
 コピーするには1ピクセル(3バイト)づつコピーしていっても良いのですが、 描画対象のDIBは単純な長方形ですからwidth 分をまとめてCopyMemory で転送してしまいましょう。 単純に考えて関数にすると、

  void drawIBMPtoIBMP(HIBMP srcI,int x,int y,HIBMP desI) {

	  int i;

	  for (i=0;i<srcI.height;i++) // 一列づつコピー
		  CopyMemory(desI.lpBMP+((i+y)*desI.width+x)*3,
		     srcI.lpBMP+srcI.width*i*3,srcI.width*3);

  }
 という形になります。srcI が描画するDIB、desI が描画対象のDIBで(x,y) が描画座標です。
 ただし、 これだけだと描画するDIBを描画対象DIBの「外」に描こうとした時に、 重大な問題が生じます。 右端からはみ出た部分が次の列(一列上)の左端の部分に描かれたり、 確保されたバッファ以外の場所に書き込もうとしてエラーになってしまうのです (なぜそうなるかは、DIBの構造を考えればわかるでしょう)。

 この問題に対処するには、 描画対象のDIBと描画するDIBの大きさや描画する座標を調べて、 描画するDIBがはみだすようならその部分を除いて描く「クリッピング」 を行う必要があります。 次回は、このクリッピング処理を考えてみましょう。

・プログラム

 今回のプログラムはdrawIBMPtoIBMP を使って、 64*64ピクセルのDIBに32*32ピクセルのDIBを「上書き」する例です。 それぞれのビットマップは、まずpsetIBMP で青と緑に塗られてから、 64*64のビットマップの上に32*32のビットマップが描かれ、 画面に描画されます。

プログラムソース表示
戻る