如何將 32 位(每像素)RGBA 影像復制到 Windows 的剪貼板?經過大量試驗后,我已經達到了這個功能,但我的影像資料“粘貼”一點也不走運。它也不會出現在剪貼板的歷史記錄中。
稍微編輯它以使用CF_DIB,并且標題在該歷史記錄中產生了一個“副本”條目,并在粘貼時產生了正確大小的影像,盡管在 a的背面粘貼 aBITMAPINFOHEADER會導致程式以令人難以置信的有趣和非良性方式出現故障.pngCF_DIB
我的目標是將帶有 alpha 通道的影像復制到剪貼板,并且在切換程序中顏色不會與該 alpha 相乘。我在做什么錯..?
bool copyBitmapIntoClipboard(Window & window, const Bitmap & in) {
// this section is my code for creating a png file
StreamWrite stream = StreamWrite::asBufferCreate();
in.savePng(stream);
uint64 bufSize = 0;
char * buf = stream._takeBuffer(bufSize, false);
// "buf" <-- contains the PNG payload
// "bufSize" <-- is the size of this payload
// beyond this point, it's just standard windows' stuff that doesn't rely on my code
BITMAPV5HEADER header;
header.bV5Size = sizeof(BITMAPV5HEADER);
header.bV5Width = in.getX(); // <-- size of the bitmap in pixels, width and height
header.bV5Height = in.getY();
header.bV5Planes = 1;
header.bV5BitCount = 0;
header.bV5Compression = BI_PNG;
header.bV5SizeImage = bufSize;
header.bV5XPelsPerMeter = 0;
header.bV5YPelsPerMeter = 0;
header.bV5ClrUsed = 0;
header.bV5ClrImportant = 0;
header.bV5RedMask = 0xFF000000;
header.bV5GreenMask = 0x00FF0000;
header.bV5BlueMask = 0x0000FF00;
header.bV5AlphaMask = 0x000000FF;
header.bV5CSType = LCS_sRGB;
header.bV5Endpoints; // ignored
header.bV5GammaRed = 0;
header.bV5GammaGreen = 0;
header.bV5GammaBlue = 0;
header.bV5Intent = 0;
header.bV5ProfileData = 0;
header.bV5ProfileSize = 0;
header.bV5Reserved = 0;
HGLOBAL gift = GlobalAlloc(GMEM_MOVEABLE, sizeof(BITMAPV5HEADER) bufSize);
if (gift == NULL)
return false;
HWND win = window.getWindowHandle();
if (!OpenClipboard(win)) {
GlobalFree(gift);
return false;
}
EmptyClipboard();
void * giftLocked = GlobalLock(gift);
if (giftLocked) {
memcpy(giftLocked, &header, sizeof(BITMAPV5HEADER));
memcpy((char*)giftLocked sizeof(BITMAPV5HEADER), buf, bufSize);
}
GlobalUnlock(gift);
SetClipboardData(CF_DIBV5, gift);
CloseClipboard();
return true;
}
uj5u.com熱心網友回復:
至少根據我的經驗,嘗試使用 a 傳輸 png 資料BITMAPV5HEADER幾乎是一種損失,除非您基本上計劃將其嚴格用作內部格式。
至少對相當數量的應用程式有效的一種策略是注冊PNG剪貼板格式,并將 PNG 檔案的內容放入剪貼板(沒有其他標題)。代碼看起來像這樣:
bool copyBitmapIntoClipboard(Window & window, const Bitmap & in) {
// this section is my code for creating a png file
StreamWrite stream = StreamWrite::asBufferCreate();
in.savePng(stream);
uint64 bufSize = 0;
char * buf = stream._takeBuffer(bufSize, false);
// "buf" <-- contains the PNG payload
// "bufSize" <-- is the size of this payload
HGLOBAL gift = GlobalAlloc(GMEM_MOVEABLE, bufSize);
if (gift == NULL)
return false;
HWND win = window.getWindowHandle();
if (!OpenClipboard(win)) {
GlobalFree(gift);
return false;
}
EmptyClipboard();
auto fmt = RegisterClipboardFormat("PNG"); // or `L"PNG", as applicable
void * giftLocked = GlobalLock(gift);
if (giftLocked) {
memcpy((char*)giftLocked, buf, bufSize);
}
GlobalUnlock(gift);
SetClipboardData(fmt, gift);
CloseClipboard();
return true;
}
我已經使用了這樣的代碼,并成功地將內容粘貼到了至少 LibreOffice Write 和 Calc、MS Word 和 Paint.Net 的最新版本中。
如果您告訴它復制位圖,這也是 Chrome(例如)作為第一種(首選)格式生成的格式。
另一方面,FireFox 產生了大量的格式,但不是這個。它將產生一個 CF_DIBV5,但至少如果有記憶,它具有預乘 alpha(或者它可能完全失去 alpha——我不記得了。無論如何都不會像你想要的那樣保留它)。
Gimp 將接受 32 位 RGB 格式的 DIB,在剩余位元組中帶有 alpha,并使用該 alpha。無論好壞,據我所知,這是唯一可以將某些東西粘貼到 Gimp 中并保留其 alpha (未預乘)的方法。
筆記
隨著版本的更新,它們支持的格式可能會發生變化,因此即使(例如)PNG 在我上次嘗試時不能與 Gimp 一起使用,但現在可能。
您可以將相同的資料以不同的格式添加到剪貼板中。您希望從“最佳”格式(最忠實地保留資料的格式)開始,然后逐步下降到最差的格式。因此,當您進行復制時,您可能想要執行 PNG,然后是帶有 alpha 通道的 RGB,然后是 CF_BITMAP(它將預乘 alpha,但總比沒有好)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/477620.html
上一篇:Ctypes資料型別轉換
下一篇:opengl不會重疊超過1個紋理
