我正在绘制一个具有不透明度(Alpha透明度)能力的画布,如下所示:
var
Form1: TForm1;
IsDrawing: Boolean;
implementation
{$R *.dfm}
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.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
case Button of
mbLeft:
begin
IsDrawing := True;
DrawOpacityBrush(Form1.Canvas, X, Y, clRed, 50, 85);
end;
end;
end;
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
if (GetAsyncKeyState(VK_LBUTTON) <> 0) and
(IsDrawing) then
begin
DrawOpacityBrush(Form1.Canvas, X, Y, clRed, 50, 85);
end;
end;
procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
IsDrawing := False;
end;
Run Code Online (Sandbox Code Playgroud)
抽奖DrawOpacityBrush()程序是Remy Lebeau对我最近提出的上一个问题的更新:如何在具有透明度和不透明度的画布上绘画?
虽然这有效,但结果并不令我满意.
目前,每次DrawOpacityBrush()在MouseMove中调用该过程时,它都会继续绘制画笔椭圆形状.这很糟糕,因为根据你在画布上移动鼠标的速度有多快,输出效果并不理想.
这些示例图像应该更好地说明这一点:

-第一个红色画笔我将鼠标从画布底部快速移动到顶部.
-我移动的第二个红色刷子慢得多.
正如您所看到的那样,正确绘制了不透明度,但圆圈也会重复绘制.
我希望它做的是:
(1)在椭圆周围涂上不透明线.
(2)可以选择防止绘制任何椭圆.
这个模拟样本图像应该让我知道如何绘制它:

3条紫色画笔线显示选项(1).
为了实现选项(2),画笔线内的圆圈不应该在那里.
这应该允许您在绘制时花费时间,而不是疯狂地在画布上移动鼠标,以期获得所需的结果.只有当你决定回到刚刚制作的画笔笔划时,该区域的不透明度才会变暗等.
如何实现这些类型的绘图效果?
我希望能够绘制一个TImage,因为这正是我目前正在做的事情,因此将TCanvas作为函数或过程中的参数传递将是理想的.我还将使用MouseDown,MouseMove和MouseUp事件进行绘图.
这是我使用NGLN提供的方法获得的输出:

不透明度似乎也应用于图像,它应该只是多边形线.
那么为什么不画一条折线?
unit Unit1;
interface
uses
Windows, Classes, Graphics, Controls, Forms, ExtCtrls;
type
TPolyLine = record
Count: Integer;
Points: array of TPoint;
end;
TPolyLines = array of TPolyLine;
TForm1 = class(TForm)
PaintBox: TPaintBox;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormResize(Sender: TObject);
procedure PaintBoxMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure PaintBoxMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure PaintBoxPaint(Sender: TObject);
private
FBlendFunc: BLENDFUNCTION;
FBmp: TBitmap;
FPolyLineCount: Integer;
FPolyLines: TPolyLines;
procedure AddPoint(APoint: TPoint);
function LastPoint: TPoint;
procedure NewPolyLine;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.AddPoint(APoint: TPoint);
begin
with FPolyLines[FPolyLineCount - 1] do
begin
if Length(Points) = Count then
SetLength(Points, Count + 64);
Points[Count] := APoint;
Inc(Count);
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FBmp := TBitmap.Create;
FBmp.Canvas.Brush.Color := clWhite;
FBmp.Canvas.Pen.Width := 30;
FBmp.Canvas.Pen.Color := clRed;
FBlendFunc.BlendOp := AC_SRC_OVER;
FBlendFunc.SourceConstantAlpha := 80;
DoubleBuffered := True;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FBmp.Free;
end;
procedure TForm1.FormResize(Sender: TObject);
begin
FBmp.Width := PaintBox.Width;
FBmp.Height := PaintBox.Height;
end;
function TForm1.LastPoint: TPoint;
begin
with FPolyLines[FPolyLineCount - 1] do
Result := Points[Count - 1];
end;
procedure TForm1.NewPolyLine;
begin
Inc(FPolyLineCount);
SetLength(FPolyLines, FPolyLineCount);
FPolyLines[FPolyLineCount - 1].Count := 0;
end;
procedure TForm1.PaintBoxMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if ssLeft in Shift then
begin
NewPolyLine;
AddPoint(Point(X, Y));
PaintBox.Invalidate;
end;
end;
procedure TForm1.PaintBoxMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
if ssLeft in Shift then
if Sqr(LastPoint.X - X) + Sqr(LastPoint.Y - Y) > 30 then
begin
AddPoint(Point(X, Y));
PaintBox.Invalidate;
end;
end;
procedure TForm1.PaintBoxPaint(Sender: TObject);
var
R: TRect;
I: Integer;
begin
R := PaintBox.ClientRect;
FBmp.Canvas.FillRect(R);
for I := 0 to FPolyLineCount - 1 do
with FPolyLines[I] do
FBmp.Canvas.Polyline(Copy(Points, 0, Count));
Windows.AlphaBlend(PaintBox.Canvas.Handle, 0, 0, R.Right, R.Bottom,
FBmp.Canvas.Handle, 0, 0, R.Right, R.Bottom, FBlendFunc);
end;
end.
Run Code Online (Sandbox Code Playgroud)

第二张图片显示了如何将它与背景相结合,并通过以下对代码的少量添加获得,而是FGraphic运行时加载的图片:
procedure TForm1.PaintBoxPaint(Sender: TObject);
var
R: TRect;
I: Integer;
begin
R := PaintBox.ClientRect;
FBmp.Canvas.FillRect(R);
for I := 0 to FPolyLineCount - 1 do
with FPolyLines[I] do
FBmp.Canvas.Polyline(Copy(Points, 0, Count));
PaintBox.Canvas.StretchDraw(R, FGraphic);
Windows.AlphaBlend(PaintBox.Canvas.Handle, 0, 0, R.Right, R.Bottom,
FBmp.Canvas.Handle, 0, 0, R.Right, R.Bottom, FBlendFunc);
end;
Run Code Online (Sandbox Code Playgroud)
或者,要结合已绘制的工作(如您的Image),将其画布复制到PaintBox:
procedure TForm1.PaintBoxPaint(Sender: TObject);
var
R: TRect;
I: Integer;
begin
R := PaintBox.ClientRect;
FBmp.Canvas.FillRect(R);
FBmp.Canvas.Polyline(Copy(FPoly, 0, FCount));
for I := 0 to FPolyLineCount - 1 do
with FPolyLines[I] do
FBmp.Canvas.Polyline(Copy(Points, 0, Count));
Windows.AlphaBlend(PaintBox.Canvas.Handle, 0, 0, R.Right, R.Bottom,
FBmp.Canvas.Handle, 0, 0, R.Right, R.Bottom, FBlendFunc);
end;
Run Code Online (Sandbox Code Playgroud)
但是大卫在评论中提到,我也强烈建议把所有内容都画上来PaintBox:这就是它的用途.
| 归档时间: |
|
| 查看次数: |
4007 次 |
| 最近记录: |