指定された色を透明色にして描画する(低速)

以前のテクニックで裏画面を作って描画するというものがありましたが、そのとき用いたBitBltを 使って、指定した色を透明にして描画するという方法を紹介します。のっけからやる気をなくさせるようなことを言うとタイトル通り実行速度は遅いです。でもまぁ アクションゲームを作るのでなければ十分でしょう。

最初に動作の中身だけを説明しましょう。まず描画する画像を用意します。

つぎに、描画したい部分が黒で、透過したい部分が白のモノクロビットマップを作成します。

モノクロビットマップを元に、透過部分が真っ黒なビットマップを作成します

描画先の画像を用意します

2つ目のビットマップをある方法で描画して、描画したい部分が黒くなるようにします

3つ目のビットマップをある方法で描画して、できあがりです。


動作の中身はこのようになっていますが、何でこんな事をするかということを説明しましょう。 画像のデータはRGB値で保持されていて、10000000,11111111,10101010のように2進数で表現しています。 BitBltではこの画像データをある一定な法則の元で転送させることができるのです。

少し具体例を挙げますと

SRCAND    オプション   転送元と転送先のビットが1ならば転送先は1それ以外は転送先は0
MERGEPAINT  オプション   転送元と転送先のどちらかのビットが1ならば転送先は1両方0ならば転送先は0
一般的にすると、F(転送元のビット,転送先のビット)=転送先のビット
といった感じでしょうか、有名どころの転送方法はオプションとして名前がついていますが名前がなくても 転送することはできます。


さて、今度は上で説明した処理が必要だったかを逆から考えてみましょう。

これが最終目標ですね。

この二つをSRCINVERT(From:0 To:1 or From:1 To:0で To 1)で転送すれば、最終目標の画像に辿りつけます。

上左の画像を作るには、転送元画像に、モノクロビットマップを反転したものをSRCANDで結合します。(転送オプションでできるので反転したものはいちいち作らない)

上右の画像を作るには、転送先画像に、モノクロビットマップをSRCANDで結合します。

あまりうまく説明できてませんが、別に分からなければ できないというわけではないので、BitBltのラストオペーレーションを使いながら覚えてください。 以下にプログラムリストを表示します。


プログラム部分

void Blit(HDC from,HDC to,int x,int y,int width,int height,int fromx,int fromy,COLORREF tran)
{
    HBITMAP bmono,oldmono,bkuro,oldkuro;
    HDC     mmono,mkuro;


    /*
      描画するビットマップと同じサイズのモノクロビット
     マップを作成し透明色の部分が白それ以外が黒となるよう
    にする。
    */

    mmono=CreateCompatibleDC(from);
    bmono=CreateBitmap(width,height,1,1,NULL);   
    oldmono=(HBITMAP)SelectObject(mmono,bmono);
    SetBkColor(from,tran);
    BitBlt(mmono,0,0,width,height,from,fromx,fromy,SRCCOPY); 
  

    /*
    メモリDCを作成し、元のビットマップと同じ物をコピーする。
    モノクロビットマップにNOT演算したものを
    作ったメモリDCにラスタオペレーションSRCANDでブリットしている。
    */

    mkuro=CreateCompatibleDC(from);
    bkuro=CreateCompatibleBitmap(from,width,height);
    oldkuro=(HBITMAP)SelectObject(mkuro,bkuro);
    BitBlt(mkuro,0,0,width,height,from,fromx,fromy,SRCCOPY);
    
    BitBlt(mkuro,0,0,width,height,mmono,fromx,fromy,0x220326);
      //↑のラスタオペレーションでNOT演算とSRCANDの作業が一度にできる

    /*
    出力先のDCにモノクロビットマップを持つDCを
    ラスタオペレーションSRCANDでブリットし
    もう一つのDCをラスタオペレーションSRCINVERTでブリットする。
    */

    BitBlt(to,x,y,width,height,mmono,fromx,fromy,SRCAND);
    BitBlt(to,x,y,width,height,mkuro,fromx,fromy,SRCINVERT);
    
    SelectObject(mmono,oldmono);
    DeleteObject(bmono);
    DeleteDC(mmono);

    SelectObject(mkuro,oldkuro);
    DeleteObject(bkuro);
    DeleteDC(mkuro);
}

この関数で描画元と先のHDC,描画先の座標、大きさ、描画元の座標、透明にしたい色を指定してやれば正しく描画できるはずです。
ただしこの関数では、毎回メモリデバイスコンテキストを作成していている為、速度が遅くなってしまいますので 高速化は各自で行ってください。
ちなみに、私が透明色を指定して描画するときはビットマップをファイルから読み込みメモリ上 にあるビットを操作して実現します。こちらの方法を使うとBitBltは一度しか使わないので多少 は速くなります。


戻る