netlib.narod.ru | < Назад | Оглавление | Далее > |
Часть GDI+, отвечающая за работу с текстом, не зависит от устройства вывода. С практической точки зрения, это значит, что MeasureString возвращает размеры текста, не зависящие от устройства вывода. Если установить одинаковое преобразование страницы для экрана и принтера, MeasureString вернет одинаковое значение для заданной текстовой строки и заданного шрифта. Такая согласованность облегчает форматирование текста, чтобы он выглядел на экране так же, как при печати на принтере.
Однако желаемый принцип WYSIWYG трудно реализовать. Проблема в пикселях. Когда знаки шрифта растеризуются, координаты, выраженные числами c плавающей запятой, должны быть округлены с учетом дискретности пикселов. Такая подгонка под координатную сетку (grid fitting) требует специальных действий для сохранения читабельности шрифта. Скажем, два вертикальных штриха в заглавной букве H должны быть одинаковой ширины. Даже для шрифтов маленьких размеров эти два штриха должны иметь ширину не менее 1 пиксела и должны быть разнесены не менее чем на 1 пиксел. (Если размер точки слишком мал в сравнении с разрешением устройства вывода, такое требование теряет смысл, потому что текст не будет разборчивым в любом случае.)
Иногда, особенно для малых кеглей на устройствах с низким разрешением (таких как монитор), подгонка может привести к тому, что преобразованные шрифты будут гораздо больше, чем их теоретические размеры. Если собрать такие знаки (скажем, строчные знаки i гарнитуры Arial) вместе, это может привести к тому, что строка текста будет выглядеть на мониторе значительно больше, чем на принтере. (В статье на сайте http://www.gotdotnet.com/team/windowsforms/gdiptext.aspx эта проблема рассмотрена подробнее).
Соединяя разные фрагменты текста с помощью DrawString и MeasureString (как, например, в программе BoldAndItalic), что бы вы предпочли: иметь дополнительное пустое место между фрагментами или чтобы фрагменты текста перекрывались? Думаю, вы согласитесь, что наложение текста неприемлемо. Чтобы его предотвратить, в методы DrawString и MeasureString предусмотрительно заложена возможность включения небольшого дополнительного пустого места. Таким образом, если растеризатору потребуется больше места для прорисовки какого-либо шрифта, он его получит.
По умолчанию у объекта SizeF, возвращаемого MeasureString, свойство Height на 1/8 размера эм больше, чем теоретически нужно, и свойство Width на 1/3 размера эм больше, чем теоретическая ширина. (Помните: размер эм численно равен кеглю шрифта. Например, для 24-пунктного шрифта 1/3 размера эм равна 8 пт.) По умолчанию DrawString начинает выводить текст на монитор на 1/6 размера эм ниже заданной вертикальной координаты. Фактически MeasureString возвращает прямоугольник, который справа и слева шире, чем предполагаемая текстовая строка на 1/6 размера эм.
Поэтому в BoldAndItalic и, более наглядно, в BoldAndItalicBigger видны лишние пустые места между соединенными фрагментами текста.
Следует помнить, что проблема подгонки к координатной сетке имеет место только для шрифтов с маленькими кеглями, которые выводятся на устройства с низким разрешением. Чтобы добиться независимости от устройства, добавление пустого места в DrawString и MeasureString должно реализовываться одинаково для устройств как с высоким, так и с низким разрешением. Дополнительное пространство должно быть также пропорциональным размеру шрифтов. Для 720-пунктного шрифта MeasureString должен вернуть размер текста в 100 раз больше, чем для 7,2-пунктного шрифта.
Что делать, если не желательно оставлять пустые места в тексте? Использовать объект StringFormat, основанный на StringFormat.GenericTypographic. Вот версия программы BoldAndItalic, которая имеет дело с таким объектом:
BoldAndItalicTighter.cs
//----------------------------------------------------- // BoldAndItalicTighter.cs (C) 2001 by Charles Petzold //----------------------------------------------------- using System; using System.Drawing; using System.Drawing.Text; using System.Windows.Forms; class BoldAndItalicTighter: PrintableForm { public new static void Main() { Application.Run(new BoldAndItalicTighter()); } public BoldAndItalicTighter() { Text = "Bold and Italic (Tighter)"; Font = new Font("Times New Roman", 24); } protected override void DoPage(Graphics grfx, Color clr, int cx, int cy) { const string str1 = "This is some "; const string str2 = "bold"; const string str3 = " text, and this is some "; const string str4 = "italic"; const string str5 = " text."; Brush brush = new SolidBrush(clr); Font fontRegular = Font; Font fontBold = new Font(fontRegular, FontStyle.Bold); Font fontItalic = new Font(fontRegular, FontStyle.Italic); PointF ptf = new PointF(0, 0); StringFormat strfmt = StringFormat.GenericTypographic; strfmt.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces; grfx.DrawString(str1, fontRegular, brush, ptf, strfmt); ptf.X += grfx.MeasureString(str1, fontRegular, ptf, strfmt).Width; grfx.DrawString(str2, fontBold, brush, ptf, strfmt); ptf.X += grfx.MeasureString(str2, fontBold, ptf, strfmt).Width; grfx.DrawString(str3, fontRegular, brush, ptf, strfmt); ptf.X += grfx.MeasureString(str3, fontRegular, ptf, strfmt).Width; grfx.DrawString(str4, fontItalic, brush, ptf, strfmt); ptf.X += grfx.MeasureString(str4, fontItalic, ptf, strfmt).Width; grfx.DrawString(str5, fontRegular, brush, ptf, strfmt); } }
Заметьте: в программе установлен флаг MeasureTrailingSpaces. Результат выглядит неплохо:
В программе BoldAndItalicTighter можно обойтись без объекта GenericTypographic, потому что заранее известно, что шрифт достаточно велик и несколько пикселов не имеют значения. Если вы хотите использовать GenericTypographic с малыми размерами шрифта на мониторе, вы также должны применить сглаживание краевых эффектов. При сглаживании не требуется подгонка к координатной сетке, потому что каждый пиксел окрашивается в зависимости от его удаленности от теоретического контура.
netlib.narod.ru | < Назад | Оглавление | Далее > |