Graphics.DrawString vs TextRenderer.DrawText? Что может обеспечить лучшее качество - PullRequest
16 голосов
/ 27 ноября 2011

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

Ответы [ 4 ]

69 голосов
/ 23 апреля 2014

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


Есть два способа рисования текста в .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:

enter image description here

GDI + : TextRenderingHintAntiAlias, GDI : ANTIALIASED_QUALITY:

enter image description here

GDI + : TextRenderingHintAntiAliasGridFit, GDI : не поддерживается, использует ANTIALIASED_QUALITY :

enter image description here

GDI + : TextRenderingHintSingleBitPerPixelGridFit, GDI : PROOF_QUALITY:

enter image description here

GDI + : TextRenderingHintSingleBitPerPixel, GDI : DRAFT_QUALITY:

enter image description here

Мне кажется странным, что DRAFT_QUALITY идентичен PROOF_QUALITY, что идентично CLEARTYPE_QUALITY.

См. Также

5 голосов
/ 08 февраля 2012

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

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

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

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

0 голосов
/ 03 июля 2014

Я просто добавлю тестовый код:

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 более точен.

0 голосов
/ 26 января 2012

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

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

TextRenderer поддерживает Uniscribe

...