在椭圆内画一条线

时间:2018-04-16 21:20:15

标签: delphi

我试图在Bitmap上绘制一条带有一条线的椭圆,类似于这张图片:

image

我的应用可以加载位图图片,可以是任何尺寸。我只需要在其中画一条椭圆线。

我知道如何绘制椭圆,但我的问题是它内部的一行:

Bmp.Canvas.Ellipse(0, 0, Bmp.Width, Bmp.Height);
Bmp.Canvas.MoveTo(?, ?);// Here is my problem
Bmp.Canvas.LineTo(?, ?);// here too

我试试这个:

Bmp.Canvas.MoveTo(0, 0);
Bmp.Canvas.LineTo(Bmp.Width, Bmp.Height);

但是这会从图片的左上角到右下角画一条线。

1 个答案:

答案 0 :(得分:5)

像你一样使用Canvas.MoveTo()Canvas.LineTo()会很好。你只需要约束椭圆内部线条的绘制,这样你在椭圆之外绘制的任何东西都不会被看到。

您可以使用Win32 API clipping regionCreateEllipticRgn()函数在绘制线之前将SelectClipRgn()应用于Canvas,例如:

// draw the actual ellipse first...
Bmp.Canvas.Ellipse(0, 0, Bmp.Width, Bmp.Height);

// then create a region to match the ellipse...
Rgn := CreateEllipticRgn(0, 0, Bmp.Width, Bmp.Height);
try
  SelectClipRgn(Bmp.Canvas.Handle, Rgn);
  try
    // then draw the line inside the region...
    Bmp.Canvas.MoveTo(0, 0);
    Bmp.Canvas.LineTo(Bmp.Width, Bmp.Height);
  finally
    SelectClipRgn(Bmp.Canvas.Handle, 0);
  end;
finally
  DeleteObject(Rgn);
end;

或者,您可以使用Win32 API clipping pathBeginPath()EndPath()函数来应用椭圆SelectClipPath(),例如:

// draw the actual ellipse first...
Bmp.Canvas.Ellipse(0, 0, Bmp.Width, Bmp.Height);

// then create a path to match the ellipse...
BeginPath(Bmp.Canvas.Handle);
try
  Bmp.Canvas.Ellipse(0, 0, Bmp.Width, Bmp.Height);
finally
  EndPath(Bmp.Canvas.Handle);
end;
SelectClipPath(Bmp.Canvas.Handle, RGN_COPY);

// then draw the line inside the path...
Bmp.Canvas.MoveTo(0, 0);
Bmp.Canvas.LineTo(Bmp.Width, Bmp.Height);

有关详细信息,请参阅MSDN上的Clipping Overview

例如:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls;

type
  TForm1 = class(TForm)
    Image1: TImage;
    Image2: TImage;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  Bmp: TBitmap;
  Rgn: HRGN;
begin
  Bmp := TBitmap.Create;
  try
    Bmp.SetSize(Image1.Width, Image1.Height);

    Bmp.Canvas.Brush.Color := clWhite;
    Bmp.Canvas.FillRect(Rect(0, 0, Bmp.Width, Bmp.Height));

    Bmp.Canvas.Pen.Color := clRed;
    Bmp.Canvas.Pen.Width := 5;

    // draw the actual ellipse first...
    Bmp.Canvas.Ellipse(0, 0, Bmp.Width, Bmp.Height);

    // then create a region to match the ellipse...
    Rgn := CreateEllipticRgn(0, 0, Bmp.Width, Bmp.Height);
    try
      SelectClipRgn(Bmp.Canvas.Handle, Rgn);
      try
        // then draw the line inside the region...
        Bmp.Canvas.MoveTo(0, 0);
        Bmp.Canvas.LineTo(Bmp.Width, Bmp.Height);
      finally
        SelectClipRgn(Bmp.Canvas.Handle, 0);
      end;
    finally
      DeleteObject(Rgn);
    end;

    Image1.Picture.Assign(Bmp);
  finally
    Bmp.Free;
  end;

  Bmp := TBitmap.Create;
  try
    Bmp.SetSize(Image2.Width, Image2.Height);

    Bmp.Canvas.Brush.Color := clWhite;
    Bmp.Canvas.FillRect(Rect(0, 0, Bmp.Width, Bmp.Height));

    Bmp.Canvas.Pen.Color := clRed;
    Bmp.Canvas.Pen.Width := 5;

    // draw the actual ellipse first...
    Bmp.Canvas.Ellipse(0, 0, Bmp.Width, Bmp.Height);

    // then create a path to match the ellipse...
    BeginPath(Bmp.Canvas.Handle);
    try
      Bmp.Canvas.Ellipse(0, 0, Bmp.Width, Bmp.Height);
    finally
      EndPath(Bmp.Canvas.Handle);
    end;
    SelectClipPath(Bmp.Canvas.Handle, RGN_COPY);

    // then draw the line inside the path...
    Bmp.Canvas.MoveTo(0, 0);
    Bmp.Canvas.LineTo(Bmp.Width, Bmp.Height);

    Image2.Picture.Assign(Bmp);
  finally
    Bmp.Free;
  end;
end;

end.

image