我正在尝试将一些文本呈现到 Web 窗体应用程序中图像的特定部分。文本将由用户输入,所以我想改变字体大小以确保它适合边界框。
我的代码在我的概念验证实现中做得很好,但我现在正在尝试对设计器的资产进行测试,这些资产更大,我得到了一些奇怪的结果。
我正在运行大小计算,如下所示:
StringFormat fmt = new StringFormat();
fmt.Alignment = StringAlignment.Center;
fmt.LineAlignment = StringAlignment.Near;
fmt.FormatFlags = StringFormatFlags.NoClip;
fmt.Trimming = StringTrimming.None;
int size = __startingSize;
Font font = __fonts.GetFontBySize(size);
while (GetStringBounds(text, font, fmt).IsLargerThan(__textBoundingBox))
{
context.Trace.Write("MyHandler.ProcessRequest",
"Decrementing font size to " + size + ", as size is "
+ GetStringBounds(text, font, fmt).Size()
+ " and limit is " + __textBoundingBox.Size());
size--;
if (size < __minimumSize)
{
break;
}
font = __fonts.GetFontBySize(size);
}
context.Trace.Write("MyHandler.ProcessRequest", "Writing " + text + " in "
+ font.FontFamily.Name + " at " + font.SizeInPoints + "pt, size is "
+ GetStringBounds(text, font, fmt).Size()
+ " and limit is " + __textBoundingBox.Size());
然后,我使用以下行将文本渲染到我从文件系统中提取的图像上:
g.DrawString(text, font, __brush, __textBoundingBox, fmt);
在哪里:
__fonts
是一个PrivateFontCollection
,PrivateFontCollection.GetFontBySize
是一个扩展方法,它返回一个FontFamily
RectangleF __textBoundingBox = new RectangleF(150, 110, 212, 64);
int __minimumSize = 8;
int __startingSize = 48;
Brush __brush = Brushes.White;
int size
从 48 开始并在该循环内递减Graphics g
有SmoothingMode.AntiAlias
并TextRenderingHint.AntiAlias
设置context
是 a (这是 an方法的System.Web.HttpContext
摘录)ProcessRequest
IHttpHandler
其他方法是:
private static RectangleF GetStringBounds(string text, Font font,
StringFormat fmt)
{
CharacterRange[] range = { new CharacterRange(0, text.Length) };
StringFormat myFormat = fmt.Clone() as StringFormat;
myFormat.SetMeasurableCharacterRanges(range);
using (Graphics g = Graphics.FromImage(new Bitmap(
(int) __textBoundingBox.Width - 1,
(int) __textBoundingBox.Height - 1)))
{
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
Region[] regions = g.MeasureCharacterRanges(text, font,
__textBoundingBox, myFormat);
return regions[0].GetBounds(g);
}
}
public static string Size(this RectangleF rect)
{
return rect.Width + "×" + rect.Height;
}
public static bool IsLargerThan(this RectangleF a, RectangleF b)
{
return (a.Width > b.Width) || (a.Height > b.Height);
}
现在我有两个问题。
首先,文本有时会坚持通过在单词中插入换行符来换行,而此时它不适合并导致 while 循环再次递减。我不明白为什么Graphics.MeasureCharacterRanges
当它不应该在一个单词中自动换行时,它会认为它适合盒子。无论使用何种字符集(我用拉丁字母单词以及 Unicode 范围的其他部分,如西里尔文、希腊文、格鲁吉亚文和亚美尼亚文),都会表现出这种行为。我应该使用一些设置来强制Graphics.MeasureCharacterRanges
只在空白字符(或连字符)处换行吗?第一个问题与2499067 后相同。
其次,在放大到新的图像和字体大小时,Graphics.MeasureCharacterRanges
给了我很大的高度。我在其中RectangleF
绘制对应于图像的视觉明显区域,因此我可以很容易地看到文本何时减少超过必要。然而,当我给它传递一些文本时,这个GetBounds
电话给我的高度几乎是它实际占用的两倍。
使用反复试验设置__minimumSize
强制退出 while 循环,我可以看到 24pt 文本适合边界框,但Graphics.MeasureCharacterRanges
报告该文本的高度,一旦渲染到图像,是 122px(当边界盒子高 64 像素,适合该盒子)。事实上,在不强制的情况下,while 循环迭代到 18pt,此时Graphics.MeasureCharacterRanges
返回一个合适的值。
跟踪日志摘录如下:
将字体大小减小到 24,因为大小为 193×122,限制为 212 ×
64
是 212×64
将字体大小递减为 21,大小为 192×71,限制为 212×64
字体大小递减为 20,大小为 198×68,限制为 212×64
字体大小递减为 19,大小为 185 ×65,限制为 212×64
将 HESSELINK 的 VENNEGOOR 写入 DIN-Black 中 18pt,尺寸为 178×61,限制为 212×64
那么为什么Graphics.MeasureCharacterRanges
给我一个错误的结果呢?我可以理解它是,例如,如果循环在 21pt 附近停止时字体的行高(如果我截取结果并在 Paint.Net 中测量它,这在视觉上很合适),但它比它应该做的要远得多因为,坦率地说,它返回了错误的结果。