【问题标题】:C# - Convert WPF Image.source to a System.Drawing.BitmapC# - 将 WPF Image.source 转换为 System.Drawing.Bitmap
【发布时间】:2011-08-07 01:49:05
【问题描述】:

我发现很多人将BitmapSource 转换为Bitmap,但是ImageSource 转换为Bitmap 呢?我正在制作一个成像程序,我需要从Image 元素中显示的图像中提取位图。有谁知道怎么做?

编辑 1:

这是一个将BitmapImage 转换为Bitmap 的函数。请记住在编译器首选项中设置“不安全”选项。

public static System.Drawing.Bitmap BitmapSourceToBitmap(BitmapSource srs)
{
    System.Drawing.Bitmap btm = null;

    int width = srs.PixelWidth;

    int height = srs.PixelHeight;

    int stride = width * ((srs.Format.BitsPerPixel + 7) / 8);

    byte[] bits = new byte[height * stride];

    srs.CopyPixels(bits, stride, 0);

    unsafe
    {
        fixed (byte* pB = bits)
        {
            IntPtr ptr = new IntPtr(pB);

            btm = new System.Drawing.Bitmap(width, height, stride, System.Drawing.Imaging.PixelFormat.Format1bppIndexed, ptr);
        }
    }
    return btm;
}

接下来是获取BitmapImage

RenderTargetBitmap targetBitmap = new RenderTargetBitmap(
    (int)inkCanvas1.ActualWidth,
    (int)inkCanvas1.ActualHeight,
    96d, 96d,
    PixelFormats.Default);

targetBitmap.Render(inkCanvas1);

MemoryStream mse = new MemoryStream();
System.Windows.Media.Imaging.BmpBitmapEncoder mem = new BmpBitmapEncoder();
mem.Frames.Add(BitmapFrame.Create(targetBitmap));
mem.Save(mse);

mse.Position = 0;
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = mse;
bi.EndInit();

接下来是转换它:

Bitmap b = new Bitmap(BitmapSourceToBitmap(bi));

【问题讨论】:

  • 没有。这太可怕了。

标签: c# image image-processing bitmap


【解决方案1】:

其实你不需要使用不安全的代码。有一个接受 IntPtr 的 CopyPixels 的重载:

public static System.Drawing.Bitmap BitmapSourceToBitmap2(BitmapSource srs)
{
    int width = srs.PixelWidth;
    int height = srs.PixelHeight;
    int stride = width * ((srs.Format.BitsPerPixel + 7) / 8);
    IntPtr ptr = IntPtr.Zero;
    try
    {
        ptr = Marshal.AllocHGlobal(height * stride);
        srs.CopyPixels(new Int32Rect(0, 0, width, height), ptr, height * stride, stride);
        using (var btm = new System.Drawing.Bitmap(width, height, stride, System.Drawing.Imaging.PixelFormat.Format1bppIndexed, ptr))
        {
            // Clone the bitmap so that we can dispose it and
            // release the unmanaged memory at ptr
            return new System.Drawing.Bitmap(btm);
        }
    }
    finally
    {
        if (ptr != IntPtr.Zero)
            Marshal.FreeHGlobal(ptr);
    }
}

【讨论】:

  • 请注意,在内部,Bitmap 的此构造函数调用GdipCreateBitmapFromScan0,它希望用户在不再需要内存时释放内存...
  • @Cameron,说得好。我编辑了我的答案以考虑到这一点。
  • 不幸的是,直到 System.Drawing.Bitmap 被释放后才能释放内存(我找不到任何文档,但在互操作繁重的应用程序中尝试过之后,我的图像只有在我之后释放时才能正确显示,所以它看起来不像是在内部复制数据)。此外,GDI docs 似乎要求步幅是 4 的倍数;所以(srs.Format.BitsPerPixel + 7) / 8 应该是(srs.Format.BitsPerPixel + 31) / 32 * 8,我相信。
  • @Cameron - 在克隆位图之前尝试冻结它。那应该释放对内存的持有。
【解决方案2】:

这个例子对我有用:

    public static Bitmap ConvertToBitmap(BitmapSource bitmapSource)
    {
        var width = bitmapSource.PixelWidth;
        var height = bitmapSource.PixelHeight;
        var stride = width * ((bitmapSource.Format.BitsPerPixel + 7) / 8);
        var memoryBlockPointer = Marshal.AllocHGlobal(height * stride);
        bitmapSource.CopyPixels(new Int32Rect(0, 0, width, height), memoryBlockPointer, height * stride, stride);
        var bitmap = new Bitmap(width, height, stride, PixelFormat.Format32bppPArgb, memoryBlockPointer);
        return bitmap;
    }

【讨论】:

    【解决方案3】:

    您根本不需要BitmapSourceToBitmap 方法。创建内存流后,只需执行以下操作:

    mem.Position = 0;  
    Bitmap b = new Bitmap(mem);
    

    【讨论】:

      【解决方案4】:

      你的 ImageSource 不是 BitmapSource 吗?如果您从文件中加载图像,它们应该是。

      回复您的评论:

      听起来应该是BitmapSource,BitmapSource是ImageSource的子类型。将 ImageSource 转换为 BitmapSource 并关注其中一篇博文。

      【讨论】:

      • 不,它说它们是 ImageSources。我正在从 Bitmaps 转换的 BitmapIamges 加载它们。
      • 谢谢,我想出了一个我认为可以正常工作的方法。我已经发布了对我的问题的编辑。
      • @SimonStenderBoisen - ImageSource 可能来自 XAML 文件而不是 Bitmap 文件。如果是这样,它的基础类可能是 DrawingBrush 并且需要转换以获得实际的 Bitmap
      猜你喜欢
      • 1970-01-01
      • 2022-01-16
      • 1970-01-01
      • 2017-12-03
      • 2019-10-21
      • 2010-11-15
      • 1970-01-01
      • 2016-12-06
      相关资源
      最近更新 更多