我怎样才能使上后台线程WriteableBitmap的文本,在Windows Phone 7的? [英] How can I render text on a WriteableBitmap on a background thread, in Windows Phone 7?

查看:182
本文介绍了我怎样才能使上后台线程WriteableBitmap的文本,在Windows Phone 7的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图呈现在Windows Phone 7应用程序上的位图文字。

I am trying to render text on a bitmap in a Windows Phone 7 application.

code,看起来或多或少像下面会正常工作时,它的主线程上运行:

Code that looks more or less like the following would work fine when it's running on the main thread:

public ImageSource RenderText(string text, double x, double y)
{
    var canvas = new Canvas();

    var textBlock = new TextBlock { Text = text };
    canvas.Children.Add(textBloxk);
    Canvas.SetLeft(textBlock, x);
    Canvas.SetTop(textBlock, y);

    var bitmap = new WriteableBitmap(400, 400);
    bitmap.Render(canvas, null);
    bitmap.Invalidate();
    return bitmap;
}

现在,因为我有渲染多个图像更复杂的东西,我想呈现在后台线程位图,以避免无响应的用户界面。

Now, since I have to render several images with more complex stuff, I would like to render the bitmap on a background thread to avoid an unresponsive UI.

当我使用的BackgroundWorker 这样做,构造为的TextBlock 引发 UnauthorizedAccessException 声称这是一个无效的跨线程访问。

When I use a BackgroundWorker to do so, the constructor for TextBlock throws an UnauthorizedAccessException claiming that this is an invalid cross-thread access.

我的问题是:我怎么能渲染上位的文本,而不阻塞UI

My question is: how can I render text on a bitmap without blocking the UI?


  • 请不要建议使用一个Web服务来进行呈现。我需要渲染大量的图像和带宽成本是不能接受我的需要,以及离线工作的能力,是一个主要的需求。

  • 解决方案并不一定必须使用 WriteableBitmap的 UI元素,如果有另一种方式来呈现文本

  • Please don't suggest using a web service to do the rendering. I need to render a large number of images and the bandwidth cost is not acceptable for my needs, and the ability to work offline is a major requirement.
  • The solution doesn't necessarily has to use WriteableBitmap or UIElements, if there is another way to render text.

修改

另一个想法:没有人知道是否应该可以运行在另一个线程的UI消息循环,然后有一个线程做的工作? (而不是使用的BackgroundWorker )?

Another thought: does anyone know if it should be possible to run a UI message loop in another thread, and then have that thread do the work? (instead of using a BackgroundWorker)?

编辑2

要考虑替代 WriteableBitmap的,我需要的是功能:

To consider alternatives to WriteableBitmap, the features I need are:


  • 绘制背景图片。

  • 测量给定的字体家庭内和尺寸(和preferably样式)的宽度和一个1行字符串的高度。无需换行。

  • 绘制一个1行字符串,用给定的字体,大小,样式,在给定的坐标。

  • 文本渲染应该支持透明背景。即你应该看到的字符之间的背景图像。

推荐答案

这个方法复制从pre制作的图片,而不是使用TextBlock的字母,它是基于我回答这个<一个href=\"http://stackoverflow.com/questions/3719750/best-way-to-get-a-glow-effect-windows-phone-7\">question.主要的限制是需要用于每种字体大小需要不同的图像。大小20字体大约需要150KB。

This method copies the letters from an pre-made image instead of using TextBlock, it's based on my answer to this question. The main limitation is requiring a different image for each font and size needed. A size 20 Font needed about 150kb.

使用 SpriteFont2 字体和XML规格文件导出您需要的尺寸。在code假定他们命名为FONTNAME字号巴纽和FONTNAME字号.XML它们添加到您的项目,并设置构建动作内容。在code也需要 WriteableBitmapEx

Using SpriteFont2 export the font and the xml metrics file in the sizes you require. The code assumes they're named "FontName FontSize".png and "FontName FontSize".xml add them to your project and set the build action to content. The code also requires 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是正确处理,您可以recolour它。在code呢,如果你画在大小,你没有加载但效果并不好缩放文本,可以使用更好的插值方法。

You need to call RegisterFont once to load the files then you call DrawString. It uses WriteableBitmapEx.Blit so if your font file has white text and a transparent background alpha is handled correctly and you can recolour it. The code does scale the text if you draw at a size you didn't load but the results aren't good, a better interpolation method could be used.

我试着从不同的线程图纸和这个工作在模拟器,你仍然需要建立在主线程中的WriteableBitmap的。我对你的情况的理解是,你想通过类似的映射应用程式如何运作,如果是这样的情况下重用旧WriteableBitmaps而不是重新创建他们的瓷砖滚动。如果不是code可以改变使用数组,而不是工作。

I tried drawing from a different thread and this worked in the emulator, you still need to create the WriteableBitmap on the main thread. My understanding of your scenario is that you want to scroll through tiles similar to how mapping apps work, if this is the case reuse the old WriteableBitmaps instead of recreating them. If not the code could be changed to work with arrays instead.

这篇关于我怎样才能使上后台线程WriteableBitmap的文本,在Windows Phone 7的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆