Graphics.DrawString vs TextRenderer.DrawText?哪个可以提供更好的质量

TextRenderer基于GDI和Graphics.DrawString基于GDI +。这些函数中的哪些function可以在图像上绘制文本时提供更高质量的文本。

只是我的2美分:我总是使用Graphics.DrawString, 除非我需要为我的(Windows窗体)控件进行自定义绘制。 例如,在设置了OwnerDraw的列表框中,如果我附加一个DrawItem事件处理程序,它完全绘制项目,包括项目文本。 或者在自定义控件中我必须自己画画。

在支持它并启用它的操作系统上使用Visual Styles的应用程序中,与其他控件绘制的常规文本相比,使用Graphics.DrawString绘制的文本看起来“关闭”。 这似乎主要是因为“ClearType”处理(或不处理)的方式不同,虽然我不确定,但我没有文档来支持该声明。 (它看起来像文本在.Net 1.x上的方式或将FlatStyle从Standard转换为System和vv时的方式)

仅在这种情况下(Winforms控件上的文本绘制)我使用TextRenderer.DrawText使文本更好地与其他控件混合。

如果“与本机混合”不是你关注的问题(它看起来像,因为你想在图像上绘图),我会选择Graphics.DrawString。 此外,如果您想要打印,则必须,因为TextRenderer仅适用于屏幕(而不是打印机canvas)。

我将在这里交叉发布我的答案,以便获取信息。


在.NET中有两种绘制文本的方法:

  • GDI +( graphics.MeasureStringgraphics.DrawString
  • GDI( TextRenderer.MeasureTextTextRenderer.DrawText

在.NET 1.1中,一切都使用GDI +进行文本渲染。 但是有一些问题:

  • 由GDI +的某种无状态特性引起一些性能问题,其中设置上下文然后在每次调用之后恢复原始设备上下文。
  • 对于Windows / Uniscribe和Avalon(Windows Presentation Foundation),国际文本的整形引擎已经多次更新,但尚未针对GDI +进行更新,这导致对新语言的国际渲染支持不具有相同的质量水平。

所以他们知道他们想要改变.NET框架以停止使用GDI +的文本渲染系统,并使用GDI 。 起初他们希望他们可以简单地改变:

 graphics.DrawString 

调用旧的DrawText API而不是GDI +。 但它们无法使文本包装和间距与GDI +完全匹配 。

在Windows Forms 2.0中,我们添加了对绘制GDI文本的支持。 起初,我们在DrawText API上进行了一些宏大的戳戳和刺激计划,这样我们就可以使它与GDI +的DrawString API的工作方式完全匹配。 我实际上认为我们非常接近,但是在自动换行和字符间距方面存在根本差异,仅作为这两种API的消费者,Windows Forms无法解决。

所以现在我们遇到了一个问题:我们希望将每个人都切换到新的TextRenderer API,这样文本看起来会更好,更好地本地化,与操作系统中的其他对话框更一致地绘制……但我们不想要打破人们依靠GDI +测量字符串来计算他们的文本应该排成一行的位置。

所以他们被迫保持graphics.DrawString来调用GDI +(兼容性原因;那些调用graphics.DrawString会突然发现他们的文本没有像过去那样包装)。 来自MSDN :

.NET Framework 2.0中引入了基于GDI的TextRenderer类,以提高性能,使文本看起来更好,并改进对国际字体的支持。 在早期版本的.NET Framework中,基于GDI +的Graphics类用于执行所有文本呈现。 GDI计算字符间距和自动换行与GDI +不同。 在使用Graphics类呈现文本的Windows窗体应用程序中,这可能导致使用TextRenderer的控件的文本与应用程序中的其他文本不同。 若要解决此不兼容问题,可以将UseCompatibleTextRendering属性设置为true以用于特定控件。 要为应用程序中所有受支持的控件将UseCompatibleTextRendering设置为true ,请使用参数true调用Application.SetCompatibleTextRenderingDefault方法。

创建了一个新的静态TextRenderer类来包装GDI文本呈现。 它有两种方法:

 TextRenderer.MeasureText TextRenderer.DrawText 

注意: TextRenderer是GDI的包装器,而graphics.DrawString仍然是GDI +的包装器。


然后是如何处理所有现有.NET控件的问题,例如:

  • Label
  • Button
  • TextBox

他们希望将它们切换为使用TextRenderer (即GDI),但他们必须小心。 可能有些人依赖于他们的控件绘制,就像在.NET 1.1中那样。 因此诞生了“ 兼容的文本渲染 ”。

默认情况下,应用程序中的控件的行为与它们在.NET 1.1中的行为相同(它们是“ 兼容的 ”)。

您通过调用以下命令关闭兼容模式:

 Application.SetCompatibleTextRenderingDefault(false); 

这使您的应用程序更好,更快,具有更好的国际支持。 总结一下:

 SetCompatibleTextRenderingDefault(true) SetCompatibleTextRenderingDefault(false) ======================================= ======================================== default opt-in bad good the one we don't want to use the one we want to use uses GDI+ for text rendering uses GDI for text rendering graphics.MeasureString TextRenderer.MeasureText graphics.DrawString TextRenderer.DrawText Behaves same as 1.1 Behaves *similar* to 1.1 Looks better Localizes better Faster 

注意GDI + TextRenderingHint与用于GDI字体绘制的相应LOGFONT质量之间的映射也很有用:

 TextRenderingHint mapped by TextRenderer to LOGFONT quality ======================== ========================================================= ClearTypeGridFit CLEARTYPE_QUALITY (5) (Windows XP: CLEARTYPE_NATURAL (6)) AntiAliasGridFit ANTIALIASED_QUALITY (4) AntiAlias ANTIALIASED_QUALITY (4) SingleBitPerPixelGridFit PROOF_QUALITY (2) SingleBitPerPixel DRAFT_QUALITY (1) else (egSystemDefault) DEFAULT_QUALITY (0) 

样品

这里是GDI +(graphics.DrawString)与GDI(TextRenderer.DrawText)文本呈现的一些比较:

GDI +TextRenderingHintClearTypeGridFitGDICLEARTYPE_QUALITY

在此处输入图像描述

GDI +TextRenderingHintAntiAliasGDIANTIALIASED_QUALITY

在此处输入图像描述

GDI +TextRenderingHintAntiAliasGridFitGDI不支持,使用ANTIALIASED_QUALITY

在此处输入图像描述

GDI +TextRenderingHintSingleBitPerPixelGridFitGDIPROOF_QUALITY

在此处输入图像描述

GDI +TextRenderingHintSingleBitPerPixelGDIDRAFT_QUALITY

在此处输入图像描述

我发现DRAFT_QUALITYDRAFT_QUALITY相同,这与PROOF_QUALITY相同。

也可以看看

  • UseCompatibleTextRendering – 与whaaaaaat兼容?
  • 对它进行排序:快速浏览一下Whidbey的TextRenderer
  • MSDN:LOGFONT结构
  • AppCompat Guy:GDI与GDI +文本渲染性能
  • GDI +文本,分辨率独立和渲染方法。 或者 – 为什么我的文字在GDI +和GDI中看起来不同?

我的个人经历(我只知道这两个不同之处):

DrawString支持Alpha通道,抗锯齿

TextRenderer支持Uniscribe

我只想输入一些测试代码:

 class Form1: Form { private string str = "hello world hello world hello world"; private int x = 32, yLabel = 0, yDraw = 64, yRenderer = 32; public Form1() { Font = new Font("Times", 16); Label label = new Label(); label.BorderStyle = BorderStyle.FixedSingle; label.AutoSize = true; label.Text = str; label.Location = new Point(x, yLabel); Controls.Add(label); } protected override void OnPaint(PaintEventArgs e) { SizeF a; // TextRenderer a = TextRenderer.MeasureText(str, Font); TextRenderer.DrawText(e.Graphics, str, Font, new Point(x, yRenderer), Color.Pink); e.Graphics.DrawRectangle(new Pen(Color.Blue), x, yRenderer, a.Width, a.Height); // DrawString e.Graphics.DrawString(str, Font, new SolidBrush(Color.Red), x, yDraw); a = e.Graphics.MeasureString(str, Font); e.Graphics.DrawRectangle(new Pen(Color.Lime), x, yDraw, a.Width, a.Height); base.OnPaint(e); } } 

底线:与简单的Label相比,TextRenderer更准确。