C++ 如何仅使用direct WinAPI将独立于设备的位图放入Windows剪贴板?(无MFC或其他包装)
我已经试着让它发挥作用有一段时间了,但我似乎还没有弄明白,几个小时的谷歌搜索还没有显示出任何有用的结果 我有一个以RGBA顺序排列的32位像素阵列,我想用它们创建一个独立于设备的位图,并使用C++ 如何仅使用direct WinAPI将独立于设备的位图放入Windows剪贴板?(无MFC或其他包装),c++,bitmap,clipboard,alpha,dib,C++,Bitmap,Clipboard,Alpha,Dib,我已经试着让它发挥作用有一段时间了,但我似乎还没有弄明白,几个小时的谷歌搜索还没有显示出任何有用的结果 我有一个以RGBA顺序排列的32位像素阵列,我想用它们创建一个独立于设备的位图,并使用SetClipboardData(CF_DIBV5,dib)或类似方法将其放在剪贴板上(理想情况下,我想保留alpha通道)。注册自定义剪贴板类型不是一个选项,因为将其放在剪贴板上的目的是为了将其粘贴到另一个程序中。如果我不必手动将像素数据转换为其他格式(如平面BGRA),则可获得额外积分 我当前的代码是这样
SetClipboardData(CF_DIBV5,dib)
或类似方法将其放在剪贴板上(理想情况下,我想保留alpha通道)。注册自定义剪贴板类型不是一个选项,因为将其放在剪贴板上的目的是为了将其粘贴到另一个程序中。如果我不必手动将像素数据转换为其他格式(如平面BGRA),则可获得额外积分
我当前的代码是这样的(都在set\u clipboard\u img函数中):
if(!OpenClipboard(hwnd))返回;
BITMAPV5HEADER*信息=(BITMAPV5HEADER*)全局Alloc(GMEM_可移动,sizeof(BITMAPV5HEADER));
信息->bV5Size=sizeof(BITMAPV5HEADER);
信息->bV5Width=img_宽度;
信息->bV5Height=-img_高度;
信息->bV5Planes=1;//文档说这是这里唯一有效的值。
信息->bV5BitCount=32;
信息->bV5Compression=BI_位字段;
信息->bV5SizeImage=img_宽度*img_高度*4;
信息->bV5RedMask=0xff000000;
信息->bV5GreenMask=0x00ff0000;
信息->bV5BlueMask=0x0000ff00;
信息->bV5AlphaMask=0x000000ff;
无符号字符*buf;
//我找到的一个来源说,我可以传递一个BitMapV5头来代替BITMAPINFO,因此第一次重新解释了_转换。
HBITMAP dib=CreateDIBSection(空,重新解释投影(信息),dib\u RGB\u颜色,重新解释投影(&buf),空,0);
如果(dib==NULL){
CloseClipboard();
返回;
}
//img_pixels_ptr是非平面RGBA格式像素的无符号字符*
标准:复制(图像像素ptr,信息->bV5SizeImage,buf);
清空电路板();
自动结果=设置剪贴板数据(CF_DIBV5,dib);
如果(结果==NULL){
char-str[256];
str[255]=0;
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,NULL,GetLastError(),0,str,255,NULL);
std::cerr您无法将HBITMAP
传递给SetClipboardData()
。它需要hglobalalloc()
的HGLOBAL
。这就是SetClipboardData()
失败并出现错误的原因
您需要将您的Bitmapv5头文件
和像素数据直接放入分配的HGLOBAL
中,并将其原样放入剪贴板,完全忘记使用CreateDIBSection()
:
CF_DIBV5
17
一种内存对象,包含BitMapV5头结构,后跟位图颜色空间信息和位图位
尝试类似以下内容:
void printErr(const char *msg)
{
char str[256] = {0};
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, str, 255, NULL);
std::cerr << msg << ": " << str << std::endl;
}
...
DWORD size_pixels = img_width * img_height * 4;
HGLOBAL hMem = GlobalAlloc(GHND, sizeof(BITMAPV5HEADER) + size_pixels);
if (!hMem)
{
printErr("Error allocating memory for bitmap data");
return;
}
BITMAPV5HEADER* hdr = (BITMAPV5HEADER*) GlobalLock(hMem);
if (!hdr)
{
printErr("Error accessing memory for bitmap data");
GlobalFree(hMem);
return;
}
hdr->bV5Size = sizeof(BITMAPV5HEADER);
hdr->bV5Width = img_width;
hdr->bV5Height = -img_height;
hdr->bV5Planes = 1;
hdr->bV5BitCount = 32;
hdr->bV5Compression = BI_BITFIELDS;
hdr->bV5SizeImage = size_pixels;
hdr->bV5RedMask = 0xff000000;
hdr->bV5GreenMask = 0x00ff0000;
hdr->bV5BlueMask = 0x0000ff00;
hdr->bV5AlphaMask = 0x000000ff;
// img_pixels_ptr is a unsigned char* to the pixels in non-planar RGBA format
CopyMemory(hdr+1, img_pixels_ptr, size_pixels);
GlobalUnlock(hMem);
if (!OpenClipboard(hwnd))
{
printErr("Error opening clipboard");
}
else
{
if (!EmptyClipboard())
printErr("Error emptying clipboard");
else if (!SetClipboardData(CF_DIBV5, hMem))
printErr("Error setting bitmap on clipboard");
else
hMem = NULL; // clipboard now owns the memory
CloseClipboard();
}
if (hMem)
GlobalFree(hMem);
void printErr(const char*msg)
{
char str[256]={0};
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,NULL,GetLastError(),0,str,255,NULL);
标准:cerr BV5平面=1;
hdr->BV5BITCUNT=32;
hdr->bV5Compression=BI_位字段;
hdr->bV5SizeImage=大小_像素;
hdr->bV5RedMask=0xff000000;
hdr->bV5GreenMask=0x00ff0000;
hdr->bV5BlueMask=0x0000ff00;
hdr->bV5AlphaMask=0x000000ff;
//img_pixels_ptr是非平面RGBA格式像素的无符号字符*
CopyMemory(hdr+1,img\u像素\u ptr,大小\u像素);
GlobalUnlock(hMem);
如果(!OpenClipboard(hwnd))
{
printErr(“打开剪贴板时出错”);
}
其他的
{
如果(!EmptyClipboard())
printErr(“清空剪贴板时出错”);
else如果(!SetClipboardData(CF_DIBV5,hMem))
printErr(“在剪贴板上设置位图时出错”);
其他的
hMem=NULL;//剪贴板现在拥有内存
CloseClipboard();
}
如果(hMem)
全球自由度(hMem);
谢谢!稍作调整后,效果似乎很好(我只需颠倒四个掩码参数的顺序)。不幸的是,许多程序在从剪贴板获取数据时似乎不读取alpha通道(GIMP甚至不知道有图像).哦,好吧!不过,我可以用alpha将paste从Paint.net复制到GIMP,所以一定有办法。我必须继续查找。
void printErr(const char *msg)
{
char str[256] = {0};
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, str, 255, NULL);
std::cerr << msg << ": " << str << std::endl;
}
...
DWORD size_pixels = img_width * img_height * 4;
HGLOBAL hMem = GlobalAlloc(GHND, sizeof(BITMAPV5HEADER) + size_pixels);
if (!hMem)
{
printErr("Error allocating memory for bitmap data");
return;
}
BITMAPV5HEADER* hdr = (BITMAPV5HEADER*) GlobalLock(hMem);
if (!hdr)
{
printErr("Error accessing memory for bitmap data");
GlobalFree(hMem);
return;
}
hdr->bV5Size = sizeof(BITMAPV5HEADER);
hdr->bV5Width = img_width;
hdr->bV5Height = -img_height;
hdr->bV5Planes = 1;
hdr->bV5BitCount = 32;
hdr->bV5Compression = BI_BITFIELDS;
hdr->bV5SizeImage = size_pixels;
hdr->bV5RedMask = 0xff000000;
hdr->bV5GreenMask = 0x00ff0000;
hdr->bV5BlueMask = 0x0000ff00;
hdr->bV5AlphaMask = 0x000000ff;
// img_pixels_ptr is a unsigned char* to the pixels in non-planar RGBA format
CopyMemory(hdr+1, img_pixels_ptr, size_pixels);
GlobalUnlock(hMem);
if (!OpenClipboard(hwnd))
{
printErr("Error opening clipboard");
}
else
{
if (!EmptyClipboard())
printErr("Error emptying clipboard");
else if (!SetClipboardData(CF_DIBV5, hMem))
printErr("Error setting bitmap on clipboard");
else
hMem = NULL; // clipboard now owns the memory
CloseClipboard();
}
if (hMem)
GlobalFree(hMem);