TextRenderer基于GDI和Graphics.DrawString基于GDI +。这些函数中的任何一个都可以在图像上绘制文本时提供更高质量的文本。
答案 0 :(得分:69)
我将在here之上交叉发布我的答案,以便获取相关信息。
在.NET中有两种绘制文本的方法:
graphics.MeasureString
和graphics.DrawString
)TextRenderer.MeasureText
和TextRenderer.DrawText
)在.NET 1.1中,所有内容都使用 GDI + 进行文本呈现。 But there were some problems:
- 由于GDI +的某种无状态特性会导致一些性能问题,其中设置上下文然后在每次调用后恢复原始内容。
- 国际文本的整形引擎已针对Windows / Uniscribe和Avalon(Windows Presentation Foundation)多次更新,但尚未针对GDI +进行更新,这导致对新语言的国际渲染支持不具有相同级别质量。
所以他们知道他们想要改变.NET框架以停止使用 GDI + 的文本渲染系统,并使用 GDI 。起初他们希望他们可以简单地改变:
graphics.DrawString
调用旧的DrawText
API而不是GDI +。但是they couldn't make the text-wrapping and spacing match exactly as what GDI+ did。
在Windows Forms 2.0中,我们添加了对绘制GDI文本的支持。起初,我们在DrawText API上有一些宏大的戳戳和刺激计划,这样我们可以使它完全匹配GDI +的DrawString API的工作方式。我实际上认为我们非常接近,但是在自动换行和字符间距方面存在根本差异,因为仅仅是这两种API的消费者,Windows窗体无法解决。
所以现在我们遇到了一个问题:我们希望将每个人都切换到新的TextRenderer API,这样文本看起来会更好,更好地本地化,与操作系统中的其他对话框更一致地绘制......但是我们不想让人们依赖GDI +测量字符串来计算他们的文本应该排成一行的位置。
所以他们被迫保持graphics.DrawString
来调用GDI +(兼容性原因;那些打电话给graphics.DrawString
的人会突然发现他们的文字并没有像过去那样包装)。 From 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
Quality之间的映射也很有用:
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 (e.g.SystemDefault) DEFAULT_QUALITY (0)
这里有一些比较GDI +(graphics.DrawString)和GDI(TextRenderer.DrawText)文本呈现:
GDI + :TextRenderingHintClearTypeGridFit
, GDI :CLEARTYPE_QUALITY
:
GDI + :TextRenderingHintAntiAlias
, GDI :ANTIALIASED_QUALITY
:
GDI + :TextRenderingHintAntiAliasGridFit
, GDI :不受支持,使用ANTIALIASED_QUALITY :
GDI + :TextRenderingHintSingleBitPerPixelGridFit
, GDI :PROOF_QUALITY
:
GDI + :TextRenderingHintSingleBitPerPixel
, GDI :DRAFT_QUALITY
:
我觉得奇怪DRAFT_QUALITY
与PROOF_QUALITY
相同,与CLEARTYPE_QUALITY
相同。
另见
答案 1 :(得分:5)
只需2美分:当我需要为我的(Windows窗体)控件进行自定义绘制时,我总是使用Graphics.DrawString,除了。例如,在设置了OwnerDraw的列表框中,如果我附加一个DrawItem事件处理程序,它完全绘制项目,包括项目文本。或者在自定义控件中,我必须自己画画。
在支持它并启用它的操作系统上使用Visual Styles的应用程序中,与其他控件绘制的常规文本相比,使用Graphics.DrawString绘制的文本看起来“关闭”。这似乎主要是因为“ClearType”处理(或不处理)的方式不同,虽然我不确定,但我没有文档来支持该声明。 (它看起来像文本在.Net 1.x上的方式或者将FlatStyle从Standard转换为System和v.v时的方式。)
仅在这种情况下(Winforms控件上的文字绘画)我使用TextRenderer.DrawText使文本更好地融入其他控件。
如果“与本机混合”不是您关心的问题(它看起来像,因为您想在图像上绘图),我会选择Graphics.DrawString。此外,如果您想要打印,则必须,因为TextRenderer仅适用于屏幕(而非打印机画布)。
答案 2 :(得分:0)
我的个人经历(我只知道这两点差异):
DrawString支持Alpha通道,抗锯齿
TextRenderer支持Uniscribe
答案 3 :(得分:0)
我只是输入一些测试代码:
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更准确。