【发布时间】:2013-03-19 08:17:47
【问题描述】:
我的应用程序应该能够将 32 位图像(RGB + alpha 通道)复制到剪贴板并从剪贴板粘贴这些图像。为此,我计划使用CF_DIBV5,因为BITMAPV5HEADER 结构有一个字段bV5AlphaMask。
问题在于,对于图像数据应该如何准确地存储在剪贴板中,似乎并没有达成共识。在进行一些测试时,我发现应用程序之间存在一些差异,因此几乎不可能提出通用解决方案。
以下是我的观察:
当我将 Alpha 通道图像从 Word 2010 或 XnView 复制到剪贴板时,它会在没有预乘像素数据的情况下存储。
但是,当我使用 Firefox 或 Chrome 复制图像时,像素数据似乎被 Alpha 通道预乘。
Firefox 将
bV5AlphaMask设置为 0xff000000,而大多数其他应用程序根本不设置它,而是将其保持为 0。这很奇怪,因为这些应用程序将 DIB 放到剪贴板上,实际上包含最高 8 位的 alpha 通道但他们仍然将bV5AlphaMask设置为0。因此必须假设如果位深度为32,即使bV5AlphaMask为0,也存在alpha 通道。
长话短说,我的基本问题是:关于 Alpha 通道数据应如何存储在剪贴板上,是否有一些官方信息?我特别想知道是否必须对数据进行预乘。正如您在上面看到的,Word 2010 和 XnView 不进行预乘,而 Firefox 和 Chrome 可以。但是知道是否应该预乘颜色通道是至关重要的。
非常感谢您对此有所了解!
更新 2 粘贴到 Paint.NET 现在可以正常工作了。这是由我的代码中的一个错误引起的,如果 alpha 通道为 0,它没有将颜色通道设置为 0,即在这种情况下预乘没有正确完成,这似乎混淆了 Paint.NET。
Internet Explorer 10 的问题仍未解决。将带有 alpha 通道的 PNG 复制到剪贴板时,IE 10 只是将 24 位 CF_DIBV5 放在剪贴板上,但 Paint.NET 可以粘贴此带有 alpha 通道的位图,因此必须是 IE 10 向剪贴板公开的另一种格式。也许它暴露了 PNG 使用 CFSTR_FILECONTENTS 和 CFSTR_FILEDESCRIPTOR。
更新 我现在已经按照下面 arx 描述的方式实现了它,并且效果很好。不过,还有两件事让我不解:
1) 将 Alpha 通道图像从我的应用程序粘贴到 Paint.NET 不会保留 Alpha 通道。图像在 Paint.NET 中显得不透明。但是,从 Firefox 和 Chrome 粘贴到 Paint.NET 可以完美地工作,alpha 通道被保留了!我已经放弃了完整的 DIBV5,它与我的应用程序相同,但它仍然适用于 FF 和 Chrome,但不适用于我的应用程序,所以它必须有其他东西! Firefox 和 Chrome 一定在做一些我的应用没有做的事情!?
2) Internet Explorer 10 也是如此。将 Alpha 通道图像从 IE 10 粘贴到我的应用程序根本不起作用...我得到一个位深度为 24 的 DIB,即没有阿尔法通道。但是,当从 IE 10 粘贴到 Paint.NET 时,alpha 通道就在那里!所以这里肯定还有更多的东西......
【问题讨论】:
-
当您从浏览器复制图像时,它还会将 HTML 片段复制到剪贴板。 (Internet Explorer 还会复制图像 URL。)如果 Paint.NET 从 HTML 片段中获取 URL 并直接加载图像,这将解释 1) 和 2)。请注意,这种技术有其自身的问题:如果图像 URL 不是公开的(即,如果它需要登录),那么粘贴应用程序将无法访问它。
-
我将 PNG 上传到我的网站空间上的 .htaccess 保护文件夹,使用 Firefox 登录,将 PNG 复制到剪贴板。然后我关闭了 Firefox 并打开了 Paint.NET 并粘贴了图像……效果很好!所以它似乎没有直接使用 URL。嗯,也许我需要查看 Firefox 或 Chrome 的源代码,看看它们究竟复制了哪些内容到剪贴板?
-
当我探索这个时,我写了一个简单的工具来显示和转储剪贴板格式。我已将来源添加到我的答案中。
-
Tks 我现在意识到可能是问题所在:我只是将 CFSTR_FILEDESCRIPTOR 设置为字符串,将 CFSTR_FILECONTENTS 设置为包含 PNG 的 IStream。但是阅读 Shell Clipboard Formats 发现这要复杂得多。 AFAIU 首先需要一个包含 STGMEDIUM 的 IDataObject,该 STGMEDIUM 包含一个包含 FILEDESCRIPTOR 的 FILEGROUPDESCRIPTOR,然后是 CFSTR_FILECONTENTS 的类似过程。我对 OLE 了解不多,所以我最好不要碰它,因为这看起来很复杂,尤其是关于谁负责释放这一切,所以我忘记了 Paint.NET :)