Canvas.TransparentColor和Canvas.Draw与不透明度的组合

lin*_*luk 4 delphi canvas bitmap alpha-transparency delphi-xe5

我想在不透明的画布上绘制位图,其中位图具有透明色.

  • 我可以创建一个透明色的位图,并将其绘制成一个
  • canvas我可以创建一个位图并将其绘制到具有不透明度的画布上

但我无法结合它.如果我合并它,则忽略不透明度.

这是我写的代码:

procedure TForm1.FormPaint(Sender: TObject);
var b1,b2:TBitmap;
begin
  // Example how it opacity works:
  b1 := TBitmap.Create;
  b1.SetSize(20,20);
  b1.Canvas.Brush.Color := clBlue;
  b1.Canvas.Rectangle(0,0,20,20);
  Canvas.Draw(10,10,b1,$ff);  // Works
  Canvas.Draw(40,10,b1,$66);  // Works

  // I need it in combination with TransparentColor:
  b2 := TBitmap.Create;
  // next 3 lines are different from above
  b2.Transparent := true;
  b2.TransparentColor := clFuchsia;
  b2.Canvas.Brush.Color := clFuchsia;
  b2.SetSize(20,20);
  b2.Canvas.Brush.Color := clBlue;
  b2.Canvas.Ellipse(0,0,20,20);
  Canvas.Draw(10,40,b2,$ff);  // Works (full opacity)
  Canvas.Draw(40,40,b2,$66);  // Ignores the $66 Opacity

  b1.Free;
  b2.Free;
end;
Run Code Online (Sandbox Code Playgroud)

生产:
在此输入图像描述

我怎么能用透明背景绘制(一个蓝色的圆圈),只有40%的不透明度?

如果可能的话,我会优先选择没有直接winapi的解决方案(如bitblt,...).

我尝试了几个hacks,比如将alpha通道转换为TColor值,但它不起作用.

在这里我尝试了什么:

procedure TForm1.FormPaint(Sender: TObject);
var b:TBitmap;
begin
  b := TBitmap.Create;
  b.PixelFormat := pf32bit;
  b.AlphaFormat := afDefined;

  b.Canvas.Brush.Color := 0 and ($ff shl 32);  // Background Transperency
  b.SetSize(20,20);
  b.Canvas.Brush.Color := clBlue + (($ff-$66) shl 32);
  b.Canvas.Ellipse(0,0,20,20);
  Canvas.Draw(10,10,b);

  b.Free;
end;
Run Code Online (Sandbox Code Playgroud)

生产:
在此输入图像描述

提前致谢!

编辑:我的系统:windows 7 64bit上的delphi xe 5(但使用32位编译器)

bum*_*mmi 5

可以procedure TBitmap.DrawTransparent在单位图形中看到发生的情况.
如果图像的属性设置为透明,如示例中的b2所示,将Graphics.TransparentStretchBlt使用StretchBlt不同的蒙版绘制位图 以绘制图像,并且无法使用Alpha通道.不透明的位图,你的b1,将使用AlphaBlend绘制 .

要达到目标,您可以使用另一个位图b2,将Alphachannel设置为0,在b3上使用不透明度$ 66绘制b2,将每个像素的Alphachannel设置为255,这是b2中的clFuchsia,然后使用所需的不透明度绘制此位图

在此输入图像描述在此输入图像描述

type
  pRGBQuadArray = ^TRGBQuadArray;
  TRGBQuadArray = ARRAY [0 .. 0] OF TRGBQuad;
  TRefChanel=(rcBlue,rcRed,rcGreen);

procedure SetBitmapAlpha(ABitmap: TBitMap; Alpha: Byte);
var
  pscanLine32: pRGBQuadArray;
  nScanLineCount, nPixelCount : Integer;
begin
  with ABitmap do
  begin
    PixelFormat := pf32Bit;
    HandleType := bmDIB;
    ignorepalette := true;
    alphaformat := afDefined;
    for nScanLineCount := 0 to Height - 1 do
    begin
      pscanLine32 := Scanline[nScanLineCount];
      for nPixelCount := 0 to Width - 1 do
        with pscanLine32[nPixelCount] do
         begin
          rgbReserved := Alpha;
        end;
    end;
  end;
end;

procedure AdaptBitmapAlpha(ABitmap,TranspBitmap:TBitmap);
var
  pscanLine32,pscanLine32_2: pRGBQuadArray;
  nScanLineCount, nPixelCount : Integer;
begin
  with ABitmap do
  begin
    PixelFormat := pf32Bit;
    HandleType := bmDIB;
    ignorepalette := true;
    alphaformat := afDefined;
    for nScanLineCount := 0 to Height - 1 do
    begin
      pscanLine32 := Scanline[nScanLineCount];
      pscanLine32_2 := TranspBitmap.Scanline[nScanLineCount];
      for nPixelCount := 0 to Width - 1 do
        with pscanLine32[nPixelCount] do
         begin
          // all picels with are not clFuchsia in the transparent bitmap
          if NOT ((pscanLine32_2[nPixelCount].rgbBlue=255) AND (pscanLine32_2[nPixelCount].rgbRed=255) AND (pscanLine32_2[nPixelCount].rgbGreen=0)  ) then
             begin
             rgbReserved := 255;
             end
          else
             begin
               rgbBlue := 0;
               rgbRed := 0;
               rgbGreen := 0;
             end;
        end;
    end;
  end;
end;



procedure TAForm.FormPaint(Sender: TObject);

var b1,b2,b3:TBitmap;
BF: TBlendFunction;
begin
  // Example how it opacity works:
  b1 := TBitmap.Create;
  b1.SetSize(20,20);
  b1.Canvas.Brush.Color := clBlue;
  b1.Canvas.Rectangle(0,0,20,20);
  Canvas.Draw(10,10,b1,$ff);  // Works
  Canvas.Draw(40,10,b1,$66);  // Works

  // I need it in combination with TransparentColor:
  b3 := TBitmap.Create;
  b3.PixelFormat := pf32Bit;

  b2 := TBitmap.Create;
  b2.PixelFormat := pf32Bit;
  // next 3 lines are different from above
  b2.Transparent := true;
  b2.TransparentColor := clFuchsia;
  b2.Canvas.Brush.Color := clFuchsia;
  b2.SetSize(20,20);
  b2.Canvas.Brush.Color := clBlue;
  b2.Canvas.Ellipse(0,0,20,20);

  Canvas.Draw(10,40,b2,$ff);  // Works (full opacity)

  b3.SetSize(20,20);
  SetBitmapAlpha(b3,0);
  b3.Canvas.Draw(0,0,b2,$66);
  AdaptBitmapAlpha(b3,b2);
  Canvas.Draw(40,40,b3,$66);

  b1.Free;
  b2.Free;
  b3.Free;
end;
Run Code Online (Sandbox Code Playgroud)