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
,
Смотрите также
- UseCompatibleTextRendering - совместимо с whaaaaaat?
- Разбираемся в этом: быстрый взгляд на TextRenderer Уидби
- MSDN: структура LOGFONT
- AppCompat Guy: GDI против GDI+ производительность рендеринга текста
- GDI+ текст, независимость разрешения и методы рендеринга. Или - Почему мой текст выглядит по-разному в GDI+ и в GDI?
Мой личный опыт (я знаю только эти два различия):
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 более точен.