这种方法是通过从预先制作的图像中复制字母来实现,而不是使用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而不是重新创建它们。如果不是,则可以更改代码以使用数组代替。