我需要打印数字,通过增加字体大小和重量来强调中间的某些数字。在下面的示例中,强调了456
。
使用的字体和两种尺寸是用户可配置的。
当前代码使用对Graphics.DrawString(...)
的三次调用来执行此操作。
我遇到的问题是,对于大多数字体,我看到的是1像素的问题(相对于灰线,456
比其他数字高出一个额外的像素):
我在帖子的底部为各种字体添加了一些调试转储(Bob Powell公式)。其他技术产生了类似的结果。
为了在共同基线上打印文本,需要计算特定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)
最后,鲍勃鲍威尔的帖子代码: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
只是将Font与其各自的基线计算相关联:
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
我尝试用Points指定字体大小而不是像素,这也不能完全解决问题。请注意,在我的情况下,仅使用整点大小不是一个选项。要查看这是否可行,我在Windows Wordpad上尝试了这个。尺寸使用96 dpi(根据定义为每英寸72点),17px,13px转换为12.75和9.75。这是比较的输出:
请注意较小字体在像素级别的高度是多少。因此,Wordpad以某种方式设法使这个更正,而不会将字体大小舍入到方便的值。
答案 0 :(得分:5)
您没有显示足够的代码来重现问题,所以这里有一个使用您提供的Bob Powell示例的工作示例。
仅限演示代码:
private void panel1_Paint(object sender, PaintEventArgs e) {
e.Graphics.Clear(Color.White);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
string[] numbers = new string[] { "1", "2", ".", "3", "4", "5", "6", "8" };
int x = 10;
int y = 30;
foreach (string num in numbers) {
Font testFont;
if (num == "4" || num == "5" || num == "6")
testFont = new Font("Arial", 16, FontStyle.Bold);
else
testFont = new Font("Arial", 11, FontStyle.Regular);
float offset = testFont.SizeInPoints /
testFont.FontFamily.GetEmHeight(testFont.Style) *
testFont.FontFamily.GetCellAscent(testFont.Style);
float pixels = e.Graphics.DpiY / 72f * offset;
int numTop = y - (int)(pixels + 0.5f);
TextRenderer.DrawText(e.Graphics, num, testFont, new Point(x, numTop),
Color.Black, Color.Empty, TextFormatFlags.NoPadding);
x += TextRenderer.MeasureText(e.Graphics, num, testFont,
Size.Empty, TextFormatFlags.NoPadding).Width;
}
e.Graphics.DrawLine(Pens.Red, new Point(5, y + 1), new Point(x + 5, y + 1));
}
这会产生:
答案 1 :(得分:2)
可能问题是您在pixels
中指定字体大小,而偏移量在points
中计算并转换回pixels
。这可能会引入各种各样的不精确。
尝试在points
中指定字体大小,看看它是否有效。
答案 2 :(得分:1)
当Graphics.TextRenderingHint
设置为使用网格拟合时,缩放的TrueType字体的实际度量(以像素为单位)由GDI +通过搜索字体VDMX table确定,而不是简单地缩放和舍入其设计指标。这就是我在反汇编中逐步浏览Graphics.DrawString所得到的。