Graphics.DrawString vs TextRenderer.DrawText, который может обеспечить лучшее качество

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

Ответ 1

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

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

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

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

Ответ 2

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


Существует два способа рисования текста в .NET:

  • GDI + (graphics.MeasureString и graphics.DrawString)
  • GDI (TextRenderer.MeasureText и TextRenderer.DrawText)

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

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

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

graphics.DrawString

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

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

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

Поэтому они были вынуждены оставить 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.

См. также

Ответ 3

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

DrawString поддерживает Alpha Channel, Anti Aliasing

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

Ответ 4

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

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 является более точным.