在Windows Phone 7中,如何在后台线程的WriteableBitmap上呈现文本?

如何解决在Windows Phone 7中,如何在后台线程的WriteableBitmap上呈现文本?

| 我正在尝试在Windows Phone 7应用程序中的位图上呈现文本。 在主线程上运行时,看起来或类似以下内容的代码可以正常工作:
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;
}
现在,由于必须渲染包含更多复杂内容的多个图像,因此我想在后台线程上渲染位图,以避免UI响应不灵敏。 当我使用
BackgroundWorker
这样做时,
TextBlock
的构造函数会抛出
UnauthorizedAccessException
,声称这是无效的跨线程访问。 我的问题是:如何在不阻止UI的情况下在位图上呈现文本? 请不要建议使用网络服务进行渲染。我需要渲染大量图像,带宽成本无法满足我的需求,并且脱机工作能力是主要要求。 如果存在另一种呈现文本的方法,则该解决方案不一定必须使用
WriteableBitmap
UIElements
。 编辑 另一个想法:是否有人知道是否应该可以在另一个线程中运行UI消息循环,然后让该线程来工作? (而不是使用
BackgroundWorker
)? 编辑2 为了考虑替代“ 4”,我需要的功能是: 绘制背景图像。 在给定字体和大小(最好是样式)的情况下,测量1行字符串的宽度和高度。无需自动换行。 在给定的坐标处绘制具有给定的字体系列,大小,样式的1行字符串。 文字渲染应支持透明背景。即您应该看到字符之间的背景图像。     

解决方法

这种方法是从预制图像中复制字母,而不是使用TextBlock,它基于我对此问题的回答。主要的限制是要求每种字体和大小都需要不同的图像。大小为20的字体大约需要150kb。 使用SpriteFont2以所需的大小导出字体和xml度量文件。该代码假定它们的名称为\“ FontName FontSize \”。png和\“ FontName FontSize \”。xml将它们添加到您的项目中,并将构建操作设置为content。该代码还需要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,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而不是重新创建它们。如果不是这样,则可以将代码更改为与数组一起使用。     ,我不确定这是否可以完全解决您的问题,但是我在漫画阅读器中使用了2种工具(我不会毫不客气地将其插入此处,但是我很想..如果您有提示,正在搜索它。它是\“ Amazing \”)。有时我需要将一堆图像拼接在一起。我使用Rene Schulte(和其他一些贡献者)的WriteableBitmapExtensions(http://writeablebitmapex.codeplex.com/)。我已经能够将图像的渲染/拼接卸载到后台线程,然后将生成的WriteableBitmap设置为UI线程上某些图像的源。 .NET映像工具(http://imagetools.codeplex.com/)是此领域中另一个崭露头角的地方。他们有一堆实用程序,用于保存/读取各种图像格式。他们也有一些较低的水平,我希望有一种简单的方法可以同时使用这两种方法(但没有)。 以上所有工作均在WP7中进行。 我猜主要的区别是这些工具不会使用XAML,而是直接写到图像(因此,您可能需要对文本和类似内容进行大小检测)。     ,UI元素的本质要求在UI线程上与它们进行交互。即使您可以在后台线程上创建它们,当您尝试将它们呈现到WriteableBitmap中时,您也会遇到类似的异常,即使这样它也允许您执行此操作,元素实际上并没有视觉表示,直到将它们添加到视觉树中。您可能需要使用通用的图像处理库,而不是使用UI元素。 也许您可以更广泛地描述您的情况,我们可能会为您提供更好的解决方案:)     ,首先,您确定要将其渲染为位图吗?如何生成带有图像的
Canvas
TextBlock
?   我需要渲染大量图像 我觉得这种生成会破坏手机性能。通常,对于位图维护,最好的方法是使用XNA。 XNA框架的某些部分在Silverlight项目方面做得很好。 (顺便说一句,更新后的Windows Phone开发人员工具将允许Silverlight和XNA共存于同一项目中) 我会退后一步,考虑一下此功能。这样的事情发展一个星期,然后以无法接受的表现告终,这会让我很难过。 编辑 据我了解,您需要某种形式的带有图片作为背景和消息的弹出窗口。 使用TextBlock制作画布,但将其隐藏。
<Canvas x:Name=\"userInfoCanvas\"  Height=\"200\" Width=\"200\" Visibility=\"Collapsed\">
    <Image x:Name=\"backgroundImage\"> </Image>
    <TextBlock x:Name=\"messageTextBlock\" Canvas.ZIndex=\"3> </TextBlock> <!--ZIndex set the order of elements  -->
</Canvas>
当您收到新消息时,请在后台线程上完成渲染时向用户显示“画布”(不透明动画会很好)。
messageTextBlock.Text = message;
backgroundImage.Source = new BitmapImage(renderedImage);
显然,这是更新问题。只能从UI线程更新UIelements,因此更新必须与Dispatcher一起排队
Dispatcher.BeginInvoke(DispatcherPriority.Background,messageUpdate);  //messageUpdate is an Action or anthing that can be infered to Delegate
PS。没有编译,这是更多的伪代码。     ,您可以在线程中绘制WriteableBitmap,但是您必须 在主UI线程中创建WriteableBitmap 在后台线程中绘制工作 在主UI线程中分配BitmapSource     ,我会同意Derek的回答:您正在尝试使用没有UI的UI控件。 如果要渲染位图,则需要坚持使用类在位图上绘制文本。 我认为Windows Phone 7具有.NET Compact Framework。 伪代码:
public Bitmap RenderText(string text,double x,double y)
{
   Bitmap bitmap = new Bitmap(400,400);

   using (Graphics g = new Graphics(bitmap))
   {
      using (Font font = SystemFonts....)
      {
         using (Brush brush = new SolidColorBrush(...))
         {
            g.DrawString(text,font,brush,new Point(x,y));
         }
      }
   }

   return bitmap;
}
    

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-