c++ - 截图和复制的位图部分在结构上有什么区别?
问题描述
我尝试使用此处问题答案之一的代码,当我在“paint”中打开位图文件后运行它时,选择其中的一部分并复制它,程序会根据需要保存复制的图像,但是当我按 PrntScrn (屏幕截图出现在剪贴板中,并在程序中标识为位图文件)程序将其保存为位图文件,但是当我尝试打开它时,我收到一条消息,指出不支持图像格式。我想这是因为我保存图像的方式。我的问题是两种类型的图像之间有什么区别,其中一种可以正常工作,而另一种不能?
这是我的代码:
#include <iostream>
#include <fstream>
#include <windows.h>
typedef struct
{
std::uint32_t biSize;
std::int32_t biWidth;
std::int32_t biHeight;
std::uint16_t biPlanes;
std::uint16_t biBitCount;
std::uint32_t biCompression;
std::uint32_t biSizeImage;
std::int32_t biXPelsPerMeter;
std::int32_t biYPelsPerMeter;
std::uint32_t biClrUsed;
std::uint32_t biClrImportant;
} DIB;
typedef struct
{
std::uint16_t type;
std::uint32_t bfSize;
std::uint32_t reserved;
std::uint32_t offset;
} HEADER;
typedef struct
{
HEADER header;
DIB dib;
} BMP;
int main()
{
std::cout << "Format Bitmap: " << IsClipboardFormatAvailable(CF_BITMAP) << "\n";
std::cout << "Format DIB: " << IsClipboardFormatAvailable(CF_DIB) << "\n";
std::cout << "Format DIBv5: " << IsClipboardFormatAvailable(CF_DIBV5) << "\n";
if (IsClipboardFormatAvailable(CF_BITMAP) || IsClipboardFormatAvailable(CF_DIB) || IsClipboardFormatAvailable(CF_DIBV5))
{
if (OpenClipboard(NULL))
{
HANDLE hClipboard = GetClipboardData(CF_DIB);
if (!hClipboard)
{
hClipboard = GetClipboardData(CF_DIBV5);
}
if (hClipboard != NULL && hClipboard != INVALID_HANDLE_VALUE)
{
void* dib = GlobalLock(hClipboard);
if (dib)
{
DIB* info = reinterpret_cast<DIB*>(dib);
BMP bmp = { 0 };
bmp.header.type = 0x4D42;
bmp.header.offset = 54;
bmp.header.bfSize = info->biSizeImage + bmp.header.offset;
bmp.dib = *info;
std::cout << "Type: " << std::hex << bmp.header.type << std::dec << "\n";
std::cout << "bfSize: " << bmp.header.bfSize << "\n";
std::cout << "Reserved: " << bmp.header.reserved << "\n";
std::cout << "Offset: " << bmp.header.offset << "\n";
std::cout << "biSize: " << bmp.dib.biSize << "\n";
std::cout << "Width: " << bmp.dib.biWidth << "\n";
std::cout << "Height: " << bmp.dib.biHeight << "\n";
std::cout << "Planes: " << bmp.dib.biPlanes << "\n";
std::cout << "Bits: " << bmp.dib.biBitCount << "\n";
std::cout << "Compression: " << bmp.dib.biCompression << "\n";
std::cout << "Size: " << bmp.dib.biSizeImage << "\n";
std::cout << "X-res: " << bmp.dib.biXPelsPerMeter << "\n";
std::cout << "Y-res: " << bmp.dib.biYPelsPerMeter << "\n";
std::cout << "ClrUsed: " << bmp.dib.biClrUsed << "\n";
std::cout << "ClrImportant: " << bmp.dib.biClrImportant << "\n";
std::ofstream file("Test2.bmp", std::ios::out | std::ios::binary);
if (file)
{
file.write(reinterpret_cast<char*>(&bmp.header.type), sizeof(bmp.header.type));
file.write(reinterpret_cast<char*>(&bmp.header.bfSize), sizeof(bmp.header.bfSize));
file.write(reinterpret_cast<char*>(&bmp.header.reserved), sizeof(bmp.header.reserved));
file.write(reinterpret_cast<char*>(&bmp.header.offset), sizeof(bmp.header.offset));
file.write(reinterpret_cast<char*>(&bmp.dib.biSize), sizeof(bmp.dib.biSize));
file.write(reinterpret_cast<char*>(&bmp.dib.biWidth), sizeof(bmp.dib.biWidth));
file.write(reinterpret_cast<char*>(&bmp.dib.biHeight), sizeof(bmp.dib.biHeight));
file.write(reinterpret_cast<char*>(&bmp.dib.biPlanes), sizeof(bmp.dib.biPlanes));
file.write(reinterpret_cast<char*>(&bmp.dib.biBitCount), sizeof(bmp.dib.biBitCount));
file.write(reinterpret_cast<char*>(&bmp.dib.biCompression), sizeof(bmp.dib.biCompression));
file.write(reinterpret_cast<char*>(&bmp.dib.biSizeImage), sizeof(bmp.dib.biSizeImage));
file.write(reinterpret_cast<char*>(&bmp.dib.biXPelsPerMeter), sizeof(bmp.dib.biXPelsPerMeter));
file.write(reinterpret_cast<char*>(&bmp.dib.biYPelsPerMeter), sizeof(bmp.dib.biYPelsPerMeter));
file.write(reinterpret_cast<char*>(&bmp.dib.biClrUsed), sizeof(bmp.dib.biClrUsed));
file.write(reinterpret_cast<char*>(&bmp.dib.biClrImportant), sizeof(bmp.dib.biClrImportant));
file.write(reinterpret_cast<char*>(info + 1), bmp.dib.biSizeImage);
std::cout << "finished" << std::endl;
}
GlobalUnlock(dib);
}
}
CloseClipboard();
}
}
return 0;
}
解决方案
如您所想,保存图像时出错。
让我们首先分析您的代码。
这是截图的图像数据。
请注意:压缩:3 -> BI_BITFIELDS
BI_BITFIELDS:位图未压缩,颜色表由三个 DWORD(在 [MS-DTYP] 2.2.9 节中定义)颜色掩码组成,分别指定每个像素的红色、绿色和蓝色分量。这在与每像素 16 位和 32 位位图一起使用时有效。
然后我注意到很少有截图用 type 保存的情况BI_BITFIELDS
。
包括官方 GDI 示例 -> 捕获图像
部分代码:
// Get the BITMAP from the HBITMAP
GetObject(hbmScreen,sizeof(BITMAP),&bmpScreen);
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bi;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bmpScreen.bmWidth;
bi.biHeight = bmpScreen.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
DWORD dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;
所以我建议你按照官方的例子来修改当前的代码。
最快的解决方案:添加bmp.dib.biCompression = BI_RGB;
在哪里添加?
参考代码:
if (dib)
{
DIB* info = reinterpret_cast<DIB*>(dib);
BMP bmp = { 0 };
bmp.header.type = 0x4D42;
bmp.header.offset = 54;
bmp.header.bfSize = info->biSizeImage + bmp.header.offset;
bmp.dib = *info;
bmp.dib.biCompression = BI_RGB;
std::cout << "Type: " << std::hex << bmp.header.type << std::dec << "\n";
....
推荐阅读
- fedora - 如何解决 Fedora 31 上 LXD 的网络问题?
- java - java: 无法访问 scala.Serializable 类文件,因为找不到 scala.Serializable
- pglogical - 如何在 Windows 机器上安装 pglogical 扩展?
- python - 我应该在我的 Git 存储库中还是在专用的父目录中运行“pip install -r requirements.txt”?
- selenium-webdriver - selenium 有没有办法用动态名称上传最后下载的文件?
- vue.js - 当我尝试控制台日志时,vue axios 返回意外的控制台语句
- python - Web Scraping (Python) 多请求运行时间太慢
- r - 多选所有按钮导致闪亮地图中的交互性问题
- caching - 使用 Redis Pub/Sub 将数据持久化到 RDBMS
- angular - 如何刷新Angular中函数返回的参数