/// <summary> /// the DIB readed should solve the issue reported here: https://sourceforge.net/projects/greenshot/forums/forum/676083/topic/6354353/index/page/1 /// </summary> /// <returns>Image</returns> private static Image GetDIBImage(IDataObject dataObejct) { try { // If the EnableSpecialDIBClipboardReader flag in the config is set, use the code from: // http://www.thomaslevesque.com/2009/02/05/wpf-paste-an-image-from-the-clipboard/ // to read the DeviceIndependentBitmap from the clipboard, this might fix bug 3576125 if (config.EnableSpecialDIBClipboardReader) { MemoryStream dibStream = GetFromDataObject(dataObejct, DataFormats.Dib) as MemoryStream; if (isValidStream(dibStream)) { LOG.Info("Found valid DIB stream, trying to process it."); byte[] dibBuffer = new byte[dibStream.Length]; dibStream.Read(dibBuffer, 0, dibBuffer.Length); BitmapInfoHeader infoHeader = BinaryStructHelper.FromByteArray <BitmapInfoHeader>(dibBuffer); LOG.InfoFormat("Using special DIB format reader for biCompression {0}", infoHeader.biCompression); int fileHeaderSize = Marshal.SizeOf(typeof(BitmapFileHeader)); uint infoHeaderSize = infoHeader.biSize; int fileSize = (int)(fileHeaderSize + infoHeader.biSize + infoHeader.biSizeImage); BitmapFileHeader fileHeader = new BitmapFileHeader(); fileHeader.bfType = BitmapFileHeader.BM; fileHeader.bfSize = fileSize; fileHeader.bfReserved1 = 0; fileHeader.bfReserved2 = 0; fileHeader.bfOffBits = (int)(fileHeaderSize + infoHeaderSize + infoHeader.biClrUsed * 4); byte[] fileHeaderBytes = BinaryStructHelper.ToByteArray <BitmapFileHeader>(fileHeader); using (MemoryStream bitmapStream = new MemoryStream()) { bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize); bitmapStream.Write(dibBuffer, 0, dibBuffer.Length); bitmapStream.Seek(0, SeekOrigin.Begin); using (Image tmpImage = Image.FromStream(bitmapStream)) { if (tmpImage != null) { return(ImageHelper.Clone(tmpImage)); } } } } } else { LOG.Info("Skipping special DIB format reader as it's disabled in the configuration."); } } catch (Exception dibEx) { LOG.Error("Problem retrieving DIB from clipboard.", dibEx); } return(null); }
public static void SetClipboardData(ISurface surface) { DataObject dataObject = new DataObject(); // This will work for Office and most other applications //ido.SetData(DataFormats.Bitmap, true, image); MemoryStream dibStream = null; MemoryStream dibV5Stream = null; MemoryStream pngStream = null; Image imageToSave = null; bool disposeImage = false; try { SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); // Create the image which is going to be saved so we don't create it multiple times disposeImage = ImageOutput.CreateImageFromSurface(surface, outputSettings, out imageToSave); try { // Create PNG stream if (config.ClipboardFormats.Contains(ClipboardFormat.PNG)) { pngStream = new MemoryStream(); // PNG works for e.g. Powerpoint SurfaceOutputSettings pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); ImageOutput.SaveToStream(imageToSave, null, pngStream, pngOutputSettings); pngStream.Seek(0, SeekOrigin.Begin); // Set the PNG stream dataObject.SetData(FORMAT_PNG, false, pngStream); } } catch (Exception pngEX) { LOG.Error("Error creating PNG for the Clipboard.", pngEX); } try { if (config.ClipboardFormats.Contains(ClipboardFormat.DIB)) { using (MemoryStream tmpBmpStream = new MemoryStream()) { // Save image as BMP SurfaceOutputSettings bmpOutputSettings = new SurfaceOutputSettings(OutputFormat.bmp, 100, false); ImageOutput.SaveToStream(imageToSave, null, tmpBmpStream, bmpOutputSettings); dibStream = new MemoryStream(); // Copy the source, but skip the "BITMAPFILEHEADER" which has a size of 14 dibStream.Write(tmpBmpStream.GetBuffer(), BITMAPFILEHEADER_LENGTH, (int)tmpBmpStream.Length - BITMAPFILEHEADER_LENGTH); } // Set the DIB to the clipboard DataObject dataObject.SetData(DataFormats.Dib, true, dibStream); } } catch (Exception dibEx) { LOG.Error("Error creating DIB for the Clipboard.", dibEx); } // CF_DibV5 try { if (config.ClipboardFormats.Contains(ClipboardFormat.DIBV5)) { // Create the stream for the clipboard dibV5Stream = new MemoryStream(); // Create the BITMAPINFOHEADER BITMAPINFOHEADER header = new BITMAPINFOHEADER(imageToSave.Width, imageToSave.Height, 32); // Make sure we have BI_BITFIELDS, this seems to be normal for Format17? header.biCompression = BI_COMPRESSION.BI_BITFIELDS; // Create a byte[] to write byte[] headerBytes = BinaryStructHelper.ToByteArray <BITMAPINFOHEADER>(header); // Write the BITMAPINFOHEADER to the stream dibV5Stream.Write(headerBytes, 0, headerBytes.Length); // As we have specified BI_COMPRESSION.BI_BITFIELDS, the BitfieldColorMask needs to be added BitfieldColorMask colorMask = new BitfieldColorMask(); // Make sure the values are set colorMask.InitValues(); // Create the byte[] from the struct byte[] colorMaskBytes = BinaryStructHelper.ToByteArray <BitfieldColorMask>(colorMask); Array.Reverse(colorMaskBytes); // Write to the stream dibV5Stream.Write(colorMaskBytes, 0, colorMaskBytes.Length); // Create the raw bytes for the pixels only byte[] bitmapBytes = BitmapToByteArray((Bitmap)imageToSave); // Write to the stream dibV5Stream.Write(bitmapBytes, 0, bitmapBytes.Length); // Set the DIBv5 to the clipboard DataObject dataObject.SetData(FORMAT_17, true, dibV5Stream); } } catch (Exception dibEx) { LOG.Error("Error creating DIB for the Clipboard.", dibEx); } // Set the HTML if (config.ClipboardFormats.Contains(ClipboardFormat.HTML)) { string tmpFile = ImageOutput.SaveToTmpFile(surface, new SurfaceOutputSettings(OutputFormat.png, 100, false), null); string html = getHTMLString(surface, tmpFile); dataObject.SetText(html, TextDataFormat.Html); } else if (config.ClipboardFormats.Contains(ClipboardFormat.HTMLDATAURL)) { string html; using (MemoryStream tmpPNGStream = new MemoryStream()) { SurfaceOutputSettings pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); // Do not allow to reduce the colors, some applications dislike 256 color images // reported with bug #3594681 pngOutputSettings.DisableReduceColors = true; // Check if we can use the previously used image if (imageToSave.PixelFormat != PixelFormat.Format8bppIndexed) { ImageOutput.SaveToStream(imageToSave, surface, tmpPNGStream, pngOutputSettings); } else { ImageOutput.SaveToStream(surface, tmpPNGStream, pngOutputSettings); } html = getHTMLDataURLString(surface, tmpPNGStream); } dataObject.SetText(html, TextDataFormat.Html); } } finally { // we need to use the SetDataOject before the streams are closed otherwise the buffer will be gone! // Check if Bitmap is wanted if (config.ClipboardFormats.Contains(ClipboardFormat.BITMAP)) { dataObject.SetImage(imageToSave); // Place the DataObject to the clipboard SetDataObject(dataObject, true); } else { // Place the DataObject to the clipboard SetDataObject(dataObject, true); } if (pngStream != null) { pngStream.Dispose(); pngStream = null; } if (dibStream != null) { dibStream.Dispose(); dibStream = null; } if (dibV5Stream != null) { dibV5Stream.Dispose(); dibV5Stream = null; } // cleanup if needed if (disposeImage && imageToSave != null) { imageToSave.Dispose(); } } }
/// <summary> /// Helper method to try to get an image in the specified format from the dataObject /// the DIB readed should solve the issue reported here: https://sourceforge.net/projects/greenshot/forums/forum/676083/topic/6354353/index/page/1 /// It also supports Format17/DibV5, by using the following information: http://stackoverflow.com/a/14335591 /// </summary> /// <param name="format">string with the format</param> /// <param name="dataObject">IDataObject</param> /// <returns>Image or null</returns> private static Image GetImageForFormat(string format, IDataObject dataObject) { object clipboardObject = GetFromDataObject(dataObject, format); MemoryStream imageStream = clipboardObject as MemoryStream; if (!isValidStream(imageStream)) { // TODO: add "HTML Format" support here... return(clipboardObject as Image); } else { if (config.EnableSpecialDIBClipboardReader) { if (format == FORMAT_17 || format == DataFormats.Dib) { LOG.Info("Found DIB stream, trying to process it."); try { byte[] dibBuffer = new byte[imageStream.Length]; imageStream.Read(dibBuffer, 0, dibBuffer.Length); BITMAPINFOHEADER infoHeader = BinaryStructHelper.FromByteArray <BITMAPINFOHEADER>(dibBuffer); if (!infoHeader.IsDibV5) { LOG.InfoFormat("Using special DIB <v5 format reader with biCompression {0}", infoHeader.biCompression); int fileHeaderSize = Marshal.SizeOf(typeof(BITMAPFILEHEADER)); uint infoHeaderSize = infoHeader.biSize; int fileSize = (int)(fileHeaderSize + infoHeader.biSize + infoHeader.biSizeImage); BITMAPFILEHEADER fileHeader = new BITMAPFILEHEADER(); fileHeader.bfType = BITMAPFILEHEADER.BM; fileHeader.bfSize = fileSize; fileHeader.bfReserved1 = 0; fileHeader.bfReserved2 = 0; fileHeader.bfOffBits = (int)(fileHeaderSize + infoHeaderSize + infoHeader.biClrUsed * 4); byte[] fileHeaderBytes = BinaryStructHelper.ToByteArray <BITMAPFILEHEADER>(fileHeader); using (MemoryStream bitmapStream = new MemoryStream()) { bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize); bitmapStream.Write(dibBuffer, 0, dibBuffer.Length); bitmapStream.Seek(0, SeekOrigin.Begin); using (Image tmpImage = Image.FromStream(bitmapStream)) { if (tmpImage != null) { return(ImageHelper.Clone(tmpImage)); } } } } else { LOG.Info("Using special DIBV5 / Format17 format reader"); // CF_DIBV5 IntPtr gcHandle = IntPtr.Zero; try { GCHandle handle = GCHandle.Alloc(dibBuffer, GCHandleType.Pinned); gcHandle = GCHandle.ToIntPtr(handle); return(new Bitmap(infoHeader.biWidth, infoHeader.biHeight, -(int)(infoHeader.biSizeImage / infoHeader.biHeight), infoHeader.biBitCount == 32 ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb, new IntPtr(handle.AddrOfPinnedObject().ToInt32() + infoHeader.OffsetToPixels + (infoHeader.biHeight - 1) * (int)(infoHeader.biSizeImage / infoHeader.biHeight)))); } catch (Exception ex) { LOG.Error("Problem retrieving Format17 from clipboard.", ex); } finally { if (gcHandle == IntPtr.Zero) { GCHandle.FromIntPtr(gcHandle).Free(); } } } } catch (Exception dibEx) { LOG.Error("Problem retrieving DIB from clipboard.", dibEx); } } } else { LOG.Info("Skipping special DIB format reader as it's disabled in the configuration."); } try { imageStream.Seek(0, SeekOrigin.Begin); using (Image tmpImage = Image.FromStream(imageStream, true, true)) { if (tmpImage != null) { LOG.InfoFormat("Got image with clipboard format {0} from the clipboard.", format); return(ImageHelper.Clone(tmpImage)); } } } catch (Exception streamImageEx) { LOG.Error(string.Format("Problem retrieving {0} from clipboard.", format), streamImageEx); } } return(null); }