在Windows 10上使用Clipboard.GetImage()后从屏幕快照中删除的文本?

Guy*_*tag 1 c# clipboard screenshot image-processing windows-10

这很奇怪:我最近将工作站从Windows 7升级到Windows10。我有一个Chat客户端,该客户端使用以下代码从剪贴板接受图像:

if (Clipboard.ContainsImage())
{
        BitmapSource source = Clipboard.GetImage();
        BitmapFrame frame = BitmapFrame.Create(source);
        var encoder = new System.Windows.Media.Imaging.PngBitmapEncoder();
        encoder.Frames.Add(frame);
        var stream = new MemoryStream();
        encoder.Save(stream);
        byte[] daten = stream.ToArray();
        if (daten != null && daten.Length > 0)
        {
            sendFile(DateTime.Now.ToString("yyyyMMddHHmmss_") + "clipboard.png", stream.ToArray());
        }
}
Run Code Online (Sandbox Code Playgroud)

这是该地区我截图什么样子(例如,如果我把它粘贴到MS-涂料或直接从截图工具保存): 实际截图

在使用导入屏幕截图后,现在看起来是这样Clipboard.GetImage();使用Glipboard.GetImage()后的屏幕截图

如您所见,所有文本都被删除,如果您仔细观察,可以看到通常是白色的背景现在是透明的。

如果我使用JpegBitmapEncoder代替PngBitmapEncoder,它可以正常工作,因此很可能是编码问题,但这让我感到困惑:

  1. 这在Windows 7上从未发生过-Windows 10中发生了哪些变化,可能使屏幕截图有所不同?
  2. 如果我将截图保存到Snipping Tool中的文件中,则会创建一个PNG(数据本身带有PNG-Header)。那么,为什么PNG不是正确的编码?

Nye*_*uds 6

我一直在研究Windows剪贴板,我想我知道发生了什么事。请耐心等待,这是一个很长的解释,并且花了很多时间才能获得有关DIB格式的足够信息,而这正是这种混乱的核心。

默认情况下,由于遗留原因,剪贴板根本不支持透明度。最初设计剪贴板时,还没有alpha通道之类的东西。您可能知道,不过,可以将多种格式放在一起放在剪贴板上,以使读取剪贴板的程序有更广泛的获取数据的可能性,而且在最近的Windows版本中,图像显然也放到了剪贴板上。 DIB(与设备无关的位图)格式的剪贴板。现在,.Net框架v3.5通常从剪贴板中获取标准的非透明“图像”格式版本,因此它从未提供透明性,但似乎4.5可能实际上代替了该DIB。

剪贴板上的DIB技术上是每像素32位RGB图像。注意,RGB,而不是 ARGB。这意味着每个像素有四个字节,但是在正常填充红色,绿色和蓝色字节的同时,第四个字节实际上是未定义的,因此不应指望实际表示“ alpha”。只是为了使数据与四个字节的倍数精确对齐。

该DIB的内部格式设置为32位“ BITFIELDS”,这与标准的32位“ RGB”类型不同,因为它在标头中专门定义了每种颜色要使用的每个32位像素的哪些位。但是它仅定义了三个这样的位字段;用于红色,绿色和蓝色。没有第四个领域。它不应该具有alpha。考虑一下,如果该图像是由实际上只将其视为不带alpha的RGB的系统创建的,并且它不会事先清除其内存(因为许多C / C ++系统不这样做),并且实际上只写那些图像R,G和B字节,则第四个字节可能只是先前操作遗留在内存中的随机垃圾。您甚至无法确保将其清除为值0或设置为标准不透明值255。

这就是问题所在……因为许多应用程序(包括Windows 10和.Net Framework 4.5)确实将其视为此类应用。当我在由具有不同高度的2个屏幕组成的Windows 10桌面上按“打印屏幕”时,所得图像实际上是Windows本身以透明的bastard-BITFIELDS-DIB格式放在剪贴板中的。当我使用功能将该DIB保存为ARGB图像时转储该图像时,该图像上落在我实际监视器之外的区域确实是透明的,而不仅仅是黑色;它是“ alpha”字节设置为0的图像的唯一片段。因此,这似乎表明Windows 10本身也考虑了支持alpha的格式。

因此,我们这里看来似乎是Microsoft本身没有正确使用其自身规范的问题。(如果您想知道,是的,他们制定了DIB规范。)他们可以完美地切换到带有较大标头的最新DIB格式,该标头确实支持真正的Alpha,但相反,它们使用的是残酷的老式RGB格式,显然每个人(我是从Google Chrome复制图像时发现的)都假定包含alpha。

反过来,这似乎会导致像您一样的奇怪行为。我怀疑“资源管理器”窗口的绘图机制中的某些内容会用这些内容填充这些alpha字节,甚至可能是其自己的绘图层之一的alpha填充,并且在将最终图像放在剪贴板上时从未清除过。然后,正如您所注意到的,.Net框架4.5显然假设这些额外的字节确实是所获取图像的alpha通道。

解决方案是将这些字节清除为255,或者使系统将结果解释为RGB而不是ARGB。这些实际上,我可以帮你的第二个:我详细介绍如何从图像数据字节的GetImageData功能在这个答案,而这其中有我的BuildImage方法来写字节回到一个新的形象。因此,如果仅使用它来获取32位ARGB数据,然后将其写回到新的32位RGB图像中,则可以使框架将图像数据视为非透明的,而不必修改单个字节。