2012-10-03 79 views
5

この質問は、私のearlier questionと関連しています。AlphablendとTransparentBlt

ソースレイヤの特定の部分にのみアルファを適用して2つのレイヤを結合したいとします。私が試した1つの方法は、SourceConstantAlphaを$ ffに設定することでした(関数にソースレイヤーのアルファチャンネルを使用させる)。

この種の作品 - 遅いですが(私はScanLinesを使ってスピードを上げることができますが)、アルファチャンネルを何に設定するか分かりません。ドキュメントは計算があることを示唆している:

st.Red = Src.Red + (1 - Src.Alpha) * Dst.Red 

私は推測作業により、いくつかの異なる値を試してみましたが、私の最初の質問は:どのように私は、アルファ値を計算していますか?

他のいくつかの質問を読んだ後、私は透明ではなく、マスキング(高速)であるTransparentBlt関数を見つけました。 これらの2つの呼び出しを組み合わせる方法があります)?

unit MainWnd; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, ExtCtrls, ControlsEx; 

type 
{------------------------------------------------------------------------------} 
    TfrmMain = class(TForm) 
    PaintBox1: TPaintBox; 
    procedure PaintBox1Paint(Sender: TObject); 
    private 
    { Private declarations } 
    public 
    { Public declarations } 
    end; 

var 
    frmMain: TfrmMain; 

implementation 

{$R *.dfm} 

{..............................................................................} 
procedure copyToAlpha(const in_bitmap : TBitmap; const in_transparentColor : TColor; 
     const in_transparency : integer); 
var 
    x : integer; 
    y : integer; 
    p : integer; 
begin 
    ASSERT(in_bitmap.PixelFormat = pf32bit); 

    for x := 0 to in_bitmap.Width - 1 do 
    begin 
    for y := 0 to in_bitmap.Height - 1 do 
    begin 
     p := in_bitmap.Canvas.Pixels[x, y]; 
     if TColor(p) <> in_transparentColor then 
     begin 
     in_bitmap.Canvas.Pixels[x, y] := p or (in_transparency shl 24); 
     end 
     else 
     in_bitmap.Canvas.Pixels[x, y] := p or ($ff shl 24); 
    end; 
    end; 
end; 

{..............................................................................} 
procedure alphaBlendTest(
     const in_target : TCanvas; 
     const in_width : integer; 
     const in_height : integer); 
const 
    BARSIZE = 30; 
var 
    bitmap : TBitmap; 
    r  : TRect; 
    blendFn : BLENDFUNCTION; 
    ret  : Boolean; 
begin 
    blendFn.BlendOp    := AC_SRC_OVER; 
    blendFn.SourceConstantAlpha := $ff; 
    blendFn.BlendFlags   := 0; 
    blendFn.alphaFormat   := AC_SRC_ALPHA; 

    bitmap := TBitmap.Create; 
    try 
    bitmap.Width    := in_width; 
    bitmap.Height    := in_height; 
    bitmap.PixelFormat  := pf32bit; 
    bitmap.HandleType   := bmDIB; 
    bitmap.TransparentColor := clFuchsia; 
    bitmap.Transparent  := true; 
    bitmap.Canvas.Brush.Color := clFuchsia; 
    bitmap.Canvas.FillRect(Bounds(0, 0, in_width, in_height)); 
    bitmap.Canvas.Brush.Color := clGreen; 

    r := Bounds(
     in_width div 2 - (in_width div 3) div 2, 
     0, 
     (in_width div 3) + 1, 
     BARSIZE   + 1); 

    bitmap.Canvas.Rectangle(r); 
    // done drawing 

    //copyToAlpha(bitmap, clFuchsia, 1); 
    ret := Windows.TransparentBlt(
     in_target.Handle, 
     0, 
     0, 
     in_width, 
     in_height, 
     bitmap.Canvas.Handle, 
     0, 
     0, 
     in_width, 
     in_height, 
     clFuchsia); 
     //blendFn); 

    ASSERT(ret); 
    finally 
    bitmap.Free; 
    end; 
end; 



{..............................................................................} 
procedure TfrmMain.PaintBox1Paint(Sender: TObject); 
var 
    r: TRect; 
begin 
    PaintBox1.Canvas.Brush.Color := clBlue; 
    r := Bounds(0, 0, PaintBox1.ClientWidth, PaintBox1.ClientHeight); 
    PaintBox1.Canvas.FillRect(r); 
    PaintBox1.Canvas.Brush.Color := clRed; 
    PaintBox1.Canvas.Ellipse(0, 0, PaintBox1.ClientWidth, PaintBox1.ClientHeight); 

    alphaBlendTest(PaintBox1.Canvas, PaintBox1.ClientWidth, PaintBox1.ClientHeight); 
end; 

end. 
+0

y各ピクセルのr、g、bをあなたの望むアルファで置き換え、AlphaBlendのために255で割ります。もちろん、ピクセルのアルファをアルファ値に設定します。私は 'TransparentBlt'に関する質問を理解していませんが、透明性はどうですか? –

+3

@Sertac OPには部分的に透明な色からなるビットマップがあります。透明部分は、宛先キャンバス上にそのまま残り、描画された部分は、宛先キャンバスにアルファベットで表示される。 – NGLN

答えて

8

トリック:任意の比率で同じ色をブレンドすると、同じ色になります。

したがって、最も簡単な方法は、最初に透明な結果を一時ビットマップに描画し、そのビットマップを宛先キャンバス上でアルファベットで表示することです。

procedure TfrmMain.PaintBox1Paint(Sender: TObject); 
const 
    BarSize = 30; 
var 
    R: TRect; 
    Bmp: TBitmap; 
    BlendFunc: TBlendFunction; 
begin 
    with PaintBox1 do 
    begin 
    R := ClientRect; 
    Canvas.Brush.Color := clBlue; 
    Canvas.FillRect(R); 
    Canvas.Brush.Color := clRed; 
    Canvas.Ellipse(R); 
    Bmp := TBitmap.Create; 
    try 
     Bmp.Width := Width; 
     Bmp.Height := Height; 
     BitBlt(Bmp.Canvas.Handle, 0, 0, Width, Height, Canvas.Handle, 0, 0, 
     SRCCOPY); 
     Bmp.Canvas.Brush.Color := clGreen; 
     R := Bounds(Width div 3, 0, Width div 3 + 1, BarSize + 1); 
     Bmp.Canvas.Rectangle(R); 
     BlendFunc.BlendOp := AC_SRC_OVER; 
     BlendFunc.BlendFlags := 0; 
     BlendFunc.SourceConstantAlpha := 80; 
     BlendFunc.AlphaFormat := 0; 
     Windows.AlphaBlend(Canvas.Handle, 0, 0, Width, Height, Bmp.Canvas.Handle, 
     0, 0, Width, Height, BlendFunc); 
    finally 
     Bmp.Free; 
    end; 
    end; 
end; 

と宛先キャンバスへのアクセスなしを描く時に:描画中に先のキャンバスへのアクセス権を持つ

procedure GetRemoteBitmap(Bmp: TBitmap; Width, Height: Integer); 
const 
    BarSize = 30; 
var 
    R: TRect; 
begin 
    Bmp.Canvas.Brush.Color := clFuchsia; 
    Bmp.Width := Width; 
    Bmp.Height := Height; 
    Bmp.TransparentColor := clFuchsia; 
    Bmp.Transparent := True; 
    Bmp.Canvas.Brush.Color := clGreen; 
    R := Bounds(Width div 3, 0, Width div 3 + 1, BarSize + 1); 
    Bmp.Canvas.Rectangle(R); 
end; 

procedure TfrmMain.PaintBox1Paint(Sender: TObject); 
var 
    R: TRect; 
    Bmp: TBitmap; 
    Tmp: TBitmap; 
    BlendFunc: TBlendFunction; 
begin 
    with PaintBox1 do 
    begin 
    R := ClientRect; 
    Canvas.Brush.Color := clBlue; 
    Canvas.FillRect(R); 
    Canvas.Brush.Color := clRed; 
    Canvas.Ellipse(R); 
    Bmp := TBitmap.Create; 
    Tmp := TBitmap.Create; 
    try 
     GetRemoteBitmap(Bmp, Width, Height); 
     Tmp.Width := Width; 
     Tmp.Height := Height; 
     BitBlt(Tmp.Canvas.Handle, 0, 0, Width, Height, Canvas.Handle, 0, 0, 
     SRCCOPY); 
     TransparentBlt(Tmp.Canvas.Handle, 0, 0, Width, Height, Bmp.Canvas.Handle, 
     0, 0, Width, Height, ColorToRGB(clFuchsia)); 
     BlendFunc.BlendOp := AC_SRC_OVER; 
     BlendFunc.BlendFlags := 0; 
     BlendFunc.SourceConstantAlpha := 80; 
     BlendFunc.AlphaFormat := 0; 
     Windows.AlphaBlend(Canvas.Handle, 0, 0, Width, Height, Tmp.Canvas.Handle, 
     0, 0, Width, Height, BlendFunc); 
    finally 
     Tmp.Free; 
     Bmp.Free; 
    end; 
    end; 
end; 
+1

私はあなたが* "目的地のビットマップへのアクセスなし" *を意味するものを得ていませんが、あなたの最初のバージョンが好きです。 :) –

+0

'blt'がピクセルを歩くよりも速いのだろうかと思うが、おそらくそれはおそらくだと思う。 –

+1

@Sertac webservice ... – NGLN

4

をちょうど完全性のために(「私はどのように計算しますアルファ値? "):

procedure alphaBlendTest(
     const in_target : TCanvas; 
     const in_width : integer; 
     const in_height : integer); 
const 
    BARSIZE = 30; 
var 
    bitmap : TBitmap; 
    r  : TRect; 
    blendFn : BLENDFUNCTION; 
    ret  : Boolean; 

    x, y: Integer; 
    px : PRGBQuad; 
begin 
    blendFn.BlendOp    := AC_SRC_OVER; 
    blendFn.SourceConstantAlpha := $ff; 
    blendFn.BlendFlags   := 0; 
    blendFn.alphaFormat   := AC_SRC_ALPHA; 

    bitmap := TBitmap.Create; 
    try 
    bitmap.Width    := in_width; 
    bitmap.Height    := in_height; 
    bitmap.PixelFormat  := pf32bit; 
    bitmap.Canvas.Brush.Color := clGreen; 

    r := Bounds(
     in_width div 2 - (in_width div 3) div 2, 
     0, 
     (in_width div 3) + 1, 
     BARSIZE   + 1); 

    bitmap.Canvas.Rectangle(r); 

    for y := 0 to bitmap.Height - 1 do begin 
     px := bitmap.ScanLine[y]; 
     for x := 0 to Bitmap.Width - 1 do begin 
     if PtInRect(r, Point(x, y)) then begin 
      px.rgbBlue := MulDiv(px.rgbBlue, $A0, $FF); 
      px.rgbGreen := MulDiv(px.rgbGreen, $A0, $FF); 
      px.rgbRed := MulDiv(px.rgbRed, $A0, $FF); 
      px.rgbReserved := $A0; 
     end else 
      px.rgbReserved := $00; // fully transparent 
     Inc(px); 
     end; 
    end; 
    // done drawing 

    ret := Windows.AlphaBlend(
     in_target.Handle, 
     0, 
     0, 
     in_width, 
     in_height, 
     bitmap.Canvas.Handle, 
     0, 
     0, 
     in_width, 
     in_height, 
     blendFn); 

    ASSERT(ret); 
    finally 
    bitmap.Free; 
    end; 
end; 
関連する問題