在 window (WPF) 中输出位图的最佳方式是什么?

What is the best way to output Bitmap in a window (WPF)?

我想做的事情:

给定一个简单的位图 (System.Drawing.Bitmap),我愿意将它输出到我的 window WPF 应用程序中。我也愿意经常做,创建帧流

我用过的:

首先,我一直在将 Bitmap 转换为 BitmapImage,然后将其分配给 Image 控件的 Source 字段。

此方法的问题在于转换本身。这很慢。我还没有找到一种工作速度足够快的方法,对于 640x480 位图,最好的方法大约需要 20 毫秒,这很慢。我希望找到一种方法,可以在不到 5 毫秒的时间内完成任何常见的解决方案或解决整个问题的不同方法。也许,除了 Image 之外,还有一个不同的控件可以与纯位图一起使用,我不需要转换。我也不习惯使用 WPF,UWP 或新的 WinUI 3 有这个问题吗? 我检查过 UWP 使用 WriteableBitmap,这也需要转换,但也许还有其他方法?

我发现了各种转换,其中一些转换速度很慢,而另一些转换出于某种原因只能生成白色图像。我在下面提供了一个列表(我尝试了更多但我不记得具体是什么):

  1. 使用下面的方法。此转换有效,但转换 640x480 毫秒位图需要大约 20 毫秒。

方法(source):

public BitmapImage ToBitmapImage(Bitmap bitmap)
{
    using (MemoryStream memory = new MemoryStream())
    {
        bitmap.Save(memory, ImageFormat.Png);

        memory.Position = 0;

        BitmapImage bitmapImage = new BitmapImage();

        bitmapImage.BeginInit();

        bitmapImage.StreamSource = memory;

        bitmapImage.CacheOption = BitmapCacheOption.OnLoad;

        bitmapImage.EndInit();

        bitmapImage.Freeze();

        return bitmapImage;
    }
}
  1. 使用 Asmak9.EssentialToolKit 库 (source),但转换大约需要 27 毫秒,所以这不是一个选项。

  2. 使用下面的方法。由于某些奇怪的原因,这个对我不起作用。它运行没有问题,但转换的结果是一个空白(白色)图像,而不是输入其中的东西。

方法(source):

private BitmapSource Convert(Bitmap bmp)
{
  
  var bitmapData = bmp.LockBits(
    new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height),
    System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);  
    
  var bitmapSource = BitmapSource.Create(
    bitmapData.Width, bitmapData.Height,
    bitmap.HorizontalResolution, bitmap.VerticalResolution,
    PixelFormats.Bgr24, null,
    bitmapData.Scan0, bitmapData.Stride * bitmapData.Height, bitmapData.Stride);
     
  bmp.UnlockBits(bitmapData);
  return bitmapSource;
}
  1. 使用方法 below.This 产生与之前转换相同的结果 - 空白 BitmapImage。我也不确定这里可能出了什么问题。

方法(source):

[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);

private BitmapSource Bitmap2BitmapImage(Bitmap bitmap)
{
    IntPtr hBitmap = bitmap.GetHbitmap();
    BitmapSource retval;

    try
    {
        retval = Imaging.CreateBitmapSourceFromHBitmap(
                        hBitmap,
                        IntPtr.Zero,
                        Int32Rect.Empty,
                        BitmapSizeOptions.FromEmptyOptions());
    }
    finally
    {
        DeleteObject(hBitmap);
    }

    return retval;
}

也许,最后两次转换更好,但它们没有正确转换,或者我做错了什么?或者是否有更好的一般方法来放弃转换步骤并直接显示位图?

正如 Clement 上面指出的,方法 3 是最快的,但它需要两件事:

  1. 像素格式设置正确。
  2. Convert方法应该在主线程运行。