所以我要做的是让我的程序截取屏幕并将其保存在计算机上。实际拍摄截图的部分我将稍后编程,我首先尝试解决如何在计算机上实际保存bmp文件的问题。我发现以下代码可以帮助我解决这个问题:
// szPathName : Specifies the pathname
// lpBits : Specifies the bitmap bits
// w : Specifies the image width
// h : Specifies the image height
bool SaveImage(char* szPathName, void* lpBits, int w, int h)
{
//Create a new file for writing
FILE *pFile = fopen(szPathName, "wb");
if(pFile == NULL)
{
return false;
}
BITMAPINFOHEADER BMIH;
BMIH.biSize = sizeof(BITMAPINFOHEADER);
BMIH.biSizeImage = w * h * 3;
// Create the bitmap for this OpenGL context
BMIH.biSize = sizeof(BITMAPINFOHEADER);
BMIH.biWidth = w;
BMIH.biHeight = h;
BMIH.biPlanes = 1;
BMIH.biBitCount = 24;
BMIH.biCompression = BI_RGB;
BMIH.biSizeImage = w * h* 3;
BITMAPFILEHEADER bmfh;
int nBitsOffset = sizeof(BITMAPFILEHEADER) + BMIH.biSize;
LONG lImageSize = BMIH.biSizeImage;
LONG lFileSize = nBitsOffset + lImageSize;
bmfh.bfType = 'B'+('M'<<8);
bmfh.bfOffBits = nBitsOffset;
bmfh.bfSize = lFileSize;
bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
//Write the bitmap file header
UINT nWrittenFileHeaderSize = fwrite(&bmfh, 1,
sizeof(BITMAPFILEHEADER), pFile);
//And then the bitmap info header
UINT nWrittenInfoHeaderSize = fwrite(&BMIH,
1, sizeof(BITMAPINFOHEADER), pFile);
//Finally, write the image data itself
//-- the data represents our drawing
UINT nWrittenDIBDataSize =
fwrite(lpBits, 1, lImageSize, pFile);
fclose(pFile);
return true;
}
那么问题是什么......我不明白变种IpBits。在代码的注释中有一个lpBits的简要说明(lpBits:指定位图位)......但我不知道这实际意味着什么。我尝试进入msdn并查看fopen和fclose函数,因为fclose是最终将使用我传递给SaveImage函数的lpbits的函数....而且似乎fclose函数中的lpBits变量依赖于在fopen函数中传递了什么变量。我试图找出&#34; wb&#34; fopen函数意味着但是没有成功(甚至在msdn上搜索)。
问题:如果我使用&#34; wb&#34;作为我之前代码中fopen函数的第二个变量,fclose函数中的lpBits究竟是什么?当我问它究竟是什么时,我的意思是......它是什么类型的变量(在代码中它被放置为void *它基本上允许它是任何变量)并且我会恭喜你可以给出的任何反馈。
谢谢你们!
答案 0 :(得分:4)
lpBits是指大小为lImageSize的字节数组。
数组的每个字节将包含一个颜色分量,顺序如下:B,G和R:每个像素占用三个字节,每个颜色分量一个。
请注意,您发布的代码未考虑每个图像行的4字节对齐。每个图像的行必须在4字节边界上对齐,因此lImageSize的正确公式为:
lImageSize = h * ((w * 3 + 3) & 0xfffffffc);
您可以自己创建lpbits:
lpbits = new BYTE[lImageSize];
或使用来自Logicrat
的答案中所述的CreateDIBSection()
答案 1 :(得分:2)
评论代码:
// lpBits stand for long pointer bits
// szPathName : Specifies the pathname -> the file path to save the image
// lpBits : Specifies the bitmap bits -> the buffer (content of the) image
// w : Specifies the image width
// h : Specifies the image height
bool SaveImage(char* szPathName, void* lpBits, int w, int h) {
// Create a new file for writing
FILE* pFile = fopen(szPathName, "wb"); // wb -> w: writable b: binary, open as writable and binary
if (pFile == NULL) {
return false;
}
BITMAPINFOHEADER BMIH; // BMP header
BMIH.biSize = sizeof(BITMAPINFOHEADER);
BMIH.biSizeImage = w * h * 3;
// Create the bitmap for this OpenGL context
BMIH.biSize = sizeof(BITMAPINFOHEADER);
BMIH.biWidth = w;
BMIH.biHeight = h;
BMIH.biPlanes = 1;
BMIH.biBitCount = 24;
BMIH.biCompression = BI_RGB;
BMIH.biSizeImage = w * h * 3;
BITMAPFILEHEADER bmfh; // Other BMP header
int nBitsOffset = sizeof(BITMAPFILEHEADER) + BMIH.biSize;
LONG lImageSize = BMIH.biSizeImage;
LONG lFileSize = nBitsOffset + lImageSize;
bmfh.bfType = 'B' + ('M' << 8);
bmfh.bfOffBits = nBitsOffset;
bmfh.bfSize = lFileSize;
bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
// Write the bitmap file header // Saving the first header to file
UINT nWrittenFileHeaderSize = fwrite(&bmfh, 1, sizeof(BITMAPFILEHEADER), pFile);
// And then the bitmap info header // Saving the second header to file
UINT nWrittenInfoHeaderSize = fwrite(&BMIH, 1, sizeof(BITMAPINFOHEADER), pFile);
// Finally, write the image data itself
//-- the data represents our drawing // Saving the file content in lpBits to file
UINT nWrittenDIBDataSize = fwrite(lpBits, 1, lImageSize, pFile);
fclose(pFile); // closing the file.
return true;
}
使用C ++替换C代码的一些改进:
改进是:
std::string
代替最初需要char*
的{{1}} const char*
代替FILE。代码:
std::ofstream
答案 2 :(得分:0)
研究Windows API CreateDIBSection()
。使用此API,Windows将为您需要的像素分配内存。当它分配内存时,它会在长指针中给你内存地址。这就是“lpbits”所指的内容 - 指向已分配位的长指针。
fopen()
中的“wb”表示“写二进制”。如果没有“b”(即,如果在第二个参数中仅使用“w”),fopen
将以文本模式打开文件,这将导致文件被写为文本,可能会以系统相关的方式更改'\ n'字符。
这是我用于类PixMapAny的构造函数,它主要用于离屏绘图,但也可用于读取像素图。
PixMapAny::PixMapAny(int width, int height, int depth)
{
m_dc.CreateCompatibleDC(NULL);
m_width = width;
m_height = height;
m_depth = depth;
// The declaration of 'fake' creates a storage area big enough to
// contain a BITMAPINFO structure composed of a BITMAPINFOHEADER
// and a 256-element array of RGBQUAD values.
long fake[266];
LPBITMAPINFO pbmi = (LPBITMAPINFO) fake;
// Initialize the area to all zeros
for(int x = 0; x < 266; x++) fake[x] = 0;
// Fill in the header with the characteristics of the bitmap we want
// to write.
pbmi->bmiHeader.biSize = sizeof(pbmi->bmiHeader);
pbmi->bmiHeader.biWidth = m_width;
pbmi->bmiHeader.biHeight = -m_height;
pbmi->bmiHeader.biPlanes = 1;
pbmi->bmiHeader.biBitCount = 24;
pbmi->bmiHeader.biCompression = BI_RGB;
// Tell the system to allocate room for the pixmap.
// 'ppvbits' receives a pointer to the pixmap memory.
m_dib = CreateDIBSection(m_dc.m_hDC, pbmi, DIB_RGB_COLORS, &m_ppvbits, NULL, 0);
// ____________________________________________________________________________
// Select the bitmap into the device context
m_prev = (CBitmap *) m_dc.SelectObject(m_dib);
// ____________________________________________________________________________
}
在此示例中,高度为负,因为像素图中的行将以自上而下的方式排序,即顶行的地址小于底行的地址。
一旦以这种方式构建了像素图,就可以轻松地复制到打开的窗口区域。这里,pDC是指向目标窗口设备上下文的指针,x和y是该窗口内的坐标:
void PixMapAny::Blit(int x, int y, CDC * pDC)
{
pDC->BitBlt(x,y,m_width,m_height,&m_dc,0,0,SRCCOPY);
}