質問

この質問は、My href="https://stackoverflow.com/q/12700165/62576">以前の質問

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

この種の作品 - 遅いですが(私は走査線を使うことによって速めることができると思います)、部分の種類は、アルファチャンネルを設定するものを見つけることができないということです。マニュアルは計算が次のとおりです。

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

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

他のいくつかの質問を読んだ後、私は透明なBlt関数を越えて、マスキングをよく(そして速い)透明性ではありませんが、組み合わせる方法はありますか これら2つの呼び出しが一緒に呼びかけます(たぶん3層目を使用)?

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.
.

役に立ちましたか?

解決

トリック:同じ色を同じ色にすると同じ色をブレンドする。

だから、最も簡単な方法(そして最も効率的な)は、最初に透明な結果を一時的なビットマップに描画し、そのビットマップを目的のキャンバスにAlphableend。

描画中に宛先キャンバスにアクセスして:

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;
.

他のヒント

完全性のためだけに( "Alpha値を計算する方法?" ):

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;
.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top