Graphics.MeasureString возвращает значения, отличные от Win32 GetTextExtent

Я пытался найти метод в C# для измерения размера строки. стандартный метод для измерения строки в Win32 заключается в использовании GetTextExtent. Настоящая цель - найти ширину и высоту в среднем символа шрифта. Стандартный метод определения средней ширины символа начинается с получения ширины всех буквенных символов и деления на 52:

size = dc.GetTextExtent(
       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52);
averageWidth = size / 52;

У Microsoft есть страница, на которой перечислены средняя ширина символа для некоторых размеров шрифтов при определенных настройках DPI, и я подтвердил их своими собственными вызовами GetTextExtent.

  • Тахома 8pt, 96dpi: 13x6 пикселей
  • Тахома 9pt, 96dpi: 14x7 пикселей
  • Segoe UI 9 пунктов, 96 точек на дюйм: 15x7 пикселей

Теперь я хочу выполнить те же вычисления в .NET WinForms. Используя Graphics.MeasureString (), я придумываю код:

public static SizeF GetAvgCharSizeF(Graphics g, Font font)
{
   String s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

   SizeF textSize = g.MeasureString(s, font);

   float baseUnitX = (textSize.Width / s.Length);
   float baseUnitY = textSize.Height;

   return new SizeF(baseUnitX, baseUnitY);
}

К сожалению, значения не соответствуют известным, принятым и истинным значениям:

  • Тахома 8pt, 96dpi: 14x6 пикселей (14,21x6,09 пикселей)
  • Тахома 9pt, 96dpi: 16x7 пикселей (15,98x6,85 пикселей)
  • Segoe UI 9pt, 96 точек на дюйм: 17x7 пикселей (17,46x6,91 пикселей)

Средняя ширина символов в порядке, но высота символов слишком велика примерно на 13%. Я предполагаю, что дополнительная высота связана с разницей в классификации высоты, которая была изменена для включения восходящих и нисходящих элементов. Если измерительная струна была слишком высокой, я попытался изменить ее с:

String s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

к

String s = "acemnorsuvwxyz";

думая, что теперь веревка не такая высокая, и поэтому измеренная высота должна быть короче. Нет, он возвращает точный ту же высоту, что и версия строки, которая включала восходящие и нисходящие элементы (хотя средняя ширина немного больше).

Что может быть причиной этого и можно ли получить среднюю высоту символа, что можно сделать со средней высотой текста, чтобы она соответствовала принятым значениям, возвращаемым GetTextExtent?

Примечание. Несмотря на то, что стандартной практикой получения средней высоты символа является использование GetTextMetrics, высота, возвращаемая GetTextExtents, возвращает то же значение.

Вы пробовали TextRenderer.MeasureText?

Martin Plante 24.12.2008 06:40
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
1
4 854
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я подозреваю, что это связано с тем, что механизм визуализации текста в .NET отличается. Возможно, вы захотите найти различия между GDI и GDI +. Все может снова измениться для вас, если вы вызовете метод Application.SetCompatibleTextRenderingDefault(<bool>) с параметром true или false (я считаю, что значение по умолчанию истинно).

В общем, если вы рисуете с помощью Windows API, измеряйте с помощью Windows API, а если вы рисуете с помощью .NET, измеряйте с помощью .NET.

Стандартные положения и размеры элементов управления выражаются в терминах «средний размер символа с высотой». Если средняя ширина и высота меняются в зависимости от того, кто измеряет, вы теряете стандарт.

Ian Boyd 15.10.2008 18:19

Я понял, что действительно существует разница между текстом Graphics.MeasureString и GDI. Проблема была настолько серьезной, что, начиная с .NET Framwork 2.0, Microsoft переключила все в .NET на использование GDI для рендеринга текста. Вот что такое класс TextRenderer. Он содержит два метода (MeasureString и DrawString), которые просто вызывают GDI. А поскольку GDI продолжает улучшаться (скорость, лигатуры и т. д.), TextRenderer является предпочтительным способом визуализации текста в .NET. Graphics.DrawString мертв и существует только для совместимости.

Ian Boyd 16.11.2011 19:58

Другие вопросы по теме