如何在另一个线程上渲染视觉效果

2024-02-05

我试图在另一个线程上渲染画布。这是我的尝试:

// returns path to exported image
private string exportToImage(double width, double height, Visual visual)
{
    var filename = string.Format(@"{0}.png", Guid.NewGuid());
    var tempFile = Path.Combine(tempDir, filename);
    Rect rect = new Rect(0, 0, width, height);
    RenderTargetBitmap rtb = new RenderTargetBitmap((int)rect.Right,
        (int)rect.Bottom, 96d, 96d, System.Windows.Media.PixelFormats.Default);

    Thread RENDER_THREAD = new Thread(() => 
    {
        this.Dispatcher.Invoke((Action)(() =>
        {
            rtb.Render(visual);
        }));
    });
    RENDER_THREAD.Start();

    //endcode as PNG
    BitmapEncoder pngEncoder = new PngBitmapEncoder();
    pngEncoder.Frames.Add(BitmapFrame.Create(rtb));

    //save to memory stream
    System.IO.MemoryStream ms = new System.IO.MemoryStream();

    pngEncoder.Save(ms);
    ms.Close();
    System.IO.File.WriteAllBytes(tempFile, ms.ToArray());
    return tempFile;
}

我没有收到任何错误,但渲染的结果是一个空图像。的实例是rtb在主线程和新线程中一样吗?

Edit: 这是我的最新尝试。

我在 MouseUp 事件上创建线程:

var curLayer = GetItemsPanel((canvasDataBinding.ItemContainerGenerator.ContainerFromIndex(Binding_LayersListView.SelectedIndex)));
Thread RASTERIZE_THREAD = new Thread(() => { exportToImage(curLayer.ActualWidth, curLayer.ActualHeight, curLayer); });
RASTERIZE_THREAD.Start();

这是新线程使用的我的方法:

void exportToImage(double width, double height, Visual visual)
{
    var filename = string.Format(@"{0}.png", Guid.NewGuid());
    var tempFile = Path.Combine(tempDir, filename);
    Rect rect = new Rect(0, 0, width, height);
    RenderTargetBitmap rtb = new RenderTargetBitmap((int)rect.Right,
        (int)rect.Bottom, 96d, 96d, System.Windows.Media.PixelFormats.Default);

    this.Dispatcher.Invoke(new Action(() =>
    {
        rtb.Render(visual);
    }));

    //endcode as PNG
    BitmapEncoder pngEncoder = new PngBitmapEncoder();
    pngEncoder.Frames.Add(BitmapFrame.Create(rtb));

    //save to memory stream
    System.IO.MemoryStream ms = new System.IO.MemoryStream();

    pngEncoder.Save(ms);
    ms.Close();
    System.IO.File.WriteAllBytes(tempFile, ms.ToArray());
}

那为什么它告诉我调用线程无法访问该对象,因为另一个线程拥有它 on rtb.Render(visual)?我没有从其他任何地方调用exportToImage,那么为什么调度程序与我创建的线程没有关联?

编辑: 我需要在 Dispatcher.Invoke() 内创建 RebderTargetBitmap。


这是一段代码,如何在线程中渲染相同内容并使其异步

整个想法是

  • 将视觉对象序列化为 xaml 字符串
  • 创建一个STA线程
  • 然后让线程反序列化相同的内容。
  • 在内容控件中托管反序列化的视觉效果,并进行排列等。
  • 最后但并非最不重要的一点是,渲染它(取自您的代码)

此代码不依赖于调度程序,因此它能够运行完全异步

    void exportToImage(double width, double height, Visual visual)
    {
        //this line can not be inside a thread because different thread owns the visual
        string visualData = XamlWriter.Save(visual);

        Thread t = new Thread(() =>
            {
                var filename = string.Format(@"{0}.png", Guid.NewGuid());
                var tempFile = System.IO.Path.Combine("c:\\", filename);

                Rect rect = new Rect(0, 0, width, height);

                //create a host control to host the visual
                ContentControl cc = new ContentControl();
                cc.Content = XamlReader.Parse(visualData);
                //call Arrange to let control perform layout (important)
                cc.Arrange(rect);

                RenderTargetBitmap rtb = new RenderTargetBitmap((int)rect.Right,
                    (int)rect.Bottom, 96d, 96d, System.Windows.Media.PixelFormats.Default);

                rtb.Render(cc);

                //endcode as PNG
                BitmapEncoder pngEncoder = new PngBitmapEncoder();
                pngEncoder.Frames.Add(BitmapFrame.Create(rtb));

                //save to memory stream
                System.IO.MemoryStream ms = new System.IO.MemoryStream();

                pngEncoder.Save(ms);
                ms.Close();
                System.IO.File.WriteAllBytes(tempFile, ms.ToArray());
            });
        //STA is necessary for XamlReader.Parse, and proper rendering
        t.SetApartmentState(ApartmentState.STA);
        t.Start();
    }

我已成功测试此代码以呈现一些测试视觉效果。但结果可能会因您的使用方式而异。据猜测,绑定和光栅图像可能存在一些问题,但在我的测试中,它的效果非常好。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在另一个线程上渲染视觉效果 的相关文章

  • Signalr 在生产服务器中总是陷入长轮询

    当我在服务器中托管应用程序时 它会检查服务器端事件并始终回退到长轮询 服务器托管环境为Windows Server 2012 R1和IIS 7 5 无论如何 我们是否可以解决这个问题 https cloud githubuserconten
  • 如何在 Unity 中从 RenderTexture 访问原始数据

    问题的简短版本 我正在尝试访问 Unity 中 RenderTexture 的内容 我一直在使用 Graphics Blit 使用自己的材质进行绘制 Graphics Blit null renderTexture material 我的材
  • 在 Xamarin Android 中将图像从 URL 异步加载到 ImageView 中

    我有一个包含多个项目的 ListView 列表中的每个项目都应该有一个与之关联的图像 我创建了一个数组适配器来保存每个列表项并具有我希望加载的图像的 url 我正在尝试使用 Web 请求异步加载图像 并设置图像并在加载后在视图中更新它 但视
  • FFMPEG Seeking 带来音频伪影

    我正在使用 ffmpeg 实现音频解码器 在读取音频甚至搜索已经可以工作时 我无法找到一种在搜索后清除缓冲区的方法 因此当应用程序在搜索后立即开始读取音频时 我没有任何工件 avcodec flush buffers似乎对内部缓冲区没有任何
  • Cygwin 下使用 CMake 编译库

    我一直在尝试使用 CMake 来编译 TinyXML 作为一种迷你项目 尝试学习 CMake 作为补充 我试图将其编译成动态库并自行安装 以便它可以工作 到目前为止 我已经设法编译和安装它 但它编译成 dll 和 dll a 让它工作的唯一
  • 使用 Microsoft Graph API 订阅 Outlook 推送通知时出现 400 错误请求错误

    我正在尝试使用 Microsoft Graph API 创建订阅以通过推送通知获取 Outlook 电子邮件 mentions 我在用本文档 https learn microsoft com en us graph api subscri
  • 如何在我的应用程序中使用 Windows Key

    Like Windows Key E Opens a new Explorer Window And Windows Key R Displays the Run command 如何在应用程序的 KeyDown 事件中使用 Windows
  • 为什么 POSIX 允许在只读模式下超出现有文件结尾 (fseek) 进行搜索

    为什么寻找文件结尾很有用 为什么 POSIX 让我们像示例中那样在以只读方式打开的文件中进行查找 c http en cppreference com w c io fseek http en cppreference com w c io
  • C# 中值类型和引用类型有什么区别? [复制]

    这个问题在这里已经有答案了 我知道一些差异 值类型存储在堆栈上 而引用类型存储在托管堆上 值类型变量直接包含它们的值 而引用变量仅包含对托管堆上创建的对象位置的引用 我错过了任何其他区别吗 如果是的话 它们是什么 请阅读 堆栈是一个实现细节
  • 跨多个控件共享事件处理程序

    在我用 C 编写的 Windows 窗体应用程序中 我有一堆按钮 当用户的鼠标悬停在按钮上时 我希望按钮的边框发生变化 目前我有以下多个实例 每个按钮一个副本 private void btnStopServer MouseEnter ob
  • 如何在 WPF RichTextBox 中跟踪 TextPointer?

    我正在尝试了解 WPF RichTextBox 中的 TextPointer 类 我希望能够跟踪它们 以便我可以将信息与文本中的区域相关联 我目前正在使用一个非常简单的示例来尝试弄清楚发生了什么 在 PreviewKeyDown 事件中 我
  • .Net Core / 控制台应用程序 / 配置 / XML

    我第一次尝试使用新的 ConfigurationBuilder 和选项模式进入 Net Core 库 这里有很多很好的例子 https docs asp net en latest fundamentals configuration ht
  • 是否有比 lex/flex 更好(更现代)的工具来生成 C++ 分词器?

    我最近将源文件解析添加到现有工具中 该工具从复杂的命令行参数生成输出文件 命令行参数变得如此复杂 以至于我们开始允许它们作为一个文件提供 该文件被解析为一个非常大的命令行 但语法仍然很尴尬 因此我添加了使用更合理的语法解析源文件的功能 我使
  • 可空属性与可空局部变量

    我对以下行为感到困惑Nullable types class TestClass public int value 0 TestClass test new TestClass Now Nullable GetUnderlyingType
  • 将应用程序从 Microsoft Access 迁移到 VB 或 C#.NET

    我目前正试图说服管理层需要将我们的应用程序之一移植到 NET 该应用程序已经发展成为 Access 中的一个庞然大物 SQL 后端 拥有 700 个链接表 650 个表单 子表单 130 个模块和 850 个查询 我几乎知道这样做的所有主要
  • 将日期参数传递给对 MVC 操作的 ajax 调用的安全方法

    我有一个 MVC 操作 它的参数之一是DateTime如果我通过 17 07 2012 它会抛出一个异常 指出参数为空但不能有空值 但如果我通过01 07 2012它被解析为Jan 07 2012 我将日期传递给 ajax 调用DD MM
  • 如何在内存中存储分子?

    我想将分子存储在内存中 这些可以是简单的分子 Methane CH4 C H bond length 108 7 pm H H angle 109 degrees But also more complex molecules like p
  • 在Linux中使用C/C++获取机器序列号和CPU ID

    在Linux系统中如何获取机器序列号和CPU ID 示例代码受到高度赞赏 Here http lxr linux no linux v2 6 39 arch x86 include asm processor h L173Linux 内核似
  • 方法参数内的变量赋值

    我刚刚发现 通过发现错误 你可以这样做 string s 3 int i int TryParse s hello out i returns false 使用赋值的返回值是否合法 Obviously i is but is this th
  • C++ 成员函数中的“if (!this)”有多糟糕?

    如果我遇到旧代码if this return 在应用程序中 这种风险有多严重 它是一个危险的定时炸弹 需要立即在应用程序范围内进行搜索和销毁工作 还是更像是一种可以悄悄留在原处的代码气味 我不打算writing当然 执行此操作的代码 相反

随机推荐