Tengo una instancia de un System.Drawing.Bitmap y quisiera ponerlo a disposición de mi aplicación WPF en la forma de un System.Windows.Media.Imaging.BitmapImage.

Cuál sería el mejor enfoque para esto?

InformationsquelleAutor Kevin | 2008-09-18

10 Comentarios

  1. 254

    Acerca de cómo cargar desde MemoryStream?

    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();
    }
    • Se podría añadir este código como un método de extensión en el Sistema.De dibujo.Mapa de bits, algo así como ToBitmapImage()
    • El Uso De ImageFormat.Bmp es un orden de magnitud más rápido.
    • En el caso de que otros están teniendo problemas con este código: he tenido que añadir ms.Seek(0, SeekOrigin.Begin); antes de establecer bi.StreamSource. Estoy usando .NET 4.0.
    • eso sería cierto de cualquier versión de .net. Voy a colarse allí y corrección de dicho código; que nadie diga Pawel.
    • no, no es necesario cerrarlo. Yo uso un «uso» de la declaración. :p
    • Adición importante a este código: añadir bitmap.CacheOption = BitmapCacheOption.OnLoad; entre BeginInit() y EndInit(). De lo contrario, el flujo puede ser cerrado (especialmente si encierran en using) por el tiempo de la BitmapImage intenta leerlo. Véase la respuesta aquí: stackoverflow.com/questions/5346727/…
    • Para mí no funcionó al principio, pero luego he cambiado la línea de bi.StreamSource = ms; a bi.StreamSource = new MemoryStream(ms.ToArray()); y este cambio era todo lo que necesitaba!
    • Alguien considere la posibilidad de editar esta respuesta para que todos la (correcta) comentarios están integrados en ella? En el momento en que es fuertemente upvoted, pero no del todo claro si se trata de la respuesta o respuesta+comentarios que son de «derecha»…
    • También debería añadir que, si bien ImageFormat.Bmp es más rápido, se tira a la basura cualquier transparencia que el mapa de bits original había
    • si se utiliza como una extensión como se ha mencionado anteriormente, asegúrese de Freeze la bitmapImage antes de devolverlo.
    • 219 personas upvoted comprimir y descomprimir un archivo PNG? En serio?

  2. 79

    Gracias a Hallgrim, aquí está el código que terminó con:

    ScreenCapture = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
       bmp.GetHbitmap(), 
       IntPtr.Zero, 
       System.Windows.Int32Rect.Empty, 
       BitmapSizeOptions.FromWidthAndHeight(width, height));

    También terminó el enlace a un BitmapSource en lugar de un BitmapImage como en mi pregunta original

    • Genial!!! ¿Por qué no seleccionar su propia respuesta como la respuesta a la pregunta? La tuya es mucho mejor ahora.
    • Ya que el tuyo es el aceptado la respuesta ya, usted puede editar su respuesta para hacerla más completa.
    • Hacer de cuenta que este código pérdidas de un HBitmap. Consulte stackoverflow.com/questions/1118496/… para solucionarlo
    • Por favor, también tenga en cuenta que este código producirá aמ InteropBitmap. He tenido un problema con esto cuando utilice XamlWriter y, a continuación, XamlReader – InteropBitmap no es compatible. Consulte este enlace para más detalles.
    • Warning: Este fugas de GDI mango cada vez que se utiliza, así que después de 10k llamadas dejará de funcionar (65k si tienes suerte). Como se documenta en GetHbitmap, absolutamente debe p/invoke DeleteObject en que manejan.
    • Para el último parámetro, he utilizado BitmapSizeOptions.FromEmptyOptions(), y funciona muy bien a mi situación.
    • tu pregunta es para BitmapImage de un Sistema.De dibujo.Mapa de bits. pero el código de retorno de un BitmapSource no BitmapImage.

  3. 53

    Sé que esto ha sido contestado, pero aquí hay un par de métodos de extensión (para .NET 3.0+) que hacer la conversión. 🙂

            ///<summary>
        ///Converts a <see cref="System.Drawing.Image"/> into a WPF <see cref="BitmapSource"/>.
        ///</summary>
        ///<param name="source">The source image.</param>
        ///<returns>A BitmapSource</returns>
        public static BitmapSource ToBitmapSource(this System.Drawing.Image source)
        {
            System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(source);
    
            var bitSrc = bitmap.ToBitmapSource();
    
            bitmap.Dispose();
            bitmap = null;
    
            return bitSrc;
        }
    
        ///<summary>
        ///Converts a <see cref="System.Drawing.Bitmap"/> into a WPF <see cref="BitmapSource"/>.
        ///</summary>
        ///<remarks>Uses GDI to do the conversion. Hence the call to the marshalled DeleteObject.
        ///</remarks>
        ///<param name="source">The source bitmap.</param>
        ///<returns>A BitmapSource</returns>
        public static BitmapSource ToBitmapSource(this System.Drawing.Bitmap source)
        {
            BitmapSource bitSrc = null;
    
            var hBitmap = source.GetHbitmap();
    
            try
            {
                bitSrc = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                    hBitmap,
                    IntPtr.Zero,
                    Int32Rect.Empty,
                    BitmapSizeOptions.FromEmptyOptions());
            }
            catch (Win32Exception)
            {
                bitSrc = null;
            }
            finally
            {
                NativeMethods.DeleteObject(hBitmap);
            }
    
            return bitSrc;
        }

    y la clase NativeMethods (para apaciguar FxCop)

        ///<summary>
    ///FxCop requires all Marshalled functions to be in a class called NativeMethods.
    ///</summary>
    internal static class NativeMethods
    {
        [DllImport("gdi32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool DeleteObject(IntPtr hObject);
    }
  4. 22

    Me tomó algo de tiempo para obtener la conversión de trabajo en ambos sentidos, así que aquí están los dos métodos de extensión que se me ocurrió:

    using System.Drawing;
    using System.Drawing.Imaging;
    using System.IO;
    using System.Windows.Media.Imaging;
    
    public static class BitmapConversion {
    
        public static Bitmap ToWinFormsBitmap(this BitmapSource bitmapsource) {
            using (MemoryStream stream = new MemoryStream()) {
                BitmapEncoder enc = new BmpBitmapEncoder();
                enc.Frames.Add(BitmapFrame.Create(bitmapsource));
                enc.Save(stream);
    
                using (var tempBitmap = new Bitmap(stream)) {
                    //According to MSDN, one "must keep the stream open for the lifetime of the Bitmap."
                    //So we return a copy of the new bitmap, allowing us to dispose both the bitmap and the stream.
                    return new Bitmap(tempBitmap);
                }
            }
        }
    
        public static BitmapSource ToWpfBitmap(this Bitmap bitmap) {
            using (MemoryStream stream = new MemoryStream()) {
                bitmap.Save(stream, ImageFormat.Bmp);
    
                stream.Position = 0;
                BitmapImage result = new BitmapImage();
                result.BeginInit();
                //According to MSDN, "The default OnDemand cache option retains access to the stream until the image is needed."
                //Force the bitmap to load right now so we can dispose the stream.
                result.CacheOption = BitmapCacheOption.OnLoad;
                result.StreamSource = stream;
                result.EndInit();
                result.Freeze();
                return result;
            }
        }
    }
  5. 10

    La cosa más fácil es si se puede hacer el WPF mapa de bits de un archivo directamente.

    De lo contrario, usted tendrá que utilizar el Sistema.Windows.De interoperabilidad.La proyección de imagen.CreateBitmapSourceFromHBitmap.

  6. 9
    //at class level;
    [System.Runtime.InteropServices.DllImport("gdi32.dll")]
    public static extern bool DeleteObject(IntPtr hObject);    //https://stackoverflow.com/a/1546121/194717
    
    
    ///<summary> 
    ///Converts a <see cref="System.Drawing.Bitmap"/> into a WPF <see cref="BitmapSource"/>. 
    ///</summary> 
    ///<remarks>Uses GDI to do the conversion. Hence the call to the marshalled DeleteObject. 
    ///</remarks> 
    ///<param name="source">The source bitmap.</param> 
    ///<returns>A BitmapSource</returns> 
    public static System.Windows.Media.Imaging.BitmapSource ToBitmapSource(this System.Drawing.Bitmap source)
    {
        var hBitmap = source.GetHbitmap();
        var result = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, System.Windows.Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
    
        DeleteObject(hBitmap);
    
        return result;
    }
  7. 5

    Yo trabajo en una imagen de proveedor y escribió un adaptador para WPF para nuestro formato de imagen que es similar a un Sistema.De dibujo.Mapa de bits.

    Escribí este artículo de KB para explicar a nuestros clientes:

    http://www.atalasoft.com/kb/article.aspx?id=10156

    Y hay allí el código que lo hace. Usted necesita para reemplazar AtalaImage con mapa de bits y hacer el equivalente de lo que estamos haciendo-que debería ser bastante sencillo.

    • Gracias Lou – fue capaz de hacer lo que sea necesario con una línea de código
  8. 4

    Mi opinión sobre esta construido a partir de un número de recursos. https://stackoverflow.com/a/7035036 https://stackoverflow.com/a/1470182/360211

    using System;
    using System.Drawing;
    using System.Runtime.ConstrainedExecution;
    using System.Runtime.InteropServices;
    using System.Security;
    using System.Windows;
    using System.Windows.Interop;
    using System.Windows.Media.Imaging;
    using Microsoft.Win32.SafeHandles;
    
    namespace WpfHelpers
    {
        public static class BitmapToBitmapSource
        {
            public static BitmapSource ToBitmapSource(this Bitmap source)
            {
                using (var handle = new SafeHBitmapHandle(source))
                {
                    return Imaging.CreateBitmapSourceFromHBitmap(handle.DangerousGetHandle(),
                        IntPtr.Zero, Int32Rect.Empty,
                        BitmapSizeOptions.FromEmptyOptions());
                }
            }
    
            [DllImport("gdi32")]
            private static extern int DeleteObject(IntPtr o);
    
            private sealed class SafeHBitmapHandle : SafeHandleZeroOrMinusOneIsInvalid
            {
                [SecurityCritical]
                public SafeHBitmapHandle(Bitmap bitmap)
                    : base(true)
                {
                    SetHandle(bitmap.GetHbitmap());
                }
    
                [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
                protected override bool ReleaseHandle()
                {
                    return DeleteObject(handle) > 0;
                }
            }
        }
    }
  9. 4

    Usted puede simplemente compartir la pixeldata entre ambos espacios de nombres ( Medios de comunicación y de Dibujo) escribiendo una costumbre bitmapsource. La conversión va a suceder de inmediato y sin memoria adicional será asignado. Si usted no desea crear explícitamente una copia de su mapa de bits este es el método que desea.

    class SharedBitmapSource : BitmapSource, IDisposable
    {
    #region Public Properties
    ///<summary>
    ///I made it public so u can reuse it and get the best our of both namespaces
    ///</summary>
    public Bitmap Bitmap { get; private set; }
    public override double DpiX { get { return Bitmap.HorizontalResolution; } }
    public override double DpiY { get { return Bitmap.VerticalResolution; } }
    public override int PixelHeight { get { return Bitmap.Height; } }
    public override int PixelWidth { get { return Bitmap.Width; } }
    public override System.Windows.Media.PixelFormat Format { get { return ConvertPixelFormat(Bitmap.PixelFormat); } }
    public override BitmapPalette Palette { get { return null; } }
    #endregion
    #region Constructor/Destructor
    public SharedBitmapSource(int width, int height,System.Drawing.Imaging.PixelFormat sourceFormat)
    :this(new Bitmap(width,height, sourceFormat) ) { }
    public SharedBitmapSource(Bitmap bitmap)
    {
    Bitmap = bitmap;
    }
    //Use C# destructor syntax for finalization code.
    ~SharedBitmapSource()
    {
    //Simply call Dispose(false).
    Dispose(false);
    }
    #endregion
    #region Overrides
    public override void CopyPixels(Int32Rect sourceRect, Array pixels, int stride, int offset)
    {
    BitmapData sourceData = Bitmap.LockBits(
    new Rectangle(sourceRect.X, sourceRect.Y, sourceRect.Width, sourceRect.Height),
    ImageLockMode.ReadOnly,
    Bitmap.PixelFormat);
    var length = sourceData.Stride * sourceData.Height;
    if (pixels is byte[])
    {
    var bytes = pixels as byte[];
    Marshal.Copy(sourceData.Scan0, bytes, 0, length);
    }
    Bitmap.UnlockBits(sourceData);
    }
    protected override Freezable CreateInstanceCore()
    {
    return (Freezable)Activator.CreateInstance(GetType());
    }
    #endregion
    #region Public Methods
    public BitmapSource Resize(int newWidth, int newHeight)
    {
    Image newImage = new Bitmap(newWidth, newHeight);
    using (Graphics graphicsHandle = Graphics.FromImage(newImage))
    {
    graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic;
    graphicsHandle.DrawImage(Bitmap, 0, 0, newWidth, newHeight);
    }
    return new SharedBitmapSource(newImage as Bitmap);
    }
    public new BitmapSource Clone()
    {
    return new SharedBitmapSource(new Bitmap(Bitmap));
    }
    //Implement IDisposable.
    public void Dispose()
    {
    Dispose(true);
    GC.SuppressFinalize(this);
    }
    #endregion
    #region Protected/Private Methods
    private static System.Windows.Media.PixelFormat ConvertPixelFormat(System.Drawing.Imaging.PixelFormat sourceFormat)
    {
    switch (sourceFormat)
    {
    case System.Drawing.Imaging.PixelFormat.Format24bppRgb:
    return PixelFormats.Bgr24;
    case System.Drawing.Imaging.PixelFormat.Format32bppArgb:
    return PixelFormats.Pbgra32;
    case System.Drawing.Imaging.PixelFormat.Format32bppRgb:
    return PixelFormats.Bgr32;
    }
    return new System.Windows.Media.PixelFormat();
    }
    private bool _disposed = false;
    protected virtual void Dispose(bool disposing)
    {
    if (!_disposed)
    {
    if (disposing)
    {
    //Free other state (managed objects).
    }
    //Free your own state (unmanaged objects).
    //Set large fields to null.
    _disposed = true;
    }
    }
    #endregion
    }
    • puedes publicar un ejemplo?
    • Exactamente lo que estaba buscando, espero que esto funciona cuando me compila =D
    • Así que si usted tiene Propiedades.Recursos.Imagen y quieres dibujar en un lienzo, toma de 133 líneas de código? WPF no está bien.
    • Es posible hacerlo en una sola línea. Pero si quieres hacerlo sin hacer una copia en profundidad de la imagedata. Este es el camino a seguir.
  10. 2

    Me vino a esta pregunta porque yo estaba tratando de hacer lo mismo, pero en mi caso, el mapa de bits a partir de un recurso/archivo. He encontrado la mejor solución es, como se describe en el siguiente link:

    http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.bitmapimage.aspx

    //Create the image element.
    Image simpleImage = new Image();    
    simpleImage.Width = 200;
    simpleImage.Margin = new Thickness(5);
    //Create source.
    BitmapImage bi = new BitmapImage();
    //BitmapImage.UriSource must be in a BeginInit/EndInit block.
    bi.BeginInit();
    bi.UriSource = new Uri(@"/sampleImages/cherries_larger.jpg",UriKind.RelativeOrAbsolute);
    bi.EndInit();
    //Set the image source.
    simpleImage.Source = bi;

Dejar respuesta

Please enter your comment!
Please enter your name here