Scenario
I want to use Glyphs
on WP7 to create a line of text that is justified, i.e. touches the left and right border of the surrounding rectangle.
My solution
var gly开发者_运维百科phs = 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();
Problem and Question
The right side of the glyphs is not exactly touching the availableSize.Width
-Border but is some pixels off, and that looks weired when there are several lines of text stacked up.
What is wrong with my calculation?
This could be down to problems with floating point accuracy.
Generally speaking, every floating-point arithmetic operation introduces an error at least equal to the machine accuracy (i.e. the smallest number that, when added to 1.0, produces a floating-point result that is different from 1.0) into the result. This error is known as roundoff error. Roundoff errors are cumulative and sometimes dependent on the order of operations.
Instead of
double spaceAdvance = ((availableSize.Width - glyphs.DesiredSize.Width)
/ spaceCount + spaceWidth) / glyphs.FontRenderingEmSize * 100;
try moving the multiplication to the front, i.e.
double spaceAdvance = 100.0 * ((availableSize.Width - glyphs.DesiredSize.Width)
/ spaceCount + spaceWidth) / glyphs.FontRenderingEmSize;
Alternatively, you could also try
double spaceAdvance = (100.0 * (availableSize.Width - glyphs.DesiredSize.Width)
/ spaceCount + 100.0 * spaceWidth) / glyphs.FontRenderingEmSize;
Alternative proposal: You can use the RichTextBox control which supports "justify".
What about layout rounding?
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;
Also, you may want to experiment with ActualWidth instead of DesiredSize.Width
double spaceAdvance = ((availableSize.Width - glyphs.ActualWidth) /
spaceCount + spaceWidth) / glyphs.FontRenderingEmSize * 100.0;
精彩评论