【发布时间】:2018-11-11 06:38:09
【问题描述】:
我正在尝试将一些文本呈现到 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是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);
}
现在我有两个问题。
首先,文本 sometimes 坚持通过在单词中插入换行符来换行,而此时它不适合并导致 while 循环再次递减。我不明白为什么Graphics.MeasureCharacterRanges 认为它不应该在一个单词中自动换行时它适合这个框。无论使用何种字符集(我用拉丁字母单词以及 Unicode 范围的其他部分,如西里尔文、希腊文、格鲁吉亚文和亚美尼亚文),都会表现出这种行为。我应该使用某些设置来强制 Graphics.MeasureCharacterRanges 仅在空白字符(或连字符)处自动换行吗?这第一个问题和post 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
HESSELINK 的 VENNEGOOR 用 DIN-Black 在 18pt 处书写,尺寸为 178×61,限制为 212×64
那么为什么Graphics.MeasureCharacterRanges 给我一个错误的结果?我可以理解它是,比如说,如果循环在 21pt 附近停止时字体的行高(如果我截取结果并在 Paint.Net 中测量它,这在视觉上很合适),但它比它应该做的要远得多因为,坦率地说,它返回了错误的结果。
【问题讨论】:
-
+1 是我在一段时间内看到的记录最多的问题之一!
标签: gdi+ system.drawing drawstring