Owe*_*ker 6 system.drawing gdi+ drawstring
我正在尝试将一些文本渲染到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());
Run Code Online (Sandbox Code Playgroud)
然后我使用以下行将文本呈现到我从文件系统中提取的图像:
g.DrawString(text, font, __brush, __textBoundingBox, fmt);
Run Code Online (Sandbox Code Playgroud)
哪里:
__fonts是一个PrivateFontCollection,PrivateFontCollection.GetFontBySize 是一个返回a的扩展方法 FontFamilyRectangleF __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);
}
Run Code Online (Sandbox Code Playgroud)
现在我有两个问题.
首先,文本有时会坚持通过在单词中插入换行符来进行换行,当它应该只是不适合并导致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,将
字体大小减小到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中截取结果并测量它,在视觉上合适,那么字体的行高),但它远远超过应该做的因为,坦率地说,它正在回归错误的结果.
您可以尝试删除以下行吗?
fmt.FormatFlags = StringFormatFlags.NoClip;
Run Code Online (Sandbox Code Playgroud)
允许显示字形的悬垂部分以及到达格式矩形之外的展开文本。默认情况下,到达格式矩形之外的所有文本和字形部分都会被剪掉。
这是我能想到的最好的办法:(