[WPF] Paste an image from the clipboard (bug in Clipboard.GetImage)

Very poorPoorAverageGoodExcellent (6 votes) 

Oops… 2 months already since my previous (and first) post… I really have to get on a more regular schedule 😉

If you’ve ever tried to use the Clipboard.GetImage method in WPF, you probably had an unpleasant surprise… In fact, this method returns an InteropBitmap which, in some cases (most cases actually), can’t be displayed in an Image control : no exception is thrown, the image size is correct, but the image either appears empty or unrecognizable.

However, if we save that image to a stream and re-read it from the stream, we get a perfectly usable image… So this could be an acceptable workaround, but I think its pretty bad for performance, because the image gets decoded, re-encoded, and re-decoded. It is also possible to use the Clipboard class from Windows Forms, which works fine, and convert the System.Drawing.Image to a System.Windows.Media.ImageSource, but I don’t like the idea of referencing the Windows Forms assembly in a WPF app… So I decided to manually retrieve the image from the clipboard and handle the decoding myself.

If we look at the image formats available from the clipboard (Clipboard.GetDataObject().GetFormats()), we can see that they depend on the origin of the image (screenshot, copy from Paint…). The only format that is always available is DeviceIndependentBitmap (DIB). So I tried to retrieve the MemoryStream for this format and decode it into a BitmapSource :

        private ImageSource ImageFromClipboardDib()
            MemoryStream ms = Clipboard.GetData("DeviceIndependentBitmap") as MemoryStream;
            BitmapImage bmp = new BitmapImage();
            bmp.StreamSource = ms;
            return bmp;

Unfortunately, this code throws a nasty NotSupportedException : « No imaging component suitable to complete this operation was found ». In other words, it doesn’t know how to decode the contents of the stream… That’s quite surprising, because DIB is a very common format. So I had a look at the structure of a DIB in MSDN documentation. Basically, a « classical » bitmap file (.bmp) is made of the following sections :

  • File header (BITMAPFILEHEADER structure)
  • Bitmap header (BITMAPINFO structure)
  • Palette (array of RGBQUAD)
  • Raw pixel data

If we observe the content of the DIB from the clipboard, we can see that it has the same structure, without the BITMAPFILEHEADER part… so the trick is just to add that header at the beginning of the buffer, and use this complete buffer to decode the image. Doesn’t seem so hard, does it ? Well, the trouble is that we have to fill in some of the header fields… for instance, we must provide the location at which the actual image data begins, so we must know the total size of the headers and palette. These values can be read or calculated from the content of the image. The following code performs that task and returns an ImageSource from the clipboard :

        private ImageSource ImageFromClipboardDib()
            MemoryStream ms = Clipboard.GetData("DeviceIndependentBitmap") as MemoryStream;
            if (ms != null)
                byte[] dibBuffer = new byte[ms.Length];
                ms.Read(dibBuffer, 0, dibBuffer.Length);

                BITMAPINFOHEADER infoHeader =

                int fileHeaderSize = Marshal.SizeOf(typeof(BITMAPFILEHEADER));
                int infoHeaderSize = infoHeader.biSize;
                int fileSize = fileHeaderSize + infoHeader.biSize + infoHeader.biSizeImage;

                BITMAPFILEHEADER fileHeader = new BITMAPFILEHEADER();
                fileHeader.bfType = BITMAPFILEHEADER.BM;
                fileHeader.bfSize = fileSize;
                fileHeader.bfReserved1 = 0;
                fileHeader.bfReserved2 = 0;
                fileHeader.bfOffBits = fileHeaderSize + infoHeaderSize + infoHeader.biClrUsed * 4;

                byte[] fileHeaderBytes =

                MemoryStream msBitmap = new MemoryStream();
                msBitmap.Write(fileHeaderBytes, 0, fileHeaderSize);
                msBitmap.Write(dibBuffer, 0, dibBuffer.Length);
                msBitmap.Seek(0, SeekOrigin.Begin);

                return BitmapFrame.Create(msBitmap);
            return null;

Definition of the BITMAPFILEHEADER and BITMAPINFOHEADER structures :

        [StructLayout(LayoutKind.Sequential, Pack = 2)]
        private struct BITMAPFILEHEADER
            public static readonly short BM = 0x4d42; // BM

            public short bfType;
            public int bfSize;
            public short bfReserved1;
            public short bfReserved2;
            public int bfOffBits;

        private struct BITMAPINFOHEADER
            public int biSize;
            public int biWidth;
            public int biHeight;
            public short biPlanes;
            public short biBitCount;
            public int biCompression;
            public int biSizeImage;
            public int biXPelsPerMeter;
            public int biYPelsPerMeter;
            public int biClrUsed;
            public int biClrImportant;

Utility class to convert structures to binary :

    public static class BinaryStructConverter
        public static T FromByteArray<T>(byte[] bytes) where T : struct
            IntPtr ptr = IntPtr.Zero;
                int size = Marshal.SizeOf(typeof(T));
                ptr = Marshal.AllocHGlobal(size);
                Marshal.Copy(bytes, 0, ptr, size);
                object obj = Marshal.PtrToStructure(ptr, typeof(T));
                return (T)obj;
                if (ptr != IntPtr.Zero)

        public static byte[] ToByteArray<T>(T obj) where T : struct
            IntPtr ptr = IntPtr.Zero;
                int size = Marshal.SizeOf(typeof(T));
                ptr = Marshal.AllocHGlobal(size);
                Marshal.StructureToPtr(obj, ptr, true);
                byte[] bytes = new byte[size];
                Marshal.Copy(ptr, bytes, 0, size);
                return bytes;
                if (ptr != IntPtr.Zero)

The image returned by that code can be safely used in an Image control.

That goes to show that, even with a state-of-the-art technology like WPF, we still have to get our hands dirty sometimes ;). Let’s hope Microsoft will fix this in a later version…


  1. Pavan says:

    Awesome! Thanks a lot… I was looking for just this.

    5 star for making it so clear…copy code…paste code…works like a charm.

  2. Random832 says:

    I actually ran into this today – the problem with the image from the clipboard is that it is treated as a 32-bit ARGB image, but the “alpha channel” is garbage that depends on how something was drawn (I get mostly opaque icons, transparent everything else, translucent for some parts of the titlebar gradient, and oddly enough opaque for anything that was drawn by WPF)

  3. Yury says:

    very useful topic, which made my chief happy :-).

  4. stverhae says:

    brilliant Thanks alot!

  5. Dan Clark says:

    Hoping to get a reply here. I am using your sample code to copy the image from the clipboard, but instead if displaying the image, I want to save it directly. The direct result still produces a black image where it should be transparent…

    Any advices?

    • Not sure what the problem is… usually it works fine if you save the result of Clipboard.GetImage directly, the bug only occurs if you try to display the image (at least that’s what I observed)

      • Dan Clark says:

        Seems to be occuring when copying an PNG image directly from IE9 (produces a black image of where it should be transparent). A code sample

        var clipboardImage = (InteropBitmap) Clipboard.GetImage();

        Image.SaveImage(clipboardImage, Path.Combine(Config.App.ApplicationDataImagesPath, string.Format(“{0}.{1}”, imageId, “png”)));

        public static void SaveImage(BitmapSource bitmapImage, string filename)
        using (var fileStream = new FileStream(filename, FileMode.Create))
        var pngBitmapEncoder = new PngBitmapEncoder();

        And then again if I use your ImageFromClipboardDib() class instead of Clipboard.GetImage(), it still produces the same output.

  6. garek says:

    Thank you!

    This article nearly saved my life XD

  7. Bob Ranck says:

    Nice job, works great when I paste to a WPF Image! But since the image is a BitmapFrame, I have trouble saving it as a .jpg. Would you be so kind to give a code example to show me how to save the paste result to a .jpg?

    Thanks a lot. Bob

    • Thomas Levesque says:

      Hi Bob,

      You could do something like this:

      var frame = (BitmapFrame)ImageFromClipboardDib();
      using (var stream = File.OpenWrite(path))
          var encoder = new JpegBitmapEncoder();
  8. sdithe says:

    Hi Thomas, Thanks much for your useful post. You mentioned

    “However, if we save that image to a stream and re-read it from the stream, we get a perfectly usable image… So this could be an acceptable workaround”

    I am using following code for above method without any success(Image is still empty). Am I missing anything? imageSource is not null.

    Code –

    BitmapSource bmpSrc = System.Windows.Clipboard.GetImage();
    BitmapSource imageSource = Clipboard.GetImage();

    if (imageSource == null) return;
    BitmapImage bi = new BitmapImage();
    using (MemoryStream ms = new MemoryStream())
    BmpBitmapEncoder encoder = new BmpBitmapEncoder();
    ms.Seek(0, SeekOrigin.Begin);

    bi.StreamSource = ms;
    bi.CacheOption = BitmapCacheOption.OnLoad;

    Image img = new Image
    Source = bi


  9. Mark says:

    For VS2013 SP4 on Windows 7×64 this works:
    ImageSource bmf = BitmapFrame.Create(Clipboard.GetImage());
    return bmf;

    • Thomas Levesque says:

      Hi Mark,
      Actually, the broken behavior was fixed in .NET 4.0, so my workaround (or yours) is no longer necessary.

  10. KCS says:

    Actually, the broken behaviour STILL PERSISTS, I am using VS2013 with .NET 4.5, so thankyou for your workaround, which allowed me to capture from paint, snipping tool, Internet Explorer.

  11. Thomas says:

    Thank you for that workaround, still works perfectly. Could you publish this as a nuget package or would you allow to publish this (github + nuget)?

    • Thomas Levesque says:

      Hi Thomas,

      To be honest, I have absolutely no interest in publishing it myself. It’s an old and ugly piece of code (and now useless, as far as I can tell, unless you’re using .NET 3.5), and if I publish it on NuGet, I’ll have to maintain it, which I don’t want… But if you want to do it yourself, I won’t stop you 😉

  12. hafizh says:

    MemoryStream ms = Clipboard.GetData(“DeviceIndependentBitmap”) as MemoryStream;

    the ms always returns null, though I copy an image from my pc and try this. Any help!!

    • Thomas Levesque says:

      What does the clipboard actually contain? You can check by calling Clipboard.GetDataObject().GetFormats()

1 Trackbacks

Leave a comment