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

GDI+ 的自定义抗锯齿

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.89/5 (31投票s)

2004 年 12 月 31 日

4分钟阅读

viewsIcon

224698

downloadIcon

3219

GDI+ 中的备用抗锯齿。

引言

我使用 GDI+ 已经很多年了。我主要在协助开发自定义 UI 时使用 GDI+。我注意到越来越复杂的矢量图形被集成到 UI 中。这背后的原因似乎是图形艺术家喜欢使用抗锯齿、渐变、混合和透明度来给 UI 带来“品质感”。我对使用矢量图形有强烈的偏好,因为它们易于在运行时操作和缩放。因此,我们已经使用 GDI+ 来创建自定义 UI 一段时间了。然而,最近我遇到了几个与原生 GDI+ 抗锯齿相关的质量问题,我认为这些问题对 CodeProject 的读者来说应该很有普遍意义。

我最近遇到的问题是:

  1. 丑陋的缩略图 – 使用原生 GDI+ 抗锯齿时,小的矢量图形通常看起来很糟糕。它们通常无法与其原始的大图像清晰辨认。尤其是在图像非常小的时候。
  2. 接缝明显 – 通过将多个对象紧密排列以试图实现无缝过渡而构建的矢量图形,常常会出现非常明显的瑕疵。
  3. 意外的瑕疵 – 一些矢量图形在使用 GDI+ 抗锯齿时会出现意外的瑕疵。通常这些是由接缝引起的,但细线和其他图形元素也可能导致不令人愉快的瑕疵。

由于我使用 GDI+ 的目标是生成高质量的图像,因此我需要一种方法来解决这些质量问题。别误会,我并不是说原生 GDI+ 抗锯齿很差,事实上它已经好得令人惊讶,而且速度很快。然而,有时它就是不够好。

本文接下来的部分将更详细地描述这些瑕疵,并提供一种简单的算法,可以在很大程度上消除您图像中的这些问题——当然,代价不菲。

清理丑陋的缩略图

缩略图是小的图像,通常用于帮助用户一次性查看多个选项。缩略图在非常小时能够轻松识别非常重要;否则它们的价值有限。不幸的是,GDI+ 的原生抗锯齿经常产生质量非常差的缩略图(参见上图的左侧和中间图像)。

在上图中,您可以看到原生 GDI+ 抗锯齿比自定义抗锯齿大约快 30%。较大的图像之间可能存在高达 10 倍的差异。然而,自定义抗锯齿缩略图的质量非常高,并且更容易与原始的大图像关联。由于渲染时间的增加,此自定义抗锯齿技术应该在绝对必要时使用。

您的接缝是否暴露

GDI+ 原生抗锯齿在处理您艺术作品中旨在不可见的接缝时会出现问题的另一种情况。这可能由多种原因引起:

混合 – 混合本质上是在两个或多个形状之间变形的渐变。由于 GDI+ 不直接支持混合,它们通常是通过创建多个路径来构建的,每个路径代表一个形状变化,并用渐变中下一个计算出的颜色填充这些路径。不幸的是,此过程可能产生接缝,当启用原生抗锯齿时,这些接缝会严重锯齿化。

紧密排列的对象 - 在构建网页图形或应用程序皮肤时,构建外观上紧密排列后无缝的位图是非常常见的。使用矢量对象时,有时也会很有用。不幸的是,如果您打开抗锯齿,您的接缝很可能会暴露出来。

出现的瑕疵往往是图形中的裂缝或看起来奇怪的渐变(参见下图的示例)。

意外的锯齿

原生 GDI+ 抗锯齿在处理细线时存在问题。在下面的示例中,请注意胡须和文本周围的线条是如何被奇怪地强调和锯齿化的。这并非原始艺术作品所期望的。这种锯齿效应会随着图像尺寸缩小而加剧。

自定义抗锯齿算法

为了生成比原生 GDI+ 抗锯齿更高质量的图像,我使用了以下算法。

  1. 构建一个离屏位图,其尺寸是我想输出图像的 2、4 或 8 倍。使用 2 的幂作为离屏位图的大小很重要。
  2. 以适当的比例绘制矢量图像以适应较大的离屏位图。
  3. 使用 Graphics.DrawImage 并将 InterpolationMode 设置为 HighQualityBicubic,在将图像拉伸到较小尺寸时。

使用此算法的输出在大多数情况下明显优于原生 GDI+ 抗锯齿方法,但绘制时间会显著增加。

// Make a 4X offscreen bitmap, power of 2's are important because 
// interpolating other size images takes significantly longer.
Bitmap offscreen = new Bitmap(bounds.Width*4, bounds.Height*4);
Graphics ofg = Graphics.FromImage(offscreen);
                        
//Update transform for additional pixels
Matrix t = m.Clone();
t.Translate(-bounds.Left, -bounds.Top, MatrixOrder.Append);
t.Scale(4.0f, 4.0f, MatrixOrder.Append);
                        
//Do Paint
Paint(ofg, t);                    
                        
//Stretch blit the rendered image to the actual image
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(offscreen, bounds, 0, 0, offscreen.Width, offscreen.Height, 
    GraphicsUnit.Pixel); 
        

历史

  • 最初写于 2004 年 12 月 29 日。

致谢

本文相关的示例程序使用 GDI+ 矢量图形代码,这些代码是从 Adobe Illustrator CS(cheshire cat.ai 和 crystal.ai)的示例文件以及 Scott Ketterer(aquabutton.ai)的示例文件中创建的。我认为这些示例很好地说明了使用 GDI+ 矢量图形所能实现的复杂图形以及使用它们时可能出现的问题。

© . All rights reserved.