我确定在CF_DIBV5中存储alpha的正确方法,但它确实没有关系。应用程序已经不一致地处理它,所以如果你希望你的应用程序能够很好地与其他应用程序一起玩,你就不能使用CF_DIBV5。
我研究过复制和粘贴透明位图。我的目标是成功地将透明位图粘贴到两个版本的Office和GIMP中。我看了几个可能的格式:
CF_BITMAP
透明度总是被忽略。
CF_DIB
在常规0xAARRGGBB格式使用32bpp的BI_RGB。 GIMP支持这一点,但没有别的。
CF_DIBV5
GIMP不支持这一点。
“PNG”
粘贴支持:GIMP,Word 2000中,Excel 2000中,Excel 2007和PowerPoint 2007中
粘贴不支持:Word 2007和OneNote 2007中
所有这些应用的成功如果您复制位图,则导出“PNG”。
但是,Word和OneNote 2007 将粘贴从资源管理器复制的PNG文件。所以,我想出了以下内容:
解决方案复制
将您的透明位图以PNG格式。
广告以下剪贴板格式:
“PNG” - 原始PNG数据。
CF_DIB - 用于不处理透明度的应用程序(如油漆)。
CFSTR_FILEDESCRIPTOR - 使PNG看起来像一个文件。文件描述符应该有一个带有“.png”扩展名的发明文件名。
CFSTR_FILECONTENTS - 内容必须公开为IStream
;只是使用HGLOBAL
似乎不起作用。数据与“PNG”数据相同。
完成此操作后,我可以成功地将透明位图粘贴到GIMP,Office 2000和Office 2007.您还可以将PNG直接粘贴到资源管理器文件夹中。
更新
我意识到,我只回答了一半的问题。这对复制非常有用,但如果您想从仅复制CF_DIBV5的应用程序(如Firefox)粘贴,则无用。
我建议您使用“PNG”(如果可用),否则回退到CF_DIBV5,将其视为预乘。这将正确处理Word 2010(导出“PNG”),Firefox和Chrome。 XnView只导出非乘法的CF_DIBV5,所以这将无法正常工作。我不确定你能做得更好。
LSCF - 一种探索剪贴板格式
这个工具是用于显示可用的剪贴板格式列表的工具的来源。它也可以写一个文件。我称之为lscf
。在Visual Studio中创建一个win32控制台应用程序,并将此源粘贴到主函数上。它有一个非常小的错误:如果您输错了格式名称,它从不显示“未知格式”错误。
#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\n"), cfNames[format - 1]);
}
else
{
TCHAR buffer[100];
if (GetClipboardFormatName(format, buffer, ARRAY_SIZE(buffer)))
_tprintf(_T("%s\n"), buffer);
else
_tprintf(_T("#%i\n"), 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!\n"));
}
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\n"));
return 1;
}
if (argc == 1)
{
WriteFormats();
}
else if (argc == 3)
{
int format = LookupFormat(argv[1]);
if (format == 0)
{
_tprintf(_T("Unknown format\n"));
return 1;
}
SaveFormat(format, argv[2]);
}
else
{
_tprintf(_T("lscf\n"));
_tprintf(_T("List available clipboard formats\n\n"));
_tprintf(_T("lscf CF_NAME filename\n"));
_tprintf(_T("Write format CF_NAME to file filename\n\n"));
}
CloseClipboard();
return 0;
}
当你从一个浏览器,它还会复制一个HTML片段复制到剪贴板的图像。 (Internet Explorer额外复制图像URL。)如果Paint.NET从HTML片段中获取URL并直接加载图像,这将解释1)和2)。请注意,这种技术有其自身的问题:如果图像URL不公开(即,如果它需要登录),那么粘贴应用程序将无法访问它。 – arx
我将PNG上传到我的网站空间上的.htaccess保护文件夹,使用Firefox登录,将PNG复制到剪贴板。然后我关闭Firefox并打开Paint.NET并粘贴图像......它工作的很好!所以它似乎没有直接使用URL。嗯,也许我需要查看Firefox或Chrome源代码,看看它们到剪贴板的内容到底是什么? – Andreas
当我探索这个时,我写了一个简单的工具来显示和转储剪贴板格式。我已将源添加到我的答案中。 – arx