我正在将文本绘制到屏幕外的位图。不幸的是,文本没有正确地左对齐(请参见下图)。文本应触摸左边缘(蓝线),但偏离几个像素。距离随着文字大小而增加。
如何摆脱这个距离?
我正在使用.NET Framework 4.6.1。但这似乎是我不了解的一般性GDI +问题。
用于生成示例的代码:
using System.Drawing;
using System.Drawing.Imaging;
namespace LeftAlignment
{
class Program
{
static void Main(string[] args)
{
const int LeftMargin = 10;
// create off-screen bitmap
using (Bitmap bitmap = new Bitmap(300, 100))
{
// create graphics context
using (Graphics graphics = Graphics.FromImage(bitmap))
{
// clear bitmap
graphics.FillRectangle(Brushes.White, 0, 0, bitmap.Width, bitmap.Height);
// draw border and left margin
graphics.DrawRectangle(Pens.Gray, new Rectangle(0, 0, bitmap.Width - 1, bitmap.Height - 1));
graphics.DrawLine(Pens.Blue, LeftMargin, 8, LeftMargin, 92);
// draw string at 24 pt
Font font = new Font("Arial", 24);
graphics.DrawString("Cool water", font, Brushes.Black, LeftMargin, 8);
// draw string at 36 pt
font = new Font("Arial", 36);
graphics.DrawString("Cool water", font, Brushes.Black, LeftMargin, 44);
}
// save result as PNG
bitmap.Save("alignment.png", ImageFormat.Png);
}
}
}
}
答案 0 :(得分:2)
传说中,Microsoft在GDI +中添加了填充,以使控件的实现更加容易。旧的GDI并没有这个问题。
当Microsoft意识到这是一个错误时,他们添加了TextRenderer class来绕过GDI +,并使用更好的GDI实现。
假设填充物在左侧为1/6 em,在右侧为1/4 em。
您有两个选择:
使用TextRenderer.DrawText。但是,它是 Windows窗体的一部分。因此,.NET Standard和.NET Core均不可用。
使用Graphics.DrawString和魔术选项StringFormat.GenericTypographic。它神奇地删除了填充。
另请参阅:
答案 1 :(得分:0)
基于@ChrisW提供的链接,我创建了一个改进的版本(请参见下文)。它使用MeasureCharacterRanges
来度量DrawString
添加的填充。结果看起来黄油很多:
如您所见,它并不完美。蓝线和字母“ C”之间仍然存在一些空白,因为所测量的矩形包括所谓的左侧轴承,即两个字符之间添加的空白左侧。 / p>
所以我仍在寻找更好的解决方案。可能可以计算方位角,并减去测得的填充量减去一半的方位角。希望它可以在.NET Standard 2.0中实现...
顺便说一句:我已经测量了几种字体,字体样式,字体大小和分辨率。看起来填充是固定的。可以计算为:
填充= 0.002312554×字体大小×分辨率
(以像素为单位的填充,以pt为单位的字体大小,以像素/英寸为单位的分辨率)
举个例子:对于24pt字体和96dpi的图形分辨率,填充为5.33像素。
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
namespace LeftAlignment
{
class Program
{
static void ImprovedDrawString(Graphics graphics, string text, Font font, float x, float y)
{
// measure left padding
StringFormat sf = new StringFormat(StringFormatFlags.NoClip);
sf.SetMeasurableCharacterRanges(new CharacterRange[] { new CharacterRange(0, 1) });
Region[] r = graphics.MeasureCharacterRanges(text, font, new RectangleF(0, 0, 1000, 100), sf);
float leftPadding = r[0].GetBounds(graphics).Left;
// draw string
sf = new StringFormat(StringFormatFlags.NoClip);
graphics.DrawString(text, font, Brushes.Black, x - leftPadding, y, sf);
}
static void Main(string[] args)
{
const int LeftMargin = 10;
const string Text = "Cool water";
// create off-screen bitmap
using (Bitmap bitmap = new Bitmap(300, 100))
{
// create graphics context
using (Graphics graphics = Graphics.FromImage(bitmap))
{
// enable high-quality output
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
// clear bitmap
graphics.FillRectangle(Brushes.White, 0, 0, bitmap.Width, bitmap.Height);
// draw border and left margin
graphics.DrawRectangle(Pens.Gray, new Rectangle(0, 0, bitmap.Width - 1, bitmap.Height - 1));
graphics.DrawLine(Pens.Blue, LeftMargin, 8, LeftMargin, 92);
// draw string at 24 pt
Font font = new Font("Arial", 24);
ImprovedDrawString(graphics, Text, font, LeftMargin, 8);
// draw string at 36 pt
font = new Font("Arial", 36);
ImprovedDrawString(graphics, Text, font, LeftMargin, 44);
}
// save result as PNG
bitmap.Save("alignment.png", ImageFormat.Png);
}
}
}
}