Graphics.DrawString vs TextRenderer.DrawText? Что может обеспечить лучшее качество

TextRenderer основан на GDI, а Graphics.DrawString основан на GDI+. Какая из этих функций может обеспечивать более качественный текст при рисовании текста на изображении.

4 ответа

Решение

Только мои 2 цента: я всегда использую Graphics.DrawString, за исключением случаев, когда мне нужно сделать пользовательское рисование для моих элементов управления (Windows Forms). Например, в списке со значением OwnerDraw, если я присоединяю обработчик события DrawItem, который полностью рисует элементы, включая текст элемента. Или в пользовательском элементе управления я должен нарисовать себя.

В приложении, которое использует визуальные стили в ОС, которая поддерживает его и имеет его включенный, текст, нарисованный с помощью Graphics.DrawString, выглядит "выключенным" по сравнению с обычным текстом, нарисованным другими элементами управления. Это, по-видимому, главным образом из-за различий в способах обработки (или не обработки) ClearType, хотя я не уверен, и у меня нет документов, подтверждающих это утверждение. (Это выглядит как текст в.Net 1.x или при переключении FlatStyle со Standard на System и vv)

Только в таких случаях (рисование текста на элементах управления Winforms) я использую TextRenderer.DrawText, чтобы текст лучше сочетался с другими элементами управления.

Если "смешивание с нативами" не является одной из ваших проблем (как это выглядит, поскольку вы хотите рисовать на изображении), я бы выбрал Graphics.DrawString. Кроме того, если вы хотите печатать, вы должны, так как TextRenderer работает только на экране (не на холсте принтера).

Я собираюсь перекрестно опубликовать свой ответ отсюда, просто чтобы информация получилась.


Есть два способа рисования текста в.NET:

  • GDI+ (graphics.MeasureString а также graphics.DrawString)
  • GDI (TextRenderer.MeasureText а также TextRenderer.DrawText)

В.NET 1.1 все использовали GDI+ для рендеринга текста. Но были некоторые проблемы:

  • Существуют некоторые проблемы с производительностью, вызванные в некоторой степени отсутствием состояния GDI+, когда контексты устройства устанавливаются, а затем исходный восстанавливается после каждого вызова.
  • Механизмы формирования международного текста неоднократно обновлялись для Windows/Uniscribe и для Avalon (Windows Presentation Foundation), но не обновлялись для GDI+, что приводит к тому, что поддержка международного рендеринга для новых языков не имеет того же уровня качества.

Таким образом, они знали, что хотят изменить.NET Framework, чтобы прекратить использовать систему рендеринга текста GDI+ и использовать GDI. Сначала они надеялись, что могут просто измениться:

graphics.DrawString

называть старым DrawText API вместо GDI+. Но они не могли сделать так, чтобы перенос текста и интервал соответствовали так, как это делал GDI+.

В Windows Forms 2.0 мы добавили поддержку рисования текста GDI. Сначала у нас были грандиозные планы по созданию и продвижению в DrawText API, чтобы мы могли точно настроить, как работает API-интерфейс DrawString в GDI+. Я на самом деле думаю, что мы подошли довольно близко, но есть фундаментальные различия в переносе слов и интервале между символами, которые, как простые потребители обоих API, Windows Forms не могли решить.

Итак, теперь у нас есть проблема: мы хотим переключить всех на новые API TextRenderer, чтобы текст выглядел лучше, локализовался лучше, рисовался более согласованно с другими диалогами в операционной системе...... но мы не хотим сломать людей, рассчитывающих на строку измерения GDI+ для расчета того, где должен располагаться их текст.

Поэтому они были вынуждены сохранить graphics.DrawString позвонить GDI+ (причины совместимости; люди, которые звонили graphics.DrawString вдруг обнаружит, что их текст не обернут так, как раньше). Из MSDN:

Класс TextRenderer, основанный на GDI, был представлен в.NET Framework 2.0 для повышения производительности, улучшения внешнего вида текста и улучшения поддержки международных шрифтов. В более ранних версиях.NET Framework класс Graphics на основе GDI+ использовался для выполнения всей визуализации текста. GDI вычисляет межсимвольный интервал и перенос слов по-другому, чем GDI+. В приложении Windows Forms, которое использует класс Graphics для визуализации текста, это может привести к тому, что текст для элементов управления, использующих TextRenderer, будет отличаться от другого текста в приложении. Чтобы устранить эту несовместимость, вы можете установить UseCompatibleTextRendering свойство true для конкретного элемента управления. Установить UseCompatibleTextRendering Значение true для всех поддерживаемых элементов управления в приложении, вызовите метод Application.SetCompatibleTextRenderingDefault с параметром true.

Новая статика 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 и соответствующий LOGFONT Качество, используемое для рисования шрифтов 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+: 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,

Смотрите также

Мой личный опыт (я знаю только эти два различия):

DrawString поддерживает альфа-канал, сглаживание

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

Итог: по сравнению с простой меткой TextRenderer более точен.

Другие вопросы по тегам