65.9K
CodeProject 正在变化。 阅读更多。
Home

CTGraphics - 抗锯齿 C++ 绘图

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.77/5 (45投票s)

2006 年 11 月 30 日

CPOL

4分钟阅读

viewsIcon

178439

downloadIcon

9133

一篇关于抗锯齿 C++ 绘图的文章。

Demo-Project Screenshot image

引言

本文介绍了使用 C++ 在 GDI 下的抗锯齿绘图支持。它适用于 MFC 或非 MFC 应用程序。这里介绍了一个名为 CTGraphics 的小类。它支持对基本图元进行抗锯齿处理:线条、弧线、椭圆(圆)、圆角矩形、多边形和扇形。您可以使用这些基本图元定义其他有趣的形状。

背景

什么是“锯齿”效应?当您使用基本的 Windows GDI 绘制某些图形形状时,就会出现锯齿边缘(或者换句话说,就是阶梯状)。请看下面的图片

Aliased Line image

那么,这有什么问题呢?如果您希望您的计算机生成的图形(或图像)看起来不错,这并不是一个好方法。那么,这是怎么发生的呢?这是因为屏幕分辨率有限,即可以在屏幕上绘制的像素数量有限,水平或垂直。它们的尺寸非常小,以至于您看不到它们,这就是为什么当您想使用 Windows GDI 的 MoveToEx()LineTo() 方法绘制线条时会发生这种情况。

那该怎么办呢?现在,这就是出现称为“抗锯齿”的技术的地方。它必须做一些事情来模糊这些边缘,因此针对此操作采用了不同的方法。一种方法称为对原始图像进行超采样。它以高频率渲染图像(缩放后的原始图像 2 倍或更多),然后对该超采样图像执行低通滤波,这样边缘就会变得不那么尖锐,当您再次缩小此图像(到原始大小)时,您将获得抗锯齿效果。这是一种非常耗内存的方法,但它有效。

另一种方法(此处实现)是对原始图像进行预滤波。它平均了被图元方程覆盖的像素数量。理想的线不会覆盖整个像素,而是覆盖像素的一部分,因此此方法将该像素的强度设置为不同于您正在绘制的线的最大值。因此,当您绘制线条时,您将线条像素设置为某个值。此方法比前一种方法更节省内存,但它需要大量数学计算才能正确实现,因此您可以看到折衷方案在哪里。

无论您采用哪种抗锯齿方式,您都将获得类似于以下内容的输出

AntiAliased Line image

因此,您已经修改了原始线条像素,现在线条边缘略微平滑。CTGraphics 类以类似的方式工作。它支持对以下内容进行抗锯齿处理

  • Lines
  • 多边形
  • 多边形
  • 椭圆
  • 弧形
  • 扇形
  • 和弦
  • 圆角矩形
  • 贝塞尔样条曲线

但是,您可以自由扩展其在其他形状和图形图元上的功能。您可以组合基本形状并获得更复杂的形状(这就是圆角矩形的方式:通过组合线条和弧线)。

使用代码

要使用提供的源代码,只需在您的 MS Visual C++ 项目中包含TGraphics.hTGraphics.cpp 文件。使用所描述的类非常简单,请参见下文

CTGraphics tGraphics;

// hDC is obtained somewhere else
// Variables x1, y1, x2 and y2 are defined somewhere else
COLORREF color = RGB(255, 0, 0); // Pick some nice line color

// You have everything, now draw anti-aliased line
tGraphics.DrawLine(hDC, x1, y1, x2, y2, color);

这非常简单,不是吗?CTGraphics 类的其他方法的工作方式非常相似,因此我将不再解释它们中的每一个。

重要提示

这里介绍了一个小的 C++ 类,它使用 Windows GDI 和 C++ 执行抗锯齿绘图。但是,在这里并没有以速度为目标,因此不要期望演示运行得最快。这只是在绘图线条和弧线时,在首要位置获得平滑边缘所需的功能的演示。此外,仅支持 1px 宽度的“绘图笔”。这听起来可能不完美,但这只是为了完成这项工作,而不是让它比现在更难。

关注点

我一直在 Internet 和 CodeProject 上寻找这个主题,并发现了或多或少相似的不同解决方案。我想将基本的线条抗锯齿算法(如 CodeProject 上存在的 Wu 算法)扩展到弧线和其他形状。我并不说这是您可以达到的最佳结果,但它很快就为我完成了这项工作。您可能还会发现,由于计算中涉及浮点数,输出并不完美,但我将其留给您作为练习。作为不同方法的一个例子,您可以在 CTGraphics 类的源代码中找到,椭圆不是使用 360 度的弧线完成的,尽管它可以。相反,我使用了一个类似且稍加修改的数学方程式。

历史

CTGraphics 类版本 1.01。

在此版本中,添加了对以下内容的支持

  • 多边形
  • 和弦
  • 贝塞尔样条曲线
© . All rights reserved.