我有一个改变大小的图像,我想知道我应该使用哪种字体大小来适应动态变化的大小。
如您所知,有一个Graphics.MeasureString
方法,它计算字符串的大小。一种可能的方法是测量每种字体大小,直到找到最合适的字体,但是由于我需要在一秒钟内渲染很多帧,因此对性能的影响太大了。
给定特定的图像宽度,是否有更有效的方法来查找字体大小?
最佳答案
首先,我很确定没有不使用 Graphics.MeasureString()
的方法。 .至少,您必须分析 GDI+ 字体渲染代码的重要部分,才能估计最终字体大小 since it uses its own renderer .
幸运的是,有一些方法可以大大减少 MeasureString()
的数量。每帧调用到一个小常数 (甚至为零),具体取决于您使用的字体。
等宽字体
如果你使用等宽字体,事情很简单:
n
不同的字体大小。 MeasureString()
的来电次数: n
启动期间的次数,0
每帧次数。比例(可变间距)字体
如果您使用具有可变字符大小的比例字体,事情会变得更加复杂。如前言所述,难免调用
MeasureString()
;但是,您可以 显着减少所需的调用次数到一个小常数 ,通过计算和改进估计。一般算法是:
max
) 字体大小。 max
测量您的字符串字体大小。 s
可用于计算估计的字体大小:est = s * max
. est
,请检查极端情况并稍微调整字体大小还不是最优的。 一个实现可能如下所示:
public Font GetFont(string str, Graphics g, int imgWidth, int imgHeight)
{
// Measure with maximum sized font
var baseSize = g.MeasureString(str, _fontCache[_maxFontSize]);
// Downsample to actual image size
float widthRatio = imgWidth / baseSize.Width;
float heightRatio = imgHeight / baseSize.Height;
float minRatio = Math.Min(widthRatio, heightRatio);
int estimatedFontSize = (int)(_maxFontSize * minRatio);
// Make sure the precomputed font list is always hit
if(estimatedFontSize > _maxFontSize)
estimatedFontSize = _maxFontSize;
else if(estimatedFontSize < _minFontSize)
estimatedFontSize = _minFontSize;
// Make sure the estimated size is not too large
var estimatedSize = g.MeasureString(str, _fontCache[estimatedFontSize]);
bool estimatedSizeWasReduced = false;
while(estimatedSize.Width > imgWidth || estimatedSize.Height > imgHeight)
{
if(estimatedFontSize == _minFontSize)
break;
--estimatedFontSize;
estimatedSizeWasReduced = true;
estimatedSize = g.MeasureString(str, _fontCache[estimatedFontSize]);
++counter;
}
// Can we increase the size a bit?
if(!estimatedSizeWasReduced)
{
while(estimatedSize.Width < imgWidth && estimatedSize.Height < imgHeight)
{
if(estimatedFontSize == _maxFontSize)
break;
++estimatedFontSize;
estimatedSize = g.MeasureString(str, _fontCache[estimatedFontSize]);
}
// We increase the size until it is larger than the image, so we need to go back one step afterwards
if(estimatedFontSize > _minFontSize)
--estimatedFontSize;
}
return _fontCache[estimatedFontSize];
}
可惜网上各种C#编译器都不支持GDI+,不过我上传了self-contained sample program as a Gist .该程序测试了各种不同的图像大小,同时记录了对 MeasureString()
的调用次数。 .MeasureString()
的来电次数: 0
启动期间的次数,2
或 3
每帧次数。因此,(在实践中)这个算法有 恒定复杂性 并且比线性方法更有效,同时它仍然可以找到最佳的整数字体大小。
这种方法可以通过添加额外的检查来进一步优化,以便保存另外一个或两个
MeasureString()
调用,如果特定的字体和字符集允许的话。备注 :
MeasureString()
的数量。叫小。 n
Font
对象并将它们放入 _fontCache
列表,为方便起见。从性能的角度来看,这可能没有必要;您可能想要测量分配 Font
的开销目的。 max
.升级也是可能的,但您可能会失去精度。 m
可能的字符串,缓存其计算的字体大小可能会有所帮助。 关于c# - 计算字体大小以使文本适合特定宽度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62608763/