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

C# Graphics.DrawString vs TextRenderer.DrawText?哪一个可以提供更好的质量,c#,.net,text,gdi+,gdi,C#,.net,Text,Gdi+,Gdi,TextRenderer基于GDI和Graphics。DrawString基于GDI+。在图像上绘制文本时,以下哪种功能可以提供更高质量的文本。我的个人体验(我只知道这两个区别): DrawString支持Alpha通道,抗锯齿 TextRenderer只支持Uniscribe我的2美分:我总是使用Graphics.DrawString,除非我需要为我的(Windows窗体)控件进行自定义绘制。例如,在设置了OwnerDraw的列表框中,如果我附加了一个DrawItem事件处理程序,该处理程序可

TextRenderer基于GDI和Graphics。DrawString基于GDI+。在图像上绘制文本时,以下哪种功能可以提供更高质量的文本。

我的个人体验(我只知道这两个区别):

DrawString支持Alpha通道,抗锯齿


TextRenderer只支持Uniscribe

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

在支持并启用了视觉样式的操作系统上使用视觉样式的应用程序中,与其他控件绘制的常规文本相比,使用Graphics.DrawString绘制的文本看起来“关闭”。这似乎主要是因为“ClearType”处理(或不处理)方式的不同,尽管我不确定,也没有文档支持该语句。(这有点像.NET1.x上的文本,或者从标准切换到系统和v.v时的文本。)

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


如果“融入当地人”不是你关心的问题之一(看起来是这样,因为你想在图像上画画),我会选择Graphics.DrawString。另外,如果您想打印,您必须这样做,因为TextRenderer只在屏幕上工作(而不是在打印机画布上)。

我将在上面交叉张贴我的答案,以便信息能够被传递


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

  • GDI+(
    graphics.MeasureString
    graphics.DrawString
  • GDI(
    textrender.MeasureText
    textrender.DrawText
在.NET 1.1中,所有内容都使用了GDI+进行文本渲染

  • GDI+的无状态特性导致了一些性能问题,在GDI+中,设备上下文将被设置,然后在每次调用后恢复原始上下文
  • Windows/Uniscribe和Avalon(Windows Presentation Foundation)的国际文本成形引擎已多次更新,但尚未针对GDI+进行更新,这导致对新语言的国际呈现支持的质量不尽相同
因此他们知道他们想改变.NET框架,停止使用GDI+的文本呈现系统,而使用GDI。起初,他们希望他们可以简单地改变:

graphics.DrawString
调用旧的
DrawText
API而不是GDI+。但是

在Windows Forms 2.0中,我们添加了对绘制GDI文本的支持。起初,我们有宏伟的计划来戳和戳DrawText API,这样我们就可以使它与GDI+的DrawString API的工作方式完全匹配。事实上,我认为我们已经非常接近了,但在单词包装和字符间距方面存在着根本性的差异,而仅仅作为这两种API的消费者,Windows窗体无法解决这一问题

因此,现在我们遇到了一个问题:我们希望将每个人都切换到新的TextRenderer API,以便文本看起来更好、本地化更好、与操作系统中的其他对话框绘制更一致。。。但是我们不想破坏那些依靠GDI+度量值字符串计算文本排列位置的人们

因此,他们被迫保留
graphics.DrawString
来调用GDI+(兼容性原因;调用
graphics.DrawString
的人会突然发现他们的文本没有以前的包装方式):

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

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

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


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

  • 标签
  • 按钮
  • TextBox
他们想将它们切换到使用
textrender
(即GDI),但必须小心。可能有人像在.NET1.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字体绘图所用的相应字体之间的映射也很有用:

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+
textrendinghintcleartypegridfit
GDI
CLEARTYPE\u-QUALITY

<
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);
    }
}