问题描述
我的应用程序应该能够将 32 位图像(RGB + alpha 通道)复制到剪贴板并从剪贴板粘贴这些图像.为此,我计划使用 CF_DIBV5
,因为 BITMAPV5HEADER
结构有一个字段 bV5AlphaMask
.
My application should be able to copy 32-bit images (RGB + alpha channel) to the clipboard and paste these images from the clipboard. For this I plan to use CF_DIBV5
because the BITMAPV5HEADER
structure has a field bV5AlphaMask
.
问题是对于图像数据应该如何存储在剪贴板中似乎没有达成共识.在进行一些测试时,我发现应用程序之间存在一些差异,因此几乎不可能提出通用解决方案.
The problem is that there doesn't seem to be a consensus as to how exactly the image data should be stored in the clipboard. While doing some tests I found out that there are several differences betweeen the applications making it next to impossible to come up with a general solution.
以下是我的观察:
当我将 Alpha 通道图像从 Word 2010 或 XnView 复制到剪贴板时,它在没有预乘像素数据的情况下被存储.
When I copy an alpha channel image from Word 2010 or XnView to the clipboard, it is stored without premultiplying pixel data.
然而,当我使用 Firefox 或 Chrome 复制图像时,像素数据似乎预先乘以 alpha 通道.
When I copy an image using Firefox or Chrome, however, the pixel data seems to be premultiplied by the alpha channel.
Firefox 将 bV5AlphaMask
设置为 0xff000000 而大多数其他应用程序根本不设置它而是将其保持为 0.这很奇怪,因为这些应用程序将 DIB 放到剪贴板上,实际上包含一个 alpha 通道在最高 8 位中,但他们仍然将 bV5AlphaMask
设置为 0.因此,必须假设如果位深度为 32,则即使 bV5AlphaMask
是 alpha 通道0.
Firefox sets bV5AlphaMask
to 0xff000000 whereas most other applications do not set this at all but keep it 0. This is strange because these applications put DIBs onto the clipboard that actually contain an alpha channel in the highest 8 bits but still they set bV5AlphaMask
to 0. So one has to make the assumption that if bit depth is 32 that there is an alpha channel even if bV5AlphaMask
is 0.
长话短说,我的基本问题是:是否有一些关于 Alpha 通道数据应如何存储在剪贴板上的官方信息?我特别想知道是否必须对数据进行预乘.正如您在上面看到的,Word 2010 和 XnView 没有预乘,而 Firefox 和 Chrome 可以.但是知道是否应该预乘颜色通道是至关重要的.
To cut a long story short my basic question is this: Is there some official information as to how alpha channel data should be stored on the clipboard? I'm especially interested to find out whether or not the data must be premultiplied. As you can see above, Word 2010 and XnView do not premultiply, while Firefox and Chrome do. But it is of essential importance to know whether or not the color channels should be premultiplied.
非常感谢您对此有所了解!
Thanks a lot for shedding some light onto this!
更新 2粘贴到 Paint.NET 现在工作正常.这是由我的代码中的一个错误引起的,如果 alpha 通道为 0,它没有将颜色通道设置为 0,即在这种情况下预乘没有正确完成,这似乎混淆了 Paint.NET.
UPDATE 2Pasting into Paint.NET works fine now. It was caused by a bug in my code which did not set the color channels to 0 if the alpha channel was 0, i.e. the premultiplication wasn't done correctly in this case which seems to have confused Paint.NET.
Internet Explorer 10 的问题仍未解决.将带有 alpha 通道的 PNG 复制到剪贴板时,IE 10 只是在剪贴板上放置了一个 24 位的 CF_DIBV5,但 Paint.NET 可以使用 alpha 通道粘贴此位图,因此必须是 IE 10 向剪贴板公开的另一种格式.也许它公开了一个使用 CFSTR_FILECONTENTS 和 CFSTR_FILEDESCRIPTOR 的 PNG.
Still unsolved is the problem with Internet Explorer 10. When copying a PNG with alpha channel to the clipboard, IE 10 just puts a 24-bit CF_DIBV5 on the clipboard but Paint.NET can paste this bitmap WITH alpha channel so there must be another format that IE 10 exposes to the clipboard. Maybe it exposes a PNG uses CFSTR_FILECONTENTS and CFSTR_FILEDESCRIPTOR.
更新我现在已经按照下面 arx 描述的方式实现了它,并且效果很好.不过,还有两件事让我不解:
UPDATEI've now implemented it in the way described by arx below and it works pretty well. However, there are still two things that keep me puzzled:
1) 将 alpha 通道图像从我的应用程序粘贴到 Paint.NET 不会保留 alpha 通道.该图像在 Paint.NET 中显得不透明.然而,从 Firefox 和 Chrome 粘贴到 Paint.NET 效果很好,alpha 通道被保留了!我已经放弃了完整的 DIBV5,它与我的应用程序完全相同,但它仍然适用于 FF 和 Chrome,但不适用于我的应用程序,因此它必须有其他功能!Firefox 和 Chrome 肯定在做我的应用没有做的其他事情!?
1) Pasting alpha channel images from my app into Paint.NET doesn't preserve the alpha channel. The image appears opaque in Paint.NET. HOWEVER, pasting from Firefox and Chrome into Paint.NET works perfectly, the alpha channel is preserved! I've dumped the complete DIBV5 and it is identical to my app, but still it works with FF and Chrome but not with my app so there must be something else to it! Firefox and Chrome must be doing something else that my app doesn't do!?
2) Internet Explorer 10 也是如此.将 IE 10 中的 alpha 通道图像粘贴到我的应用程序根本不起作用......我得到了一个深度为 24 的 DIB,即没有阿尔法通道.然而,当从 IE 10 粘贴到 Paint.NET 时,alpha 通道就在那里!所以这里一定还有更多的东西......
2) The same is true for Internet Explorer 10. Pasting an alpha channel image from IE 10 to my app doesn't work at all... I'm getting a DIB that has a bit depth of 24, i.e. no alpha channel at all. When pasting from IE 10 to Paint.NET, however, the alpha channel is there! So there must be something more to it here as well...
推荐答案
我确信在 CF_DIBV5 中存储 alpha 有一种正确的方法,但这真的无关紧要.应用程序已经不一致地处理它,所以如果你希望你的应用程序与其他人很好地合作,你不能使用 CF_DIBV5.
I'm sure there is a right way of storing the alpha in CF_DIBV5, but it really doesn't matter. Applications already handle it inconsistently, so if you want your application to play nicely with others you can't use CF_DIBV5.
我不久前研究了复制和粘贴透明位图.我的目标是成功地将透明位图粘贴到两个版本的 Office 和 GIMP 中.我查看了几种可能的格式:
I researched copying and pasting transparent bitmaps a while ago. My aim was to successfully paste a transparent bitmap into two versions of Office and GIMP. I looked at several possible formats:
CF_BITMAP
透明度总是被忽略.
CF_DIB
以通常的 0xAARRGGBB 格式使用 32bpp BI_RGB.GIMP 支持这一点,但没有其他支持.
Using 32bpp BI_RGB in the usual 0xAARRGGBB format. GIMP supports this but nothing else does.
CF_DIBV5
GIMP 不支持这个.
GIMP doesn't support this.
PNG"
支持粘贴:GIMP、Word 2000、Excel 2000、Excel 2007 和 PowerPoint 2007.
不支持粘贴:Word 2007 和 OneNote 2007.
Paste supported: GIMP, Word 2000, Excel 2000, Excel 2007 and PowerPoint 2007.
Paste unsupported: Word 2007 and OneNote 2007.
如果您复制位图,所有这些应用程序都可以成功导出PNG".
All of these applications successfully export "PNG" if you copy a bitmap.
但是,Word 和 OneNote 2007 将粘贴从资源管理器复制的 PNG 文件.所以我想出了以下内容:
However, Word and OneNote 2007 will paste a PNG file copied from Explorer. So I came up with the following:
复制解决方案
将您的透明位图转换为 PNG 格式.
Convert your transparent bitmap to PNG format.
宣传以下剪贴板格式:
PNG" - 原始 PNG 数据.
CF_DIB - 适用于不处理透明度的应用程序(如油漆).
CFSTR_FILEDESCRIPTOR - 使 PNG 看起来像一个文件.文件描述符应该有一个带有.png"扩展名的发明文件名.
CFSTR_FILECONTENTS - 内容必须作为 IStream
公开;仅使用 HGLOBAL
似乎不起作用.数据与PNG"数据相同.
"PNG" - the raw PNG data.
CF_DIB - for applications (like paint) that don't handle transparency.
CFSTR_FILEDESCRIPTOR - make the PNG look like a file. The file descriptor should have an invented filename with a ".png" extension.
CFSTR_FILECONTENTS - the contents must be exposed as an IStream
; just using an HGLOBAL
doesn't seem to work. The data is identical to the "PNG" data.
完成此操作后,我可以成功地将透明位图粘贴到 GIMP、Office 2000 和 Office 2007 中.您也可以将 PNG 直接粘贴到资源管理器文件夹中.
Having done this I could successfully paste transparent bitmaps into GIMP, Office 2000 and Office 2007. You can also paste the PNG directly into an Explorer folder.
更新
我意识到我只回答了问题的一半.这非常适合复制,但如果您想从仅复制 CF_DIBV5 的应用程序(如 Firefox)粘贴,则没有用.
I realised that I've only answered half the question. This is great for copying, but no use if you want to paste from an application that only copies CF_DIBV5 (like Firefox).
如果可用,我建议您使用PNG",否则回退到 CF_DIBV5,将其视为预乘.这将正确处理 Word 2010(导出PNG")、Firefox 和 Chrome.XnView 仅导出未乘的 CF_DIBV5,因此这将无法正常工作.我不确定你能不能做得更好.
I'd recommend that you use "PNG" if it's available, otherwise fall back to CF_DIBV5, treating it as premultiplied. This will correctly handle Word 2010 (which exports "PNG"), Firefox and Chrome. XnView only exports non-multiplied CF_DIBV5, so this won't work correctly. I'm not sure you can do any better.
lscf - 探索剪贴板格式的工具
这是用于显示可用剪贴板格式列表的工具的来源.它还可以将一个写入文件.我称之为lscf
.在 Visual Studio 中创建一个 win32 控制台应用程序并将此源粘贴到主函数上.它有一个非常小的错误:如果您输入错误格式名称,它永远不会显示未知格式"错误.
This is the source of a tool for displaying a list of available clipboard formats. It can also write one to a file. I called it lscf
. Create a win32 console application in Visual Studio and paste this source over the main function. It has one very minor bug: it never displays the "Unknown format" error if you mistype a format name.
#include <Windows.h>
#include <stdio.h>
#include <tchar.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
LPCTSTR cfNames[] = {
_T("CF_TEXT"),
_T("CF_BITMAP"),
_T("CF_METAFILEPICT"),
_T("CF_SYLK"),
_T("CF_DIF"),
_T("CF_TIFF"),
_T("CF_OEMTEXT"),
_T("CF_DIB"),
_T("CF_PALETTE"),
_T("CF_PENDATA"),
_T("CF_RIFF"),
_T("CF_WAVE"),
_T("CF_UNICODETEXT"),
_T("CF_ENHMETAFILE"),
_T("CF_HDROP"),
_T("CF_LOCALE"),
_T("CF_DIBV5")
};
int LookupFormat(LPCTSTR name)
{
for (int i = 0; i != ARRAY_SIZE(cfNames); ++i)
{
if (_tcscmp(cfNames[i], name) == 0)
return i + 1;
}
return RegisterClipboardFormat(name);
}
void PrintFormatName(int format)
{
if (!format)
return;
if ((format > 0) && (format <= ARRAY_SIZE(cfNames)))
{
_tprintf(_T("%s
"), cfNames[format - 1]);
}
else
{
TCHAR buffer[100];
if (GetClipboardFormatName(format, buffer, ARRAY_SIZE(buffer)))
_tprintf(_T("%s
"), buffer);
else
_tprintf(_T("#%i
"), format);
}
}
void WriteFormats()
{
int count = 0;
int format = 0;
do
{
format = EnumClipboardFormats(format);
if (format)
{
++count;
PrintFormatName(format);
}
}
while (format != 0);
if (!count)
_tprintf(_T("Clipboard is empty!
"));
}
void SaveFormat(int format, LPCTSTR filename)
{
HGLOBAL hData = (HGLOBAL)GetClipboardData(format);
LPVOID data = GlobalLock(hData);
HANDLE hFile = CreateFile(filename, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
DWORD bytesWritten;
WriteFile(hFile, data, GlobalSize(hData), &bytesWritten, 0);
CloseHandle(hFile);
}
GlobalUnlock(hData);
}
int _tmain(int argc, _TCHAR* argv[])
{
if (!OpenClipboard(0))
{
_tprintf(_T("Cannot open clipboard
"));
return 1;
}
if (argc == 1)
{
WriteFormats();
}
else if (argc == 3)
{
int format = LookupFormat(argv[1]);
if (format == 0)
{
_tprintf(_T("Unknown format
"));
return 1;
}
SaveFormat(format, argv[2]);
}
else
{
_tprintf(_T("lscf
"));
_tprintf(_T("List available clipboard formats
"));
_tprintf(_T("lscf CF_NAME filename
"));
_tprintf(_T("Write format CF_NAME to file filename
"));
}
CloseClipboard();
return 0;
}
这篇关于Win32 剪贴板和 alpha 通道图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!