Мне нужно напечатать числа, где некоторые цифры в середине подчеркиваются увеличением размера шрифта и веса. В приведенном ниже примере подчеркивается 456
.
Шрифт и два используемых размера настраиваются пользователем.
Текущий код делает это, используя три вызова Graphics.DrawString(...)
.
Проблема, с которой я сталкиваюсь, заключается в том, что с большинством шрифтов я вижу проблемы с одним пикселем (относительно серой линии, 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
Здесь мой метод draw:
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 каким-то образом справляется с этим, не округляя размеры шрифта до удобных значений.