C# Win8:如何复制 .PNG 到 Windows 剪贴板并保留透明度信息的粘贴?

3

我被指派捕获一张图片,将其复制到剪贴板,并粘贴到下面的应用程序中。我必须能够支持几乎任何富文本字段,并且必须保留透明度。我的当前解决方案首先呈现白色背景。以下是我的代码:

RenderTargetBitmap包含我希望复制为 .PNG 的图像。

public static void CopyImageToClipboard(RenderTargetBitmap b)
{

    MemoryStream stream = new MemoryStream();
    PngBitmapEncoder encoder = new PngBitmapEncoder();
    encoder.Frames.Add(BitmapFrame.Create(b));
    encoder.Save(stream);

    Bitmap bmp = new Bitmap(stream);
    Bitmap blank = new Bitmap(Convert.ToInt32(b.Width), Convert.ToInt32(b.Height));
    Graphics g = Graphics.FromImage(blank);
    g.Clear(System.Drawing.Color.White);
    System.Drawing.Image img = System.Drawing.Image.FromStream(stream);
    g.DrawImage(img, 0, 0, Convert.ToInt32(b.Width), Convert.ToInt32(b.Height));

    Bitmap tempImage = new Bitmap(blank);
    blank.Dispose();
    img.Dispose();

    bmp = new Bitmap(tempImage);
    tempImage.Dispose();

    System.Windows.Forms.Clipboard.SetImage(bmp);
    stream.Dispose();
 }

问题在哪里?你不想要白色背景吗? - Adriano Repetti
是的 - 就像我上面提到的,它必须是透明的。您可能知道,将“透明”位图粘贴到富文本字段会产生灰色背景。 - BPS
g.Clear(System.Drawing.Color.White); 你这样做的原因是什么? - Blorgbeard
Blorgbeard:“我的当前解决方案首先呈现一个白色背景。” - BPS
更好的解决方案是将其作为PNG流放入剪贴板。现在大多数现代应用程序都是这样做的。 - Nyerguds
显示剩余2条评论
2个回答

3

只需选择一个随机的颜色作为背景,比如说

var background = Color.FromArgb(1, 255, 1, 255);

将背景擦除:

g.Clear(background); // instead of System.Drawing.Color.White

然后将该颜色设置为透明:
Bitmap tempImage = new Bitmap(blank);
tempImage.MakeTransparent(background);

请注意,即使使用默认的透明色,也可以很好地工作,不需要选择一个“魔术颜色”(如果需要清除背景,请检查是否需要Clear() - 可能是默认位图背景)。
g.Clear(Color.Transparent);
// ...
tempImage.MakeTransparent();

编辑:一些旧版的RTF控件不支持透明度,据我所知没有什么解决方法。一个还算靠谱的解决方法(如果你不能检测黏贴目标控件的类并读取其背景颜色)是使用 Color.FromArgb(254, 255, 255, 255)。在不支持透明度的地方使用白色,在支持透明度的地方使用完全透明(因为 MakeTransparent())。


感谢您提供的代码片段,但我又回到了灰色背景(通过在Wordpad中粘贴进行测试)。 - BPS
Wordpad是旧版RTF控件处理透明度的方式。较新版本(如Win 8.1)可以正确处理此问题(没有灰色背景)。如果您不知道目标控件(因此无法读取其背景颜色),则可以使用FromArgb(254, 255, 255, 255)方法。如果不支持,白色会被设置为透明。 - Adriano Repetti
Adriano Repetti,感谢您提供这些信息。我不知道有一种更旧/更新的处理方式。我可能需要编写代码来处理这些情况。 - BPS
@BPS 不幸的是,你所能做的很少,而且很难“检测”目标控件是否能够很好地处理它,这就是为什么只能使用一个不规范的解决方法... - Adriano Repetti
现今大部分应用程序都接受“PNG”剪贴板格式,数据对象为包含实际PNG图像字节的MemoryStream - Nyerguds
显示剩余4条评论

2
默认情况下,Windows剪贴板不支持透明度,但您可以将内容以许多类型一起放在剪贴板上,以确保大多数应用程序在其中找到一种可用的类型。通常,除了正常的非透明剪贴板位图格式外,还需要将图像以PNG和DIB格式放在剪贴板上,这样大多数应用程序都能够使用它们中的至少一个来获取其支持的图像格式中的透明部分。
但是,这些格式需要按特定方式放置在剪贴板上。它们需要将其数据(对于PNG格式而言,不是已加载的图像对象,而是实际的png文件字节)放入MemoryStream中,然后将其放置在剪贴板上。
以这种方式放置在剪贴板上的PNG将被多种应用程序接受,包括Gimp和更新的MS Office。当然,如果您也实现了其读取功能,则可以在自己的应用程序中使用它。而(相当肮脏的)DIB格式则应该可以解决大多数其他应用程序的问题,如果它们确实支持粘贴透明图像的话。
我在这个回答中详细说明了如何进行复制和检索。

https://dev59.com/9FcP5IYBdhLWcg3wlq33#46424800


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接