我需要一个非常简单的函数来绘制一堆具有抗锯齿功能的行。它必须遵循Delphi范式:自包含和SYSTEM INDEPENDENT(没有DLL地狱),快速,简单。 有谁知道这样的图书馆?
到现在为止我已经尝试过:
WuLine
swissdelphicenter.ch/torry/showcode.php?id=1812
我不认为这个代码的作者曾经运行它。画一条线需要一秒钟!这显然只是出于教育目的:)
来自TMetaFile的抗锯齿图纸
链接:blog.synopse.info/post/2010/04/02/Antialiased-drawing-from-TMetaFile
还没有真正试过这个(我可能很快就会这样做)。它仅适用于TMetaFiles。它只加载EMF文件并使用抗锯齿功能绘制它。此外,该网站上的许多代码只是示范/教育。
Image32
非常好的图书馆 - 迄今为止最完整。我可能会用它,但它对于我需要的东西来说太过分了
缺点:
- 添加到应用程序的足迹非常大
- 真的很难用
- 即使是简单的任务,你也需要深入了解其模糊的文档。
- 提供的演示代码太复杂了
- 越野车!
- 没有最近的更新(以修复错误)
抗粮几何图书馆
该库需要一个体面的安装程序。该库的编写者是Linux / Mac用户。 Windows实现看起来很奇怪。我不能对图书馆本身说些什么。
Xiaolin Wu的基础功能(作者:Andreas Rejbrand)
请看下面的几个帖子。 Andreas Rejbrand提供了一个非常紧凑的解决方案。迄今为止的最佳解决方
看起来我必须解释为什么我不喜欢大型第三方库和VCL:
答案 0 :(得分:35)
在Delphi中实现Xiaolin Wu的抗锯齿线渲染算法并不是很难。当我编写以下过程时,我使用the Wikipedia article作为参考(实际上,我只是将伪代码翻译成Delphi并更正了错误,并添加了对彩色背景的支持):
procedure DrawAntialisedLine(Canvas: TCanvas; const AX1, AY1, AX2, AY2: real; const LineColor: TColor);
var
swapped: boolean;
procedure plot(const x, y, c: real);
var
resclr: TColor;
begin
if swapped then
resclr := Canvas.Pixels[round(y), round(x)]
else
resclr := Canvas.Pixels[round(x), round(y)];
resclr := RGB(round(GetRValue(resclr) * (1-c) + GetRValue(LineColor) * c),
round(GetGValue(resclr) * (1-c) + GetGValue(LineColor) * c),
round(GetBValue(resclr) * (1-c) + GetBValue(LineColor) * c));
if swapped then
Canvas.Pixels[round(y), round(x)] := resclr
else
Canvas.Pixels[round(x), round(y)] := resclr;
end;
function rfrac(const x: real): real; inline;
begin
rfrac := 1 - frac(x);
end;
procedure swap(var a, b: real);
var
tmp: real;
begin
tmp := a;
a := b;
b := tmp;
end;
var
x1, x2, y1, y2, dx, dy, gradient, xend, yend, xgap, xpxl1, ypxl1,
xpxl2, ypxl2, intery: real;
x: integer;
begin
x1 := AX1;
x2 := AX2;
y1 := AY1;
y2 := AY2;
dx := x2 - x1;
dy := y2 - y1;
swapped := abs(dx) < abs(dy);
if swapped then
begin
swap(x1, y1);
swap(x2, y2);
swap(dx, dy);
end;
if x2 < x1 then
begin
swap(x1, x2);
swap(y1, y2);
end;
gradient := dy / dx;
xend := round(x1);
yend := y1 + gradient * (xend - x1);
xgap := rfrac(x1 + 0.5);
xpxl1 := xend;
ypxl1 := floor(yend);
plot(xpxl1, ypxl1, rfrac(yend) * xgap);
plot(xpxl1, ypxl1 + 1, frac(yend) * xgap);
intery := yend + gradient;
xend := round(x2);
yend := y2 + gradient * (xend - x2);
xgap := frac(x2 + 0.5);
xpxl2 := xend;
ypxl2 := floor(yend);
plot(xpxl2, ypxl2, rfrac(yend) * xgap);
plot(xpxl2, ypxl2 + 1, frac(yend) * xgap);
for x := round(xpxl1) + 1 to round(xpxl2) - 1 do
begin
plot(x, floor(intery), rfrac(intery));
plot(x, floor(intery) + 1, frac(intery));
intery := intery + gradient;
end;
end;
要使用此功能,只需提供要绘制的画布(以类似于需要设备上下文(DC)的Windows GDI函数的方式),并指定行上的初始点和最终点。请注意,上面的代码绘制了黑色行,并且背景必须为白色。将其概括为任何情况并不困难,甚至不是透明的透明图纸。只需调整plot
功能,其中c \in [0, 1]
是(x, y)
处像素的不透明度。
使用示例:
创建一个新的VCL项目并添加
procedure TForm1.FormCreate(Sender: TObject);
begin
Canvas.Brush.Style := bsSolid;
Canvas.Brush.Color := clWhite;
end;
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
Canvas.FillRect(ClientRect);
DrawAntialisedLine(Canvas, Width div 2, Height div 2, X, Y, clBlack);
end;
如果您需要2D或3D的高性能和高质量渲染,并且您自己完成所有绘图,那么OpenGL通常是最佳选择。在Delphi中编写OpenGL应用程序非常容易。有关我在十分钟内完成的示例,请参阅http://privat.rejbrand.se/smooth.exe。使用鼠标右键在填充的多边形和轮廓之间切换,然后单击并按住鼠标左键进行拍摄!
我只是让代码在彩色背景上工作(例如,照片)。
上面的代码相当慢,因为Bitmap.Pixels
属性非常慢。当我使用图形时,我总是使用二维颜色值数组来表示位图,这种颜色值要快得多。当我完成图像后,我将其转换为GDI位图。我还有一个从GDI位图创建像素图数组的函数。
我修改了上面的代码来绘制数组而不是GDI位图,结果很有希望:
如果我们让
type
TPixmap = array of packed array of RGBQUAD;
并定义
procedure TForm3.DrawAntialisedLineOnPixmap(var Pixmap: TPixmap; const AX1, AY1, AX2, AY2: real; const LineColor: TColor);
var
swapped: boolean;
procedure plot(const x, y, c: real);
var
resclr: TRGBQuad;
begin
if swapped then
begin
if (x < 0) or (y < 0) or (x >= ClientWidth) or (y >= ClientHeight) then
Exit;
resclr := Pixmap[round(y), round(x)]
end
else
begin
if (y < 0) or (x < 0) or (y >= ClientWidth) or (x >= ClientHeight) then
Exit;
resclr := Pixmap[round(x), round(y)];
end;
resclr.rgbRed := round(resclr.rgbRed * (1-c) + GetRValue(LineColor) * c);
resclr.rgbGreen := round(resclr.rgbGreen * (1-c) + GetGValue(LineColor) * c);
resclr.rgbBlue := round(resclr.rgbBlue * (1-c) + GetBValue(LineColor) * c);
if swapped then
Pixmap[round(y), round(x)] := resclr
else
Pixmap[round(x), round(y)] := resclr;
end;
function rfrac(const x: real): real; inline;
begin
rfrac := 1 - frac(x);
end;
procedure swap(var a, b: real);
var
tmp: real;
begin
tmp := a;
a := b;
b := tmp;
end;
var
x1, x2, y1, y2, dx, dy, gradient, xend, yend, xgap, xpxl1, ypxl1,
xpxl2, ypxl2, intery: real;
x: integer;
begin
x1 := AX1;
x2 := AX2;
y1 := AY1;
y2 := AY2;
dx := x2 - x1;
dy := y2 - y1;
swapped := abs(dx) < abs(dy);
if swapped then
begin
swap(x1, y1);
swap(x2, y2);
swap(dx, dy);
end;
if x2 < x1 then
begin
swap(x1, x2);
swap(y1, y2);
end;
gradient := dy / dx;
xend := round(x1);
yend := y1 + gradient * (xend - x1);
xgap := rfrac(x1 + 0.5);
xpxl1 := xend;
ypxl1 := floor(yend);
plot(xpxl1, ypxl1, rfrac(yend) * xgap);
plot(xpxl1, ypxl1 + 1, frac(yend) * xgap);
intery := yend + gradient;
xend := round(x2);
yend := y2 + gradient * (xend - x2);
xgap := frac(x2 + 0.5);
xpxl2 := xend;
ypxl2 := floor(yend);
plot(xpxl2, ypxl2, rfrac(yend) * xgap);
plot(xpxl2, ypxl2 + 1, frac(yend) * xgap);
for x := round(xpxl1) + 1 to round(xpxl2) - 1 do
begin
plot(x, floor(intery), rfrac(intery));
plot(x, floor(intery) + 1, frac(intery));
intery := intery + gradient;
end;
end;
和转换功能
var
pixmap: TPixmap;
procedure TForm3.CanvasToPixmap;
var
y: Integer;
Bitmap: TBitmap;
begin
Bitmap := TBitmap.Create;
try
Bitmap.SetSize(ClientWidth, ClientHeight);
Bitmap.PixelFormat := pf32bit;
BitBlt(Bitmap.Canvas.Handle, 0, 0, ClientWidth, ClientHeight, Canvas.Handle, 0, 0, SRCCOPY);
SetLength(pixmap, ClientHeight, ClientWidth);
for y := 0 to ClientHeight - 1 do
CopyMemory(@(pixmap[y][0]), Bitmap.ScanLine[y], ClientWidth * sizeof(RGBQUAD));
finally
Bitmap.Free;
end;
end;
procedure TForm3.PixmapToCanvas;
var
y: Integer;
Bitmap: TBitmap;
begin
Bitmap := TBitmap.Create;
try
Bitmap.PixelFormat := pf32bit;
Bitmap.SetSize(ClientWidth, ClientHeight);
for y := 0 to Bitmap.Height - 1 do
CopyMemory(Bitmap.ScanLine[y], @(Pixmap[y][0]), ClientWidth * sizeof(RGBQUAD));
Canvas.Draw(0, 0, Bitmap);
finally
Bitmap.Free;
end;
end;
然后我们可以写
procedure TForm3.FormPaint(Sender: TObject);
begin
// Get the canvas as a bitmap, and convert this to a pixmap
CanvasToPixmap;
// Draw on this pixmap (very fast!)
for i := 0 to 99 do
DrawAntialisedLineOnPixmap(pixmap, Random(ClientWidth), Random(ClientHeight), Random(ClientWidth), Random(ClientHeight), clRed);
// Convert the pixmap to a bitmap, and draw on the canvas
PixmapToCanvas;
end;
将在不到百分之一秒的时间内在表单上呈现100条消除锯齿的线条。
但是,代码中似乎存在一个小错误,可能是在Canvas中 - &gt; Pixmap功能。但是现在我太累了,无法调试(只是下班回家)。
答案 1 :(得分:10)
我相信GDI +会进行抗锯齿绘制(默认情况下),我不知道最近的Delphi版本是否有GdiPlus.pas,但有copies available online。
答案 2 :(得分:4)
您可以尝试TAgg2D。它是通过AggPas进行2D绘图的简化API。所以你可以使用简单的函数,如:
容易!
答案 3 :(得分:3)
答案 4 :(得分:3)
下载Graphics32。创建一个新的TBitmap32实例。调用TBitmap32.RenderText方法:
procedure TBitmap32.RenderText(X, Y: Integer; const Text: String; AALevel: Integer; Color: TColor32);
if AALevel > -1
然后您应该获得抗锯齿文本。
当您在TBitmap32实例上写完字符串后,您可以使用DrawTo方法将此TBitmap32实例绘制到任何Canvas:
procedure TBitmap32.DrawTo(hDst: HDC; DstX, DstY: Integer);
答案 5 :(得分:3)
以下是我所知道的产品:
答案 6 :(得分:1)
有用于Delphi的BGRABitmap https://github.com/bgrabitmap/BGRABitmapDelphi
BGRABitmap最初是Lazarus FPC库,现在可与Delphi VCL一起使用,并且具有抗锯齿和透明的功能。