如何在具有透明度和不透明度的画布上绘画?

11 delphi delphi-xe

概观

从GR32库中,我使用TImgView32渲染网格,这将是我的透明背景,如下所示:

在此输入图像描述

放在TImgView32内部我有一个常规的TImage,我将在画布上绘制,如下所示:

在此输入图像描述

任务

我想要实现的是能够设置画笔的不透明度,从而为我的程序中的图像编辑提供了更多的可能性.而不是绘制一个平面颜色,设置画笔的不透明度允许不同级别的颜色深度等.

我在搜索时更早地发现了这个问题:在Delphi 2010中绘制不透明椭圆 - Andreas Rejbrand在他的答案中提供了一些例子.

我已经看过安德烈亚斯做了什么,并提出了我自己的简化尝试,但我遇到了问题.看看下面这两个图像,第一个是透明背景,第二个是黑色背景,以显示问题更清晰:

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

正如你所看到的,在画笔(圆圈)周围是一个非常讨厌的广场我无法摆脱.所有应该可见的是刷子.这是我用来产生这些结果的代码:

procedure DrawOpacityBrush(ACanvasBitmap: TBitmap; X, Y: Integer;
  AColor: TColor; ASize: Integer; Opacity: Integer);
var
  Bmp: TBitmap;
begin
  Bmp := TBitmap.Create;
  try
    Bmp.SetSize(ASize, ASize);
    Bmp.Transparent := False;

    with Bmp.Canvas do
    begin
      Pen.Color := AColor;
      Pen.Style := psSolid;
      Pen.Width := ASize;
      MoveTo(ASize div 2, ASize div 2);
      LineTo(ASize div 2, ASize div 2);
    end;

    ACanvasBitmap.Canvas.Draw(X, Y, Bmp, Opacity);
  finally
    Bmp.Free;
  end;
end;

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  DrawOpacityBrush(Image1.Picture.Bitmap, X, Y, clRed, 50, 85);
end;
Run Code Online (Sandbox Code Playgroud)

它在常规位图上产生这个:

在此输入图像描述

我的想法(基于Andreas创建具有不透明度的椭圆的方法)是在画布上渲染一个典型的画笔,将其分配给屏幕外的位图,然后将其重绘到具有不透明度的主位图上.哪个有效,除了边缘周围的烦人方块.

如何在屏幕截图中显示不透明度的画笔,但是在画笔周围没有那个方块?

如果我设置Bmp.Transparent := True仍然有一个白色的盒子,但不再有不透明度.只是一个坚实的白色方块和坚实的红色圆圈.

Rem*_*eau 15

不透明度功能TCanvas.Draw()不支持您尝试执行的操作,至少不支持您尝试使用它的方式.要实现所需的效果,您需要创建一个32位,TBitmap以便拥有每像素的Alpha通道,然后为每个像素填充alpha,为不需要的像素将alpha设置为0,并设置alpha到所需像素的所需不透明度.然后,在调用时TCanvas.Draw(),将其不透明度设置为255,以告诉它仅使用每像素不透明度.

procedure DrawOpacityBrush(ACanvas: TCanvas; X, Y: Integer; AColor: TColor; ASize: Integer; Opacity: Byte);
var
  Bmp: TBitmap;
  I, J: Integer;
  Pixels: PRGBQuad;
  ColorRgb: Integer;
  ColorR, ColorG, ColorB: Byte;
begin
  Bmp := TBitmap.Create;
  try
    Bmp.PixelFormat := pf32Bit; // needed for an alpha channel
    Bmp.SetSize(ASize, ASize);

    with Bmp.Canvas do
    begin
      Brush.Color := clFuchsia; // background color to mask out
      ColorRgb := ColorToRGB(Brush.Color);
      FillRect(Rect(0, 0, ASize, ASize));
      Pen.Color := AColor;
      Pen.Style := psSolid;
      Pen.Width := ASize;
      MoveTo(ASize div 2, ASize div 2);
      LineTo(ASize div 2, ASize div 2);
    end;

    ColorR := GetRValue(ColorRgb);
    ColorG := GetGValue(ColorRgb);
    ColorB := GetBValue(ColorRgb);

    for I := 0 to Bmp.Height-1 do
    begin
      Pixels := PRGBQuad(Bmp.ScanLine[I]);
      for J := 0 to Bmp.Width-1 do
      begin
        with Pixels^ do
        begin
          if (rgbRed = ColorR) and (rgbGreen = ColorG) and (rgbBlue = ColorB) then
            rgbReserved := 0
          else
            rgbReserved := Opacity; 
          // must pre-multiply the pixel with its alpha channel before drawing
          rgbRed := (rgbRed * rgbReserved) div $FF;
          rgbGreen := (rgbGreen * rgbReserved) div $FF;
          rgbBlue := (rgbBlue * rgbReserved) div $FF;
        end;
        Inc(Pixels);
      end;
    end;

    ACanvas.Draw(X, Y, Bmp, 255);
  finally
    Bmp.Free;
  end;
end;

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;  
  Shift: TShiftState; X, Y: Integer);  
begin  
  DrawOpacityBrush(Image1.Picture.Bitmap.Canvas, X, Y, clRed, 50, 85);  
end;  
Run Code Online (Sandbox Code Playgroud)

  • 您可能还会发现该类很有用:http://code.google.com/p/transparent-canvas/。它是围绕32位,按像素的Alpha绘图的包装,其接口与TCanvas非常相似。创建一个,绘制到它,然后绘制到画布上,完成。MPL许可,因此您可以在任何地方使用它。 (2认同)