如何在C#winforms应用程序中从剪贴板粘贴透明图像?

如何在C#winforms应用程序中从剪贴板粘贴透明图像?,winforms,image,clipboard,transparent,paste,Winforms,Image,Clipboard,Transparent,Paste,注意:此问题是关于从剪贴板粘贴,而不是复制到剪贴板。有几篇关于复制到剪贴板的帖子,但找不到一篇能够解决此问题的帖子 如何将具有透明度的图像粘贴到winforms应用程序中并保持透明度 我尝试过使用System.Windows.Forms.GetImage(),但这会生成一个黑色背景的位图 我正在从Google Chrome复制此图像,Google Chrome支持多种剪贴板格式,包括DeviceIndependentBitmap和Format17Chrome以24bpp格式将图像复制到剪贴板。这

注意:此问题是关于从剪贴板粘贴,而不是复制到剪贴板。有几篇关于复制到剪贴板的帖子,但找不到一篇能够解决此问题的帖子

如何将具有透明度的图像粘贴到winforms应用程序中并保持透明度

我尝试过使用
System.Windows.Forms.GetImage()
,但这会生成一个黑色背景的位图


我正在从Google Chrome复制此图像,Google Chrome支持多种剪贴板格式,包括
DeviceIndependentBitmap
Format17

Chrome以24bpp格式将图像复制到剪贴板。这会将透明度变成黑色。您可以从剪贴板中获取32bpp格式,但这需要处理DIB格式。在System.Drawing中没有内置的支持。您需要一个小助手函数来进行转换:

    private Image GetImageFromClipboard() {
        if (Clipboard.GetDataObject() == null) return null;
        if (Clipboard.GetDataObject().GetDataPresent(DataFormats.Dib)) {
            var dib = ((System.IO.MemoryStream)Clipboard.GetData(DataFormats.Dib)).ToArray();
            var width = BitConverter.ToInt32(dib, 4);
            var height = BitConverter.ToInt32(dib, 8);
            var bpp = BitConverter.ToInt16(dib, 14);
            if (bpp == 32) {
                var gch = GCHandle.Alloc(dib, GCHandleType.Pinned);
                Bitmap bmp = null;
                try {
                    var ptr = new IntPtr((long)gch.AddrOfPinnedObject() + 40);
                    bmp = new Bitmap(width, height, width * 4, System.Drawing.Imaging.PixelFormat.Format32bppArgb, ptr);
                    return new Bitmap(bmp);
                }
                finally {
                    gch.Free();
                    if (bmp != null) bmp.Dispose();
                }
            }
        }
        return Clipboard.ContainsImage() ? Clipboard.GetImage() : null;
    }
示例用法:

    protected override void OnPaint(PaintEventArgs e) {
        using (var bmp = GetImageFromClipboard()) {
            if (bmp != null) e.Graphics.DrawImage(bmp, 0, 0);
        }
    }
生成此屏幕截图的窗体的BackgroundImage属性设置为库存位图:

(我不能对答案发表评论)

汉斯·帕桑的回答是好的,但不正确

您需要替换
var ptr=new IntPtr((long)gch.AddrOfPinnedObject()+40)
带有
var ptr=new IntPtr((长)gch.AddrOfPinnedObject()+52)


此外,您还需要垂直翻转图像。非常感谢。刚刚注意到-图像旋转了180度!上面的图像也从原始图像旋转。知道为什么吗?我可以用image.RotateFlip(SD.RotateFlipType.Rotate180FlipX)解决这个问题。但我不知道为什么上面的代码会导致旋转和翻转。啊,没错,位图中的扫描行是颠倒存储的。您的解决方法还可以。具有40字节头的32位DIB格式在技术上是不带alpha的RGB。这似乎经常被滥用为ARGB,但问题是无法确定每个像素数据的第4个字节是alpha还是垃圾字节。看起来40的偏移量可能取决于dib格式的某些变化。我建议重新措辞。我会说:“使用偏移量40(来自@Hans Passant的答案)在我的图像上造成了一个奇怪的边界,偏移量52修复了它。”