4

This simple program does not work, the image does not appear in the Window.

namespace ClipBoardTest
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        private void CopyButton_Click(object sender, RoutedEventArgs e)
        {
            if (Clipboard.ContainsImage())
            {
                ImageUIElement.Source = Clipboard.GetImage();
                Console.WriteLine("Clipboard copied to UIElement");
            }
            else
            {
                Console.WriteLine("No image in Clipboard");
            }
        }
    }
 }

Output is "Clipboard copied to UIElement", but the image does not appear in the Window.

XAML:

 <Window x:Class="ClipBoardTest.MainWindow"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         Title="MainWindow" Height="350" Width="525">
     <Grid>
         <Button x:Name="CopyButton" Content="Copy" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75" Click="CopyButton_Click"/>
         <Image x:Name="ImageUIElement" Margin="90,10,10,10"/>
     </Grid>
 </Window>

Is there anybody, who understands, what is wrong?

Torsten Crull
  • 123
  • 3
  • 9
  • Try the workaround as specified [here](http://social.msdn.microsoft.com/Forums/vstudio/en-US/10589cd6-6a48-4497-8f7d-a12490f376c6/clipboardgetimage-and-imagesource). – Rohit Vats Sep 09 '14 at 16:44
  • I'm seeing this behavior too, but oddly just with **some** images on the clipboard. Images copied from the browser work for me. Images copied from SnagIt for some reason don't even though I can capture and save that same image explicitly to disk and use it. One alternate workaround for me has been to save to disk first then load it from there to display in the control. – Rick Strahl Aug 26 '20 at 19:28

3 Answers3

7

Use Clipboard.GetDataObject to get bitmap and convert it into bitmapSource. Also, be aware that Bitmap.GetHbitmap() leaks memory unless you call DeleteObject on it.

So, correct solution would be to dispose the IntPtr after use. Declare the method at class level and use it from your code:

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

if (Clipboard.ContainsImage())
{
    IDataObject clipboardData = Clipboard.GetDataObject();
    if (clipboardData != null)
    {
        if (clipboardData.GetDataPresent(System.Windows.Forms.DataFormats.Bitmap))
        {
            System.Drawing.Bitmap bitmap = (System.Drawing.Bitmap)clipboardData.GetData(System.Windows.Forms.DataFormats.Bitmap);
            IntPtr hBitmap = bitmap.GetHbitmap();
            try
            {
                ImageUIElement.Source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
                Console.WriteLine("Clipboard copied to UIElement");
            }
            finally 
            {
                DeleteObject(hBitmap)
            }
        }
    }
}

Source - MSDN and Memory leak in Bitmap.

Community
  • 1
  • 1
Rohit Vats
  • 79,502
  • 12
  • 161
  • 185
3

Visual Studio 2019, WPF C# project targeting .NET Core 3.1, the following works (or, at least, it does for me):

myImage.Source = GetImageFromClipBoard();

where:

public static ImageSource GetImageFromClipBoard ()
        {
        if (Clipboard.ContainsImage())
            {
            return Clipboard.GetImage();
            }
        else
            return null;
        }
Andrea Antonangeli
  • 1,242
  • 1
  • 21
  • 32
  • 3
    Note that this doesn't work for all copied bitmaps. For example if a bitmap is copied in Microsoft's Paint it gets an empty area but if it the bitmap is copied in Paint.NET, LibreOffice or such it works. Generally the problem is that some programs like Microsoft's Paint copy only a device dependent bitmap and WPF likes to work with device INdependent bitmaps. You will have to convert it by adding a BITMAPINFOHEADER structure as shown in this blog: https://thomaslevesque.com/2009/02/05/wpf-paste-an-image-from-the-clipboard/ – AndresRohrAtlasInformatik Aug 25 '20 at 13:11
  • For anyone needing to get the image from paint, highly recommend the link attached in @AndresRohrAtlasInformatik comment above. – Eduards Jul 02 '21 at 14:53
1

Now it works fine.

if (Clipboard.ContainsImage())
{
    // ImageUIElement.Source = Clipboard.GetImage(); // does not work
    System.Windows.Forms.IDataObject clipboardData = System.Windows.Forms.Clipboard.GetDataObject();
    if (clipboardData != null)
    {
        if (clipboardData.GetDataPresent(System.Windows.Forms.DataFormats.Bitmap))
        {
            System.Drawing.Bitmap bitmap = (System.Drawing.Bitmap)clipboardData.GetData(System.Windows.Forms.DataFormats.Bitmap);
            ImageUIElement.Source =  System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty,BitmapSizeOptions.FromEmptyOptions());
            Console.WriteLine("Clipboard copied to UIElement");
        }
    }
}
Termininja
  • 6,620
  • 12
  • 48
  • 49
Torsten Crull
  • 123
  • 3
  • 9