Мне нужно напечатать числа, в которых некоторые цифры в середине выделены увеличением размера и веса шрифта. В приведенном ниже примере подчеркивается 456
.

Шрифт и два используемых размера настраиваются пользователем.
Текущий код делает это, используя три вызова Graphics.DrawString(...)
.
Проблема, с которой я сталкиваюсь, заключается в том, что с большинством шрифтов я вижу проблемы размером 1 пиксель (по отношению к серой линии 456
сидит на дополнительный пиксель выше, чем другие цифры):

Я прикрепил отладочный дамп (формулы Боба Пауэлла) для различных шрифтов внизу моего поста. Другие методы дали аналогичные результаты.
Чтобы напечатать текст на общей базовой линии, необходимо рассчитать смещение базовой линии для определенного Font
. Я пробовал использовать три метода:
Сначала код MSDN: http://msdn.microsoft.com/en-us/library/xwf9s90b(v=vs.80).aspx
ascent = fontFamily.GetCellAscent(FontStyle.Regular);
ascentPixel = font.Size * ascent / fontFamily.GetEmHeight(FontStyle.Regular)
Во-вторых, код из: С помощью GDI +, какой самый простой подход для выравнивания текста (нарисованного в нескольких разных шрифтах) по общей базовой линии?
Наконец, код из сообщения Боба Пауэлла: http://www.bobpowell.net/formattingtext.htm
Вот мой метод рисования:
private void DrawOnBaseline(Graphics g, string text, FontWithBaseline fwb, Brush brush, float x, float y) {
g.DrawString(text, fwb.Font, brush, x, y - fwb.Baseline, StringFormat.GenericTypographic);
}
Где FontWithBaseline
просто связывает шрифт с соответствующим базовым расчетом:
public class FontWithBaseline {
private Font m_font;
private float m_baseline;
public FontWithBaseline(Font font) {
m_font = font;
m_baseline = CalculateBaseline(font);
}
public Font Font { get { return m_font; } }
public float Baseline { get { return m_baseline; } }
private static float CalculateBaseline(Font font) {
... // I've tried the three formulae here.
}
}
Я еще не экспериментировал с Graphics.TestRenderingHint
. Это волшебный соус?
Что мне не хватает? Есть ли альтернативный API, который я могу использовать, когда я вызываю вызов для рисования и предоставляет координату Y базовой линии?

Обновление 1
Я интерполировал свой код с помощью @LarsTech. Он делал одно немного другое; он добавил 0.5f
. Однако даже этот вариант не устраняет проблему. Вот код:
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
TryLarsTechnique(e);
}
private void TryLarsTechnique(PaintEventArgs e) {
base.OnPaint(e);
Graphics g = e.Graphics;
GraphicsContainer c = g.BeginContainer();
g.Clear(Color.White);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.TextRenderingHint = TextRenderingHint.AntiAlias;
Font small = new Font("Arial", 13, FontStyle.Regular, GraphicsUnit.Pixel);
Font large = new Font("Arial", 17, FontStyle.Bold, GraphicsUnit.Pixel);
int x = 100;
int y = 100;
x += DrawLars(g, "12.3", small, x, y);
x += DrawLars(g, "456", large, x, y);
x += DrawLars(g, "8", small, x, y);
g.EndContainer(c);
}
// returns width of text
private int DrawLars(Graphics g, string text, Font font, int x, int y) {
float offset = font.SizeInPoints /
font.FontFamily.GetEmHeight(font.Style) *
font.FontFamily.GetCellAscent(font.Style);
float pixels = g.DpiY / 72f * offset;
int numTop = y - (int)(pixels + 0.5f);
TextRenderer.DrawText(g, text, font, new Point(x, numTop), Color.Black, Color.Empty, TextFormatFlags.NoPadding);
return TextRenderer.MeasureText(g, text, font, Size.Empty, TextFormatFlags.NoPadding).Width;
}
Мне интересно, виноват ли указание размера шрифта с помощью GraphicsUnit.Pixel
. Возможно, есть способ найти предпочтительные размеры для любого конкретного шрифта?
Обновление 2
Я пытался указать размеры шрифта в пунктах вместо пикселей, и это также не полностью решает проблему. Обратите внимание, что использование только целых размеров точек не вариант в моем случае. Чтобы увидеть, возможно ли это, я попробовал это на Windows Wordpad. Размеры Используя 96 точек на дюйм (и 72 точки на дюйм по определению), 17px, 13px переводят в 12,75 и 9,75. Вот результат сравнения:

Обратите внимание, что меньшие шрифты имеют одинаковую высоту на уровне пикселей. Так что Wordpad каким-то образом удается исправить это без округления размеров шрифта до удобных значений.