Silverlight:字形宽度

29

场景

我想在WP7上使用 Glyphs 创建一行文本,使其两端对齐,即触碰到周围矩形的左右边框。

我的解决方案

var glyphs = new Glyphs();
glyphs.FontUri = new Uri("/MyAssembly;component/MyPath/MyFont.ttf", UriKind.Relative);
glyphs.FontRenderingEmSize = 20;
glyphs.Fill = new SolidColorBrush(Colors.Red);

// measue width of space
glyphs.UnicodeString = " ";
glyphs.Measure(availableSize);
double spaceWidth = glyphs.DesiredSize.Width;
glyphs.InvalidateMeasure();

// setup justified text
string text = "Lorem Ipsum is dummy text of the printing and typesetting industry.";
int spaceCount = 10; // number of spaces in above text

glyphs.UnicodeString = text;
glyphs.Measure(availableSize); // now DesiredSize.Width = width of left aligned text

// I suspect my error to be in this formula:
double spaceAdvance = ((availableSize.Width - glyphs.DesiredSize.Width) 
                       / spaceCount + spaceWidth) / glyphs.FontRenderingEmSize * 100;
string spaceAdvanceString = String.Format(",{0};", spaceAdvance);

var indices = new StringBuilder();
foreach (char c in text)
{
    if (c == ' ')   indices.Append(spaceAdvanceString);
    else            indices.Append(';');
}
glyphs.Indices = indices.ToString();

问题和疑问

字形的右侧与availableSize.Width-边界没有完全接触,而是有一些像素偏离,当有多行文本堆叠在一起时,这看起来很奇怪。

我的计算有什么问题吗?


2
您已经验证了(spaceCount * spaceWidth) + <widthOf>(text.Replace(" ", "") == <widthOf>(text)吗? 我所知道的少量排版技巧是,您可以应用各种技巧使其看起来均匀,并在可能的情况下对其进行像素对齐。 - Albin Sunnanbo
@Albin:不,它们不相等!不幸的是,这似乎只解释了部分“错误”,但它已经对我有所帮助。 - Tilo
3个回答

2

这可能是由于浮点数精度问题造成的。

总的来说,每次浮点数算法操作都会引入一个误差,至少等于机器精度(即当加到1.0时产生与1.0不同的浮点结果的最小数字)。这个误差被称为舍入误差。舍入误差是累积的,有时取决于操作的顺序。

不要使用

double spaceAdvance = ((availableSize.Width - glyphs.DesiredSize.Width)
         / spaceCount + spaceWidth) / glyphs.FontRenderingEmSize * 100;

尝试将乘法移到前面,即

double spaceAdvance = 100.0 * ((availableSize.Width - glyphs.DesiredSize.Width)
         / spaceCount + spaceWidth) / glyphs.FontRenderingEmSize;

另外,你也可以尝试

double spaceAdvance = (100.0 * (availableSize.Width - glyphs.DesiredSize.Width)
         / spaceCount + 100.0 * spaceWidth) / glyphs.FontRenderingEmSize;

非常好的观点,但不幸的是,这似乎对视觉外观没有影响。我进行了一些操作顺序的实验,并发现在这种情况下的典型数字中,结果在前十二个小数位上相等,这意味着舍入误差占据了一个像素的百万分之一或更少 - 这取决于字体渲染 em 大小。 - Tilo

1

关于布局四舍五入怎么样?

var glyphs = new Glyphs();
glyphs.FontUri = new Uri("/MyAssembly;component/MyPath/MyFont.ttf", UriKind.Relative);
glyphs.FontRenderingEmSize = 20;
glyphs.Fill = new SolidColorBrush(Colors.Red);
glyphs.UseLayoutRounding = false;

此外,您可能想尝试使用ActualWidth而不是DesiredSize.Width 进行实验。

double spaceAdvance = ((availableSize.Width - glyphs.ActualWidth) / 
             spaceCount + spaceWidth) / glyphs.FontRenderingEmSize * 100.0;

1

另一种建议:您可以使用支持“对齐”的RichTextBox控件。


RichTextBox在我提问时还不可用,但现在可能是一个很好的解决方法。与此同时,我学会了如何使字形表现出我想要的方式。如果有人需要详细信息,请与我联系。Albin的评论是最大的帮助。Chris对问题的搜索有着非常好的“感觉”,我建议每个查看这个问题的人仔细阅读他的答案,但不幸的是他在我的特殊情况下错过了真正的问题。 - Tilo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接