Почему шрифт в Windows занимает разную ширину: GDI и DirectWrite

Один и тот же файл шрифта может занимать разную ширину и переносить слова в разных программах Windows. Часто меняется не рисунок букв, а способ измерения и позиционирования глифов: старый путь GDI привязывает метрики к экранным пикселям, а DirectWrite умеет раскладывать текст по идеальным метрикам с дробным позиционированием. Разберём, как найти источник расхождения и когда его можно устранить.
Почему одинаковый шрифт даёт разную строку
Шрифт задаёт контуры символов и базовые метрики, но программа ещё должна превратить последовательность знаков в строку с конкретными координатами. Для этого она выбирает текстовый API, метод измерения, режим сглаживания и правила формирования текста. Поэтому одинаковые имя гарнитуры, кегль и надпись не гарантируют пиксельного совпадения между приложениями.
Для диагностики важно разделить три результата. Форма — какой контур и начертание выбраны. Метрики — какая ширина назначена каждому глифу и где стоят промежутки. Растеризация — какие пиксели подсвечены вокруг уже размещённых контуров. Если отличается только чёткость края, проблема визуальная; если меняется длина строки или перенос, различаются метрики, формирование текста либо настройки макета.
От GDI к DirectWrite: менялся не только способ сглаживания
GDI — старый интерфейс Windows для рисования текста и графики. Многие существующие приложения используют его для надписей, контролов и измерения ширины строки. DirectWrite появился как отдельная подсистема работы с текстом: она отвечает за шрифты и раскладку глифов, а рисовать результат может Direct2D или другой рендерер. Такое разделение позволяет обновлять текстовый слой постепенно, оставляя части интерфейса на прежних графических API.
В классическом режиме GDI позиции глифов согласуются с пиксельной сеткой дисплея. Это помогает старому интерфейсу сохранять привычную ширину надписей и их привязку к элементам управления, но строка может зависеть от разрешения и округления. DirectWrite предлагает также естественные метрики: интервалы берутся из дизайна шрифта, а координаты могут иметь доли пикселя. Такой режим лучше сохраняет пропорции при масштабировании и разной плотности экрана, но ширина может не совпасть с ранее сохранённой GDI-версткой.
Это не строгая граница «старое плохо, новое хорошо». Документация Microsoft перечисляет в DirectWrite режимы измерения и растеризации, совместимые с GDI: GDI classic и GDI natural. Приложение может выбрать их ради совместимого размещения текста, даже если само использует DirectWrite. Поэтому название API — только часть ответа; важны конкретные параметры, выбранные программистом.
Измерение и сглаживание решают разные задачи
Режим измерения влияет на координаты и ширину. В документации DirectWrite `DWRITE_MEASURING_MODE_NATURAL` использует идеальные метрики глифов, независимые от разрешения экрана. `GDI_CLASSIC` использует метрики, настроенные под дисплей; `GDI_NATURAL` воспроизводит метрики GDI с настройкой `CLEARTYPE_NATURAL_QUALITY`. Если набор слов в строке отличается, сравнивать нужно измерение и доступную ширину контейнера в первую очередь.
Режим рисования определяет, как покрытие контура превращается в пиксели. Алиасинг может быть двоичным, серым или ClearType, если приложение и поверхность это позволяют. В режиме natural DirectWrite допускает дробное размещение по горизонтали; симметричная растеризация может сглаживать также вертикальные края. Эти решения заметны глазу, но смена цвета сглаживания сама по себе обычно не должна исправлять переносы: перенос определяется геометрией и измерением, а не оттенком пиксельного края.
Для совместимости нужно сверять соответствующие пары, а не смешивать все опции в один переключатель: GDI classic measurement — с GDI classic rendering; GDI natural measurement — с GDI natural rendering; natural measurement — с natural rendering. В реальной программе могут быть другие композиция, масштабирование, текстовый движок и доступная ширина поля, поэтому это диагностическая карта, а не гарантия идентичного скриншота.
Слои могут сочетаться и внутри одного приложения. DirectWrite отвечает за анализ и раскладку текста, а интерфейс отрисовки передаёт глифы графическому слою; Microsoft описывает возможность применять DirectWrite для текста и одновременно сохранять GDI или GDI+ для остального окна. Поэтому сравнение «эта программа использует DirectWrite» не объясняет само по себе поведение каждой надписи. Например, текст в основном редакторе и системная подпись диалога могут идти разными путями. Для локализации сравнивайте одинаковые элементы одного типа и не принимайте разницу между основным текстом и кнопкой за дефект установленного файла шрифта.
Как локализовать расхождение без доступа к исходному коду
Если вы готовите макет, документ или инструкцию для коллег, проведите небольшой контролируемый тест. Возьмите один установленный файл шрифта, один компьютер и одну короткую строку с разными ширинами глифов: например, «Минимум: ширина WMW; цифры 111 и 888». Сравните один и тот же текст в проблемной программе, в другом приложении Windows и в PDF, если именно его передают дальше.
Сначала проверьте свойства шрифта и текста: не подменился ли файл начертания, не выбран ли синтетический bold/italic, одинаковы ли размер, масштаб интерфейса, межсимвольный интервал, кернинг и ширина поля. Затем сохраните скриншоты и измерьте не сглаженные края, а положение начала и конца строки. Если силуэты букв похожи, но финальная буква сдвинулась, ищите измерение, shaping или параметры абзаца; если ширина строки одинакова, но края выглядят иначе — это вероятнее растеризация.
Для автора макета полезен такой тест:
- Создайте копию страницы и задайте одинаковую ширину колонки в физических единицах.
- Вставьте стабильную контрольную фразу с узкими и широкими буквами, цифрами, пунктуацией и кириллицей.
- Сравните число строк, переносы, длину последней строки и положение границы абзаца.
- Экспортируйте обе версии в PDF и проверьте их в одном просмотрщике при одинаковом масштабе.
- Если важна повторяемость, зафиксируйте приложение, версию, файл шрифта, размер, ширину колонки и способ экспорта.
В таком опыте не нужно угадывать по одному символу. Сравнение абзаца показывает накопление малых различий: даже несколько округлений по ширине могут вытолкнуть последнее слово на следующую строку. При этом PDF тоже не абсолютный эталон: важны настройки экспорта, встроен ли шрифт, а также то, как конкретный просмотрщик его выводит. Сравнивайте конечный носитель, если именно его получит читатель или типография.
Если вы разрабатываете приложение
При переносе интерфейса на DirectWrite сначала решите, что важнее для конкретного экрана: сохранение старых координат или независимая от разрешения раскладка. Таблица, кнопка и длинный текстовый блок предъявляют разные требования. В кнопке с фиксированной шириной может быть критична совместимость с прежними размерами; в редакторе текста важнее естественное позиционирование, предсказуемое масштабирование и работа с письмами сложной формы.
Microsoft документирует взаимодействие DirectWrite с GDI: можно преобразовать логический шрифт GDI в объект DirectWrite, получать сведения о выбранном шрифте из контекста устройства и выводить текст через bitmap render target на поверхность GDI. Это позволяет обновлять подсистему постепенно. Но при смешении API необходимо отдельно проверить измерение строки и её визуальное согласование с соседними надписями: одинаковый начальный x не означает одинаковый конец строки.
Воспроизводимый тест приложения должен включать несколько размеров текста, узкие и широкие буквы, кириллицу, диакритические знаки, цифры и текст с разными языками. Проверяйте не только прямой вывод на монитор, но и печать или экспорт, если продукт поддерживает эти сценарии. Зафиксируйте ожидаемые переносы и допустимое поведение при смене DPI. Это помогает обнаружить, когда обновление графического стека изменило макет, хотя файл шрифта остался прежним.
Чек-лист проверки
- Сверьте фактический файл и начертание, а не только название в списке шрифтов. - Уравняйте размер, масштаб интерфейса, межсимвольный интервал и ширину текстового поля. - Разделите дефект метрик (ширина, перенос, положение) и дефект растеризации (резкость, оттенок края). - Сравните один текст при одинаковой ширине контейнера и в одном просмотрщике PDF. - Для разработанного приложения запишите API, режим измерения, режим растеризации и настройки экспорта. - Проверьте критичные строки на фактическом устройстве и в конечном формате передачи.
Частые ошибки при сравнении
Менять сглаживание, ожидая исправить перенос. Оно влияет на изображение контура; сначала проверьте измерение и ширину поля.
Сравнивать два похожих, но разных файла. В системе могут сосуществовать статическое и вариативное начертания, дубликат шрифта или другая версия файла. Сверьте источник и свойства файла.
Считать PDF точной копией экрана. Экспорт и просмотр добавляют собственные этапы. Откройте обе версии в одном просмотрщике и при одном масштабе, а затем отдельно оцените файл, предназначенный для печати.
Оценивать только один размер. Округление и hinting заметнее на малом кегле; на крупном размере сильнее бросаются в глаза форма и сглаживание. Проверяйте диапазон размеров, которые реально используются.
Пытаться добиться совпадения через случайный межбуквенный интервал. Это маскирует причину и меняет рисунок строки. Сначала выясните, различаются ли режим измерения, шрифтовой файл или ширина набора.
Часто задаваемые вопросы
DirectWrite всегда делает строку шире, чем GDI?
Нет. Результат зависит от режима измерения, конкретного текста, параметров шрифта и ширины контейнера. Natural-режим может сохранить дробные значения ширины, а GDI-совместимые режимы DirectWrite предназначены для близких к GDI метрик. Проверяйте выбранные настройки, а не делайте вывод только по названию подсистемы.
ClearType отвечает за переносы слов?
Нет. ClearType относится к субпиксельной растеризации и влияет на отображение краёв букв. Перенос определяется шириной глифов, раскладкой текста, параметрами абзаца и доступной шириной строки. При диагностике эти причины полезно проверять отдельно.
Можно ли получить одинаковый набор в двух программах Windows?
Можно приблизить его, если приложения используют те же файлы шрифтов, размеры, ширины полей и совместимые режимы измерения. Полное совпадение всё равно зависит от обработки текста и экспорта. Для точной передачи фиксируйте конечный формат и проверяйте его в том виде, в каком его увидит получатель.
Что выбрать разработчику нового приложения?
Выбирайте по задаче. Естественные метрики и дробное позиционирование удобны для масштабируемого интерфейса и типографики, а GDI-совместимые режимы нужны, когда требуется близость к существующим надписям и сохранение измерений. Проверьте сценарии продукта на контрольных строках и укажите выбор явно.
Почему различие заметнее на маленьком кегле?
При малом размере шаг экранного пикселя занимает большую долю ширины штриха и промежутка. Округление и привязка к сетке поэтому сильнее меняют вид и размещение отдельных глифов. Если меняется именно перенос, дополнительно проверьте режим измерения и доступную ширину текстовой области.
Вывод
GDI и DirectWrite различаются не просто способом сглаживания: они могут измерять и размещать глифы по-разному. Чтобы понять, почему меняется строка, сравнивайте файл шрифта, параметры макета, режим измерения и конечный способ вывода по отдельности. Если вы создаёте собственный рукописный шрифт, соберите его в Fontgenerator и проверьте контрольные фразы в тех программах и форматах, где будете применять его.