透過転送

CGを転送するのは四角とは限りません。いろんな形で転送する必要が出てくる時があります。
これまでは、CG本体と一緒にマスク用の画像も組み込んでおいて、 SrcAnd転送とSrcPaint転送をかけていました。 VBページに載ってます。

でもマスク用の画像を持っていると、その分ファイルサイズが大きくなります。 それで画像無しでも透過転送が出来るようにする事にしました。

マスクを生成する

マスクを自己生成してみます。 マスクを作るMaskBltMask。それとこれを使って一回で透過転送出来るMaskBltExを作りました。

以下、マスク生成するMaskBltMaskのコードです。
CG中、黒(0, 0, 0)を透明色として、マスクを作ります。
procedure MaskBltMask(iCG1:HDC; X1,Y1,W1,H1:Integer; iCG2:HDC; X2,Y2:Integer);
var
  iBackColor1, iBackColor2: TColor;
  iMaskDC: HDC;
  iMaskBitmap: LongInt;
  
begin
  iBackColor1 := SetBkColor(iCG1, clWhite);
  iMaskDC := CreateCompatibleDC(iCG1);
  iMaskBitmap := CreateBitmap(W1, H1, 1, 1, nil);

  try
    SelectObject(iMaskDC, iMaskBitmap);
    iBackColor2 := SetBkColor(iCG2, clBlack);
    BitBlt(iMaskDC, 0, 0, W1, H1, iCG2, X2, Y2, SrcCopy);
    SetBkColor(iCG2, iBackColor2);
    BitBlt(iCG1, X1, Y1, W1, H1, iMaskDC, 0, 0, SrcCopy);
    SetBkColor(iCG1, iBackColor1);

  finally
    SelectObject(iMaskDC, iMaskBitmap);
    DeleteDC(iMaskDC);
    DeleteObject(iMaskBitmap);
  end;
end;
例えばBitmap"Puti" のマスクをBitmap"Mask" に作る場合こうです。BitBltと書式はほぼ同じです。 これでMaskを作って透過転送に使えば良い訳です。

MaskBltMask(Mask.Canvas.Handle, 0, 0, 40, 40, Puti.Canvas.Handle, 0, 0);

マスクが出来たら、SrcAndとSrcPaintで透過転送出来ます。
例えばこんな感じです。 Form1が転送先。 Putiが転送したいCG。 Maskがマスクです。

BitBlt(Form1.Canvas.Handle, 0, 0, 40, 40, Mask.Canvas.Handle, 0, 0, SrcAnd);
BitBlt(Form1.Canvas.Handle, 0, 0, 40, 40, Puti.Canvas.Handle, 0, 0, SrcPaint);

MaskBltEx

上でマスク使って、SrcAndしてSrcPaintしてと色々やって透過転送をおこなっていますが、 これを1命令で終わらせるようにしたものです。内部でMaskBltMaskを呼び出します。
procedure MaskBltEx(iCG1:HDC; X1,Y1,W1,H1:Integer; iCG2:HDC; X2,Y2:Integer);
var
  iBitmap:TBitmap;
begin
  iBitmap := TBitmap.Create;
  try
    iBitmap.Width := W1; iBitmap.Height := H1;
    MaskBltMask(iBitmap.Canvas.Handle, 0, 0, W1, H1, iCG2, X2, Y2);
    BitBlt(iCG1, X1, Y1, W1, H1, iBitmap.Canvas.Handle, 0, 0, SrcAnd);
    BitBlt(iCG1, X1, Y1, W1, H1, iCG2, X2, Y2, SrcPaint);
  finally
    iBitmap.Free; 
  end;
end;
これでプチキャラの例が1命令で終わります。
MaskBltEx(Form1.Canvas.Handle, 0, 0, 40, 40, Puti.Canvas.Handle, 0, 0);