我確定在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