Этот метод копирует буквы из готового изображения вместо использования TextBlock, он основан на моем ответе на этот вопрос . Основное ограничение - это разные изображения для каждого шрифта и необходимого размера. Размер шрифта 20 требуется около 150 КБ.
Использование 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, поэтому, если ваш файл шрифта имеет белый текст и прозрачный фон альфа обрабатывается правильно, и вы можете перекрасить его. Код действительно масштабирует текст, если вы рисуете с размером, который вы не загрузили, но результаты не очень хорошие, можно использовать лучший метод интерполяции.
Я пробовал рисовать из другого потока, и это сработало в эмуляторе, вам все еще нужно создать WriteableBitmap в основном потоке. Насколько я понимаю, ваш сценарий заключается в том, что вы хотите прокручивать листы, похожие на то, как работают картографические приложения, если в этом случае используйте старые WriteableBitmaps вместо того, чтобы воссоздавать их. Если нет, то код можно изменить для работы с массивами.