我遇到的问题是,当我使用Graphics.MeasureCharacterRanges方法测量字符串的宽度时,结果与显示的内容不匹配。
我发现这是由TextRenderingHint.ClearTypeGridFit引起的。设置此项后,文本将被绘制得更宽。如果未设置,则绘制文本与测量匹配。我要求启用此功能,因为它可确保以最高质量绘制字体。
我需要一种快速方法来评估字符串的宽度。唯一的选择是在图像上实际绘制字符串,检查颜色的像素吗?
这是MeasureCharacterRanges方法的错误还是我做错了什么?
NB。这个字体似乎特别糟糕。其他字体,其他Arial风格和其他尺寸的Arial似乎更准确。我写了一个工具来枚举所有字体/大小,这是迄今为止最大的差异。
以下代码获取测量值,绘制文本和测量的边界框。
Dim g As Graphics = Nothing
Dim text As String = "MSCI EMU Net"
Dim font As Font = New Font("Arial", 8, FontStyle.Regular)
Dim wordwrapwidth As Single = Single.MaxValue
g = Graphics.FromHwnd(IntPtr.Zero)
g.PageUnit = GraphicsUnit.Pixel
g.TextContrast = 2
g.TextRenderingHint = Drawing.Text.TextRenderingHint.ClearTypeGridFit
Dim ranges As System.Drawing.CharacterRange() = {New System.Drawing.CharacterRange(0, text.Length)}
Dim regions As System.Drawing.Region() = New System.Drawing.Region(0) {}
Dim STRFormat As StringFormat = StringFormat.GenericTypographic.Clone
STRFormat.SetTabStops(0, New Single() {72})
STRFormat.SetMeasurableCharacterRanges(ranges)
regions = g.MeasureCharacterRanges(text, font, New System.Drawing.RectangleF(0, 0, wordwrapwidth, Single.MaxValue), STRFormat)
Dim tempRectF As RectangleF = regions(0).GetBounds(g)
Dim textImage As New Bitmap(500, 100)
Dim textImageGraphics As Graphics = Graphics.FromImage(textImage)
textImageGraphics.TextContrast = 2
textImageGraphics.TextRenderingHint = Drawing.Text.TextRenderingHint.ClearTypeGridFit
textImageGraphics.Clear(Color.White)
textImageGraphics.DrawString(text, font, Brushes.Black, New Point(0, 0))
textImageGraphics.DrawRectangle(Pens.Red, Rectangle.Round(tempRectF))
PictureBox1.Image = textImage
如有任何问题或疑问,请告知我们。
答案 0 :(得分:1)
我无法告诉你GDI +内部会发生什么,但无论如何我都可以提供一些澄清。
基本上,如果您希望字符串与测量的宽度完全相同,则需要在相同的表面上绘制并使用相同的选项。
在原始代码中,Graphics.FromHwnd
用于测量,并在内部使用GdipCreateFromHWND
来创建绘图表面。相反,Graphics.FromImage
用于绘图,在内部使用GdipGetImageGraphicsContext
。即使Graphics
对象上的.NET属性看起来相同,但内部GDI +绘图表面仍然存在内部差异。
因此,为了简化您的解决方案,使用
就足够了Dim Im As New Bitmap(500, 100)
g = Graphics.FromImage(Im)
在我的Server 2008系统和Win7上工作正常,看起来像这样:
这不完全准确,红框与文字完全不符。这应该是预期的,因为您使用 StringFormat
标志测量并在没有的情况下绘制。
因此,为了改善测量,请使用以下代码行进行绘制:
textImageGraphics.DrawString(text, font, Brushes.Black, New Point(0, 0), STRFormat)
然后在两个操作系统上结果看起来都非常准确:
另外,在Me.CreateGraphics()
内部,您实际上可以使用Graphics.FromHwnd(IntPtr.Zero)
代替Control
。但它不会在这里解决问题。
这有帮助吗?
答案 1 :(得分:0)
解决方案是不使用
g = Graphics.FromHwnd(IntPtr.Zero)
如果用它替换它可以正常工作:
Dim resolution As Single = 96
Dim Im As New Bitmap(500, 100)
Im.SetResolution(resolution, resolution)
g = Graphics.FromImage(Im)
我不明白为什么。我已经对图形对象进行了比较,无法确定可以解释它的差异。
Bounty将会找到可以告诉我原因的人。