此方法从预制图像中复制字母,而不是使用 TextBlock,它基于我对这个问题的回答。主要限制是需要为所需的每种字体和大小提供不同的图像。大小为 20 的字体大约需要 150kb。
使用SpriteFont2以您需要的大小导出字体和 xml 度量文件。代码假定它们被命名为“FontName FontSize”.png 和“FontName FontSize”.xml 将它们添加到您的项目并将构建操作设置为内容。该代码还需要WriteableBitmapEx。
public static class BitmapFont
{
private class FontInfo
{
public FontInfo(WriteableBitmap image, Dictionary<char, Rect> metrics, int size)
{
this.Image = image;
this.Metrics = metrics;
this.Size = size;
}
public WriteableBitmap Image { get; private set; }
public Dictionary<char, Rect> Metrics { get; private set; }
public int Size { get; private set; }
}
private static Dictionary<string, List<FontInfo>> fonts = new Dictionary<string, List<FontInfo>>();
public static void RegisterFont(string name,params int[] sizes)
{
foreach (var size in sizes)
{
string fontFile = name + " " + size + ".png";
string fontMetricsFile = name + " " + size + ".xml";
BitmapImage image = new BitmapImage();
image.SetSource(App.GetResourceStream(new Uri(fontFile, UriKind.Relative)).Stream);
var metrics = XDocument.Load(fontMetricsFile);
var dict = (from c in metrics.Root.Elements()
let key = (char) ((int) c.Attribute("key"))
let rect = new Rect((int) c.Element("x"), (int) c.Element("y"), (int) c.Element("width"), (int) c.Element("height"))
select new {Char = key, Metrics = rect}).ToDictionary(x => x.Char, x => x.Metrics);
var fontInfo = new FontInfo(new WriteableBitmap(image), dict, size);
if(fonts.ContainsKey(name))
fonts[name].Add(fontInfo);
else
fonts.Add(name, new List<FontInfo> {fontInfo});
}
}
private static FontInfo GetNearestFont(string fontName,int size)
{
return fonts[fontName].OrderBy(x => Math.Abs(x.Size - size)).First();
}
public static Size MeasureString(string text,string fontName,int size)
{
var font = GetNearestFont(fontName, size);
double scale = (double) size / font.Size;
var letters = text.Select(x => font.Metrics[x]).ToArray();
return new Size(letters.Sum(x => x.Width * scale),letters.Max(x => x.Height * scale));
}
public static void DrawString(this WriteableBitmap bmp,string text,int x,int y, string fontName,int size,Color color)
{
var font = GetNearestFont(fontName, size);
var letters = text.Select(f => font.Metrics[f]).ToArray();
double scale = (double)size / font.Size;
double destX = x;
foreach (var letter in letters)
{
var destRect = new Rect(destX,y,letter.Width * scale,letter.Height * scale);
bmp.Blit(destRect, font.Image, letter, color, WriteableBitmapExtensions.BlendMode.Alpha);
destX += destRect.Width;
}
}
}
您需要调用 RegisterFont 一次以加载文件,然后调用 DrawString。它使用 WriteableBitmapEx.Blit,因此如果您的字体文件包含白色文本并且正确处理了透明背景 alpha 并且您可以重新着色它。如果您以未加载的大小绘制但结果不佳,则代码会缩放文本,可以使用更好的插值方法。
我尝试从不同的线程绘图,这在模拟器中工作,您仍然需要在主线程上创建 WriteableBitmap。我对您的场景的理解是,您希望滚动浏览类似于地图应用程序工作方式的图块,如果是这种情况,请重用旧的 WriteableBitmaps 而不是重新创建它们。如果不是,则可以将代码更改为使用数组。