我正在尝试将一些文本渲染到 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);
where:
-
__fonts
is a 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
has SmoothingMode.AntiAlias
and TextRenderingHint.AntiAlias
set
-
context
is a 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
报告显示,渲染到图像后,该文本的高度为 122 像素(当边界框高 64 像素并且适合该框时)。事实上,在不强迫的情况下,while 循环迭代到 18pt,此时Graphics.MeasureCharacterRanges
返回一个合适的值。
跟踪日志摘录如下:
将字体大小减小到 24,因为大小为 193×122,限制为 212×64
将字体大小减小到 23,因为大小为 191×117,限制为 212×64
将字体大小减小到 22,因为大小为 200×75,限制为 212×64
将字体大小减小到 21,因为大小为 192×71,限制为 212×64
将字体大小减小到 20,因为大小为 198×68,限制为 212×64
将字体大小减小到 19,因为大小为 185×65,限制为 212×64
以 DIN-Black 18pt 书写 HESSELINK 的 VENNEGOOR,尺寸为 178×61,限制为 212×64
那么为什么是Graphics.MeasureCharacterRanges
给我一个错误的结果?如果循环停止在 21pt 左右,我可以理解它是字体的行高(如果我截图结果并在 Paint.Net 中测量它,这在视觉上会合适),但它比它应该做的要远得多因为,坦率地说,它返回了错误的该死的结果。