如何将32位(每像素) RGBA图像复制到Windows的剪贴板上?经过大量的尝试,我已经开始使用这个功能了,但是我的图像数据“粘贴”一点也没有。它也不会出现在剪贴板的历史记录中。
稍微编辑一下它来使用CF_DIB
和BITMAPINFOHEADER
头已经在历史上产生了一个“拷贝”条目,并在粘贴时产生了一个大小正确的图像,尽管在CF_DIB
背面粘贴一个png
会导致程序以令人难以置信的有趣和非良性的方式出现故障。
我的目标是将带有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;
}
发布于 2022-05-18 01:01:07
至少在我的经验中,尝试用BITMAPV5HEADER
传输png数据几乎是一个完全的损失,除非您基本上计划将其作为内部格式严格使用。
至少对相当数量的应用程序有效的一种策略是注册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 with和Calc、MS和Paint.Net的最新版本中。
这也是Chrome (举个例子)的格式,如果您告诉它复制位图,它将产生第一个(首选)格式。
另一方面,FireFox产生了大量的格式,而不是这个格式。它会产生一个CF_DIBV5,但至少如果内存正常的话,它会预先乘以alpha (或者它可能会完全失去α)--我不太清楚。不会像你想要的那样保存它)。
Gimp将接受32位RGB格式的DIB,其中alpha位于左字节,并使用该alpha。不管是好是坏,据我所知,这是唯一能将某些东西粘贴到Gimp中的东西,并保留它的alpha (而不是预成倍的)。
备注
随着版本的更新,
https://stackoverflow.com/questions/72280052
复制相似问题