WPF In-Memory Image Display

一世执手 提交于 2021-01-29 14:50:30

问题


Im trying to build an Item Template for my list-view and im bound to a list of Entities. The entity I have has a System.Drawing.Image that I'd like to display, but so far I cannot for the life of me figure out how to bind it to the <Image> block.

Every example and documentation I can find on the internet pertains to Images accessible via an uri i.e. File on HDD or On Website

    <DataTemplate x:Key="LogoPreviewItem">
        <Border BorderBrush="Black" BorderThickness="1">
            <DockPanel Width="150" Height="100">
                <Image>
                    <Image.Source>
                        <!--
                            {Binding PreviewImage} is where the System.Drawing.Image
                            is in this context
                        -->
                    </Image.Source>
                </Image>
                <Label DockPanel.Dock="Bottom" Content="{Binding CustomerName}" />
            </DockPanel>
        </Border>
    </DataTemplate>

回答1:


A System.Drawing.Image is a WinForms / GDI+ object and is really out of place in the WPF world. A pure WPF program will generally not use System.Drawing.Image but will use BitmapSource instead. However sometimes we are stuck with the old stuff for a while.

You can convert your image from the old technology into the new as follows:

var oldImage = ...;  // System.Drawing.Image

var oldBitmap =
  oldImage as System.Drawing.Bitmap ??
  new System.Drawing.Bitmap(oldImage);

var bitmapSource =
   System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
     oldBitmap.GetHbitmap(System.Drawing.Color.Transparent),
     IntPtr.Zero,
     new Int32Rect(0, 0, oldBitmap.Width, oldBitmap.Height),
     null);

Now you can set:

myImage.Source = bitmapSource;

This is much faster than the MemoryStream approach that you will find described elsewhere, since it never serializes the bitmap data to a stream.




回答2:


The answer by Ray Burns results in a memory leak since

oldBitmap.GetHbitmap(System.Drawing.Color.Transparent)

allocates memory which is never released.

As stated under "Remarks" in the documentation for GetHbitmap (Microsoft Docs):

You are responsible for calling the GDI DeleteObject method to free the memory used by the GDI bitmap object.

Following the documentation, memory is freed by importing and using DeleteObject():

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

var hBitmap = someBitmap.GetHbitmap(...);

// Do something with hBitmap

DeleteObject(hBitmap);

The answer by Ray Burns should thus be modified to:

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

...

var oldImage = ...;  // System.Drawing.Image

var oldBitmap =
  oldImage as System.Drawing.Bitmap ??
  new System.Drawing.Bitmap(oldImage);

var hOldBitmap = oldBitmap.GetHbitmap(System.Drawing.Color.Transparent);
var bitmapSource =
   System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
     hOldBitmap,
     IntPtr.Zero,
     new Int32Rect(0, 0, oldBitmap.Width, oldBitmap.Height),
     null);
DeleteObject(hOldBitmap);


来源:https://stackoverflow.com/questions/3018004/wpf-in-memory-image-display

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!