#include <stdio.h>
#include <Windows.h>
#pragma warning(disable: 4996) // 關閉fopen, scanf等庫函數的_s警告
// 為指定大小的位圖分配內存
LPBYTE AllocateBits(int nWidth, int nHeight, int nBitcCount, int *pSize)
{
*pSize = (int)((nWidth * nBitcCount + 31) / 32) * 4 * nHeight;
if (*pSize < 0)
*pSize = -*pSize;
return (LPBYTE)malloc(*pSize);
}
int main(void)
{
BITMAPFILEHEADER fileheader;
BITMAPINFOHEADER infoheader; // 由於BITMAPINFO結構體中有一個沒用的調色板, 所以不使用那個結構體
FILE *fp;
HBITMAP hbmp; // DDB句柄
HDC hdc, hdcMem;
int width, height;
int size;
PBYTE pBits; // DIB數據
/* 獲取屏幕解析度 */
width = GetSystemMetrics(SM_CXSCREEN);
height = GetSystemMetrics(SM_CYSCREEN);
printf("屏幕解析度: %dx%d\n", width, height);
/* 創建設備有關位圖(DDB)及其DC, 並把屏幕上的內容複製到該位圖上 */
hdc = GetDC(NULL); // 獲取屏幕DC
hbmp = CreateCompatibleBitmap(hdc, width, height);
hdcMem = CreateCompatibleDC(hdc); // 創建內存DC
SelectObject(hdcMem, hbmp);
BitBlt(hdcMem, 0, 0, width, height, hdc, 0, 0, SRCCOPY);
ReleaseDC(NULL, hdc);
/* 填寫設備無關位圖(DIB)的結構體 */
ZeroMemory(&infoheader, sizeof(infoheader));
infoheader.biSize = sizeof(infoheader);
infoheader.biPlanes = 1;
infoheader.biBitCount = 24;
infoheader.biWidth = width;
infoheader.biHeight = height;
/* 為設備無關位圖分配內存, 然後把設備有關位圖轉換為設備無關位圖 */
pBits = AllocateBits(width, height, infoheader.biBitCount, &size);
GetDIBits(hdcMem, hbmp, 0, height, pBits, (BITMAPINFO *)&infoheader, DIB_RGB_COLORS); // DDB -> DIB
/* 填寫設備無關位圖文件的結構體 */
fileheader.bfReserved1 = fileheader.bfReserved2 = 0;
fileheader.bfSize = sizeof(fileheader) + sizeof(infoheader) + size;
fileheader.bfType = *(PWORD)"BM";
fileheader.bfOffBits = sizeof(fileheader) + sizeof(infoheader);
/* 打開位圖文件並寫入 */
fp = fopen("file.bmp", "wb");
if (fp != NULL)
{
fwrite(&fileheader, sizeof(fileheader), 1, fp);
fwrite(&infoheader, sizeof(infoheader), 1, fp);
fwrite(pBits, size, 1, fp);
fclose(fp);
}
else
puts("打開文件失敗");
/* 釋放內存 */
free(pBits);
DeleteObject(hbmp);
DeleteDC(hdcMem);
}