WPF - 将位图转换为 ImageSource

Posted

技术标签:

【中文标题】WPF - 将位图转换为 ImageSource【英文标题】:WPF - converting Bitmap to ImageSource 【发布时间】:2014-12-03 08:02:23 【问题描述】:

我需要将 System.Drawing.Bitmap 转换为 System.Windows.Media.ImageSource 类,以便将其绑定到 WizardPage(扩展 WPF 工具包)的 HeaderImage 控件中。 位图被设置为我编写的程序集的资源。 它被这样引用:

public Bitmap GetBitmap

   get
   
      Bitmap bitmap = new Bitmap(Resources.my_banner);
      return bitmap;
   


public ImageSource HeaderBitmap

   get
   
      ImageSourceConverter c = new ImageSourceConverter();
      return (ImageSource)c.ConvertFrom(GetBitmap);
   

转换器是我here找到的。我在

得到一个 NullReferenceException
return (ImageSource) c.ConvertFrom(Resources.my_banner);

如何初始化 ImageSource 以避免此异常?还是有其他方法? 之后我想使用它:

<xctk:WizardPage x:Name="StartPage" Height="500" Width="700"
                 HeaderImage="Binding HeaderBitmap" 
                 Enter="StartPage_OnEnter"

提前感谢您的任何回答。

【问题讨论】:

见这里:What is a NullReferenceException and how do I fix it? 【参考方案1】:
void Draw()

    System.Drawing.Bitmap bmp = new Bitmap();
    ...
    Image img = new Image();
    img.Source = BitmapToImageSource(bmp)
 


private BitmapImage BitmapToImageSource(System.Drawing.Bitmap bitmap)

    using (MemoryStream memory = new MemoryStream())
    
        bitmap.Save(memory, System.Drawing.Imaging.ImageFormat.Bmp);
        memory.Position = 0;
        BitmapImage bitmapimage = new BitmapImage();
        bitmapimage.BeginInit();
        bitmapimage.StreamSource = memory;
        bitmapimage.CacheOption = BitmapCacheOption.OnLoad;
        bitmapimage.EndInit();
        return bitmapimage;
    

【讨论】:

【参考方案2】:

对其他人来说,这是可行的:

    //If you get 'dllimport unknown'-, then add 'using System.Runtime.InteropServices;'
    [DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool DeleteObject([In] IntPtr hObject);

    public ImageSource ImageSourceFromBitmap(Bitmap bmp)
    
        var handle = bmp.GetHbitmap();
        try
        
            return Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
        
        finally  DeleteObject(handle);                
    

【讨论】:

你是我的英雄。用它来为 Bitmap 类做一个扩展,效果很好。干得好。 @ARidder101 我确定我是从其他人那里得到的。 这种方法提供了非常低质量的透明度。 Mike Strobel 下面的回答 (***.com/a/26261562/418362) 要好得多,不需要任何互操作。 让我知道当我没有调用 DeleteObject(handle) 时会发生什么。我有一个问题。谢谢。 早在 .NET 2.0 天的 Windows XP 上,可以同时打开 10.000 个句柄的限制。当达到该限制时,机器冻结了。 - 所以不调用删除,意味着你会泄漏一个句柄。 .NET 可以在某处适当地清理它,但您很可能会受到性能影响。'【参考方案3】:

dethSwatch - 感谢您在上面的回答!它帮助很大!在实现它之后,我得到了想要的行为,但我发现我在程序的另一部分遇到了内存/句柄问题。我将代码更改如下,使其更加冗长,问题就消失了。再次感谢!

    [DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool DeleteObject([In] IntPtr hObject);

    public ImageSource ImageSourceForBitmap(Bitmap bmp)
    
        var handle = bmp.GetHbitmap();
        try
        
            ImageSource newSource = Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());

            DeleteObject(handle);
            return newSource;
        
        catch (Exception ex)
        
            DeleteObject(handle);
            return null;
        
    

【讨论】:

你的一个更漂亮的变体:) ``` var handle = bmp.GetHbitmap();尝试 返回 Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); 捕捉 返回空值; 最后 Win32.DeleteObject(handle); ```【参考方案4】:

对我来说最简单的解决方案:

ImageBrush myBrush = new ImageBrush();
var bitmap = System.Drawing.Image.FromFile("pic1.bmp");
Bitmap bitmap = new System.Drawing.Bitmap(image);//it is in the memory now
var bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap(),IntPtr.Zero,Int32Rect.Empty,BitmapSizeOptions.FromEmptyOptions());
myBrush.ImageSource = bitmapSource;
cover.MainGrid.Background = myBrush;
cover.Show();
bitmap.Dispose();

【讨论】:

我认为GetHbitmap的hande应该被释放。【参考方案5】:

为了搜索者的利益,我基于detailed solution 创建了一个快速转换器。

目前没有问题。

using System;
using System.Drawing;
using System.IO;
using System.Windows.Media.Imaging;

namespace XYZ.Helpers

    public class ConvertBitmapToBitmapImage
    
        /// <summary>
        /// Takes a bitmap and converts it to an image that can be handled by WPF ImageBrush
        /// </summary>
        /// <param name="src">A bitmap image</param>
        /// <returns>The image as a BitmapImage for WPF</returns>
        public BitmapImage Convert(Bitmap src)
        
            MemoryStream ms = new MemoryStream();
            ((System.Drawing.Bitmap)src).Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
            BitmapImage image = new BitmapImage();
            image.BeginInit();
            ms.Seek(0, SeekOrigin.Begin);
            image.StreamSource = ms;
            image.EndInit();
            return image;
        
    

【讨论】:

今天你是我的神 我喜欢这个。我喜欢这个。【参考方案6】:

我不相信ImageSourceConverter 会从System.Drawing.Bitmap 转换。但是,您可以使用以下内容:

public static BitmapSource CreateBitmapSourceFromGdiBitmap(Bitmap bitmap)

    if (bitmap == null)
        throw new ArgumentNullException("bitmap");

    var rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);

    var bitmapData = bitmap.LockBits(
        rect,
        ImageLockMode.ReadWrite,
        PixelFormat.Format32bppArgb);

    try
    
        var size = (rect.Width * rect.Height) * 4;

        return BitmapSource.Create(
            bitmap.Width,
            bitmap.Height,
            bitmap.HorizontalResolution,
            bitmap.VerticalResolution,
            PixelFormats.Bgra32,
            null,
            bitmapData.Scan0,
            size,
            bitmapData.Stride);
    
    finally
    
        bitmap.UnlockBits(bitmapData);
    

此方案要求源图片为 Bgra32 格式;如果您正在处理其他格式,则可能需要添加转换。

【讨论】:

以上是关于WPF - 将位图转换为 ImageSource的主要内容,如果未能解决你的问题,请参考以下文章

使用medata数据wpf c#将位图保存为png [重复]

将 WPF 画布保存到文件而不损失质量(不使用位图作为中介)

将输入流转换为位图

如何将双数组列表转换为位图? [关闭]

将 ImageView 转换为具有本机分辨率的位图

将位图数组转换为 YUV(420 平面)?