如何从另一个线程生成调色板图像到 WPF UI 线程? [英] How can I yield a palette image from another thread to WPF UI thread?

查看:57
本文介绍了如何从另一个线程生成调色板图像到 WPF UI 线程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想异步创建/操作基于调色板的图像并将该图像生成给 WPF UI 线程.

I want to create/manipulate a palette based image asynchronously and yield that image to the WPF UI thread.

为了从另一个线程向 UI 线程生成一个可冻结的对象,需要冻结该对象.

In order to yield a freezable object from another thread to the UI thread it's required to freeze the object.

但是,当图像基于调色板时,我无法冻结图像.BitmapPalette 派生自 DispatcherObject,所以我无法冻结它.

However, I'm not able to freeze the image when it is palette based. The BitmapPalette derives from DispatcherObject, so I cannot freeze it.

如何将调色板图像从另一个线程生成到 WPF UI 线程?

How can I yield a palette image from another thread to WPF UI thread?

示例代码如下:

internal static Task<BitmapSource> GetImageAsync()
{
  return Task.Run<BitmapSource>(() =>
  {
    BitmapImage bi = new BitmapImage();

    bi.BeginInit();
    bi.UriSource = new Uri(@"test.jpg");
    bi.DecodePixelWidth = 16;
    bi.EndInit();

    FormatConvertedBitmap fcb = new FormatConvertedBitmap(bi, PixelFormats.Indexed2, new BitmapPalette(bi, 4), 1);

    // Required for the UI thread to be able to use the bitmap.
    // However, fcb.CanFreeze is false, though.
    fcb.Freeze();

    return fcb;
  });
}

...这是我收到的警告(错误):

... and here's the warning (error) I get:

System.Windows.Freezable Warning:
  2 : CanFreeze is returning false because a DependencyProperty
      on the Freezable has a value that is a DispatcherObject
      with thread affinity


@克莱门斯:


@Clemens:

这是我想出的解决方法.它非常类似于您的解决方案.不过我省略了复制.

Here's the workaround I came up with. It resembles your solution very much. I omitted the copying though.

private void CopyBitmapSourceToUi(BitmapSource image)
{
  BitmapSource uiSource;

  uiSource = BitmapFrame.Create(image);
  uiSource.Freeze();  // locks bitmap and enables access by UI thread

  Dispatcher.Invoke(() => Source = uiSource);
  Thread.Sleep(10);   // WPF requires a short while to render the picture. During that period, you cannot create a WritableBitmap from the source image. So I added a minor delay.
}

不过,使用我的解决方案,当 WPF 呈现图像时,我似乎无法从源创建 WritableBitmap(请参阅上面的评论).

With my solution, though, it looks like I cannot create a WritableBitmap from the source while WPF renders the image (see comment above).

推荐答案

您可以创建调色板位图的副本,如下所示.

You may create a copy of the paletted bitmap like shown below.

为简单起见,它使用 Indexed8 而不是 Indexed2,因此源像素缓冲区中的每个字节都包含一个调色板索引.

For simplicity, it uses Indexed8 instead of Indexed2, so that each byte in the source pixel buffer contains exactly one palette index.

目标位图使用Rgb24格式,因此源缓冲区的每个字节映射到目标缓冲区的3个字节.您也可以使用 Bgr24,但您必须更改 for 循环中的索引.

The target bitmap uses the Rgb24 format, so each byte of the source buffer is mapped to 3 bytes of the target buffer. You could as well use Bgr24, but you would have to change the indexes in the for-loop.

var palette = new BitmapPalette(bi, 4);
var fcb = new FormatConvertedBitmap(bi, PixelFormats.Indexed8, palette, 1);

var sourceBuffer = new byte[fcb.PixelWidth * fcb.PixelHeight];
var targetBuffer = new byte[3 * sourceBuffer.Length];

fcb.CopyPixels(sourceBuffer, fcb.PixelWidth, 0);

for (int i = 0; i < sourceBuffer.Length; i++)
{
    var color = palette.Colors[sourceBuffer[i]];

    targetBuffer[3 * i + 0] = color.R;
    targetBuffer[3 * i + 1] = color.G;
    targetBuffer[3 * i + 2] = color.B;
}

var bitmap = BitmapSource.Create(
    fcb.PixelWidth, fcb.PixelHeight,
    fcb.DpiX, fcb.DpiY,
    PixelFormats.Rgb24, null,
    targetBuffer, 3 * fcb.PixelWidth);

bitmap.Freeze();

这篇关于如何从另一个线程生成调色板图像到 WPF UI 线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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