gpt4 book ai didi

c# - GDI+ 在基线上绘制不同大小的文本存在 off-by-1px 问题

转载 作者:可可西里 更新时间:2023-11-01 09:10:21 26 4
gpt4 key购买 nike

我需要打印数字,通过增加字体大小和粗细来强调中间的一些数字。在下面的示例中,强调了 456

enter image description here

使用的字体和两种大小是用户可配置的。

当前代码使用对 Graphics.DrawString(...) 的三个调用来完成此操作。

我遇到的问题是,对于大多数字体,我看到偏移 1 像素的问题(相对于灰线,456 比其他数字高一个像素) :

enter image description here

我在帖子底部附上了一些针对各种字体的调试转储(Bob Powell 公式)。其他技术产生了类似的结果。

为了在公共(public)基线上打印文本,需要计算特定字体 的基线偏移量。我尝试使用三种技术:

首先是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)

二、代码来自:Using GDI+, what's the easiest approach to align text (drawn in several different fonts) along a common baseline?

最后,Bob Powell 的帖子中的代码:Formatting text on a common baseline.

这是我的绘制方法:

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 坐标?

enter image description here


更新 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 写字板上尝试了这个。尺寸 使用 96 dpi(根据定义每英寸 72 点),17px、13px 转换为 12.75 和 9.75。这是比较的输出:

enter image description here

请注意较小的字体在像素级别上的高度相同。因此,写字板设法在不将字体大小四舍五入为方便的值的情况下做到这一点。

最佳答案

您没有显示足够的代码来重现该问题,因此这里是一个使用您提供的 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));
}

这会产生:

enter image description here

关于c# - GDI+ 在基线上绘制不同大小的文本存在 off-by-1px 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9100051/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com