在Delphi 2010中绘制透明度椭圆

6
我想在CodeGear Delphi 2010中绘制一个透明度椭圆。我已经尝试过向另一个位图绘制,设置了位图的透明颜色(作为背景),并调用了椭圆方法。然后在我的图像中,我使用带有透明度参数的重载方法绘制了位图。但它没有起作用。我想要类似于这个 http://www.java2s.com/Tutorial/VBImages/WPF-UseOpacityMaskAndRadialGradientBrush.PNG 的效果。有人知道有效的方法吗?
1个回答

18

对我来说有效:

procedure TForm1.Button1Click(Sender: TObject);
var
  bm1, bm2: TBitmap;
begin
  bm1 := TBitmap.Create;
  bm1.LoadFromFile('C:\Users\Andreas Rejbrand\Pictures\portrait.bmp');

  bm2 := TBitmap.Create;
  bm2.SetSize(bm1.Width, bm1.Height);
  bm2.Canvas.Brush.Color := clRed;
  bm2.Canvas.Pen.Style := psClear;
  bm2.Canvas.Ellipse(0, 0, bm2.Width, bm2.Height);

  Canvas.Draw(100, 100, bm1);
  Canvas.Draw(100, 100, bm2, 127);
end;

示例1

如果您想要更多的控制权,您总可以手动处理:

procedure TForm1.Button1Click(Sender: TObject);
type
  TRGB32Array = packed array[0..MaxInt div SizeOf(TRGBQuad)-1] of TRGBQuad;
  PRGB32Array = ^TRGB32Array;
  TScanline = TRGB32Array;
  PScanline = ^TScanline;
var
  bm1, bm2, bm3: TBitmap;
  sc1, sc2, sc3: PScanline;
  i: Integer;
  j: Integer;
var
  transp: real;
const
  opacity = 0.29;
begin
  transp := 1 - opacity;

  bm1 := TBitmap.Create;
  bm1.LoadFromFile('C:\Users\Andreas Rejbrand\Pictures\portrait.bmp');

  bm2 := TBitmap.Create;
  bm2.SetSize(bm1.Width, bm1.Height);
  bm2.Canvas.Brush.Color := clRed;
  bm2.Canvas.Pen.Style := psClear;
  bm2.Canvas.Ellipse(0, 0, bm2.Width, bm2.Height);

  bm3 := TBitmap.Create;
  bm3.SetSize(bm1.Width, bm1.Height);

  bm1.PixelFormat := pf32bit;
  bm2.PixelFormat := pf32bit;
  bm3.PixelFormat := pf32bit;

  for i := 0 to bm1.Height - 1 do
  begin
    sc1 := bm1.ScanLine[i];
    sc2 := bm2.ScanLine[i];
    sc3 := bm3.ScanLine[i];
    for j := 0 to bm1.Width - 1 do
      with sc3^[j] do
      begin
        rgbBlue := round(transp*sc1^[j].rgbBlue + opacity*sc2^[j].rgbBlue);
        rgbGreen := round(transp*sc1^[j].rgbGreen + opacity*sc2^[j].rgbGreen);
        rgbRed := round(transp*sc1^[j].rgbRed + opacity*sc2^[j].rgbRed);
      end;
  end;

  Canvas.Draw(100, 100, bm3);

end;

示例2

例如,您可以让背景图像在椭圆形外部以100%的不透明度显示:

  ...
  for i := 0 to bm1.Height - 1 do
  begin
    sc1 := bm1.ScanLine[i];
    sc2 := bm2.ScanLine[i];
    sc3 := bm3.ScanLine[i];
    for j := 0 to bm1.Width - 1 do
      if sc2^[j].rgbBlue + sc2^[j].rgbGreen + sc2^[j].rgbRed = 3*255 then
        sc3^[j] := sc1^[j]
      else
        with sc3^[j] do
        begin
          rgbBlue := round(transp*sc1^[j].rgbBlue + opacity*sc2^[j].rgbBlue);
          rgbGreen := round(transp*sc1^[j].rgbGreen + opacity*sc2^[j].rgbGreen);
          rgbRed := round(transp*sc1^[j].rgbRed + opacity*sc2^[j].rgbRed);
        end;
  end;
  ...

示例3

更不用提利用像素图操作完成的其他有趣事情了:

  ...
  for i := 0 to bm1.Height - 1 do
  begin
    sc1 := bm1.ScanLine[i];
    sc2 := bm2.ScanLine[i];
    sc3 := bm3.ScanLine[i];
    for j := 0 to bm1.Width - 1 do
      if sc2^[j].rgbBlue + sc2^[j].rgbGreen + sc2^[j].rgbRed = 3*255 then
        sc3^[j] := sc1^[j]
      else
        with sc3^[j] do
        begin
          rgbBlue := round(sin(transp*sc1^[j].rgbBlue + opacity*sc2^[j].rgbBlue));
          rgbGreen := round(transp*sc1^[j].rgbGreen + opacity*sc2^[j].rgbGreen);
          rgbRed := round(transp*sc1^[j].rgbRed + opacity*sc2^[j].rgbRed);
        end;
  end;
  ...

示例4

如果你真的不想手动操作,我发现你可以在第一个位图的副本上绘制椭圆,然后混合这两个位图:

procedure TForm1.Button1Click(Sender: TObject);
var
  bm1, bm2: TBitmap;
begin

  bm1 := TBitmap.Create;
  bm1.LoadFromFile('C:\Users\Andreas Rejbrand\Pictures\portrait.bmp');

  bm2 := TBitmap.Create;
  bm2.LoadFromFile('C:\Users\Andreas Rejbrand\Pictures\portrait.bmp');
  bm2.Canvas.Brush.Color := clRed;
  bm2.Canvas.Pen.Style := psClear;
  bm2.Canvas.Ellipse(0, 0, bm2.Width, bm2.Height);

  Canvas.Draw(100, 100, bm1);
  Canvas.Draw(100, 100, bm2, 127);
end;

示例 5


感谢您提供的完整解决方案。再次感谢! - user558126
非常全面的示例!不过别忘了使用try..finally释放位图对象,但我打赌你已经知道了 ;) - user1175743

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接