怎样将我们上一篇截取的位图保存在文件夹里。根据MSDN,思路是这样的,用CreateFile函数在磁盘建立一个bmp文件,用WriteFile填充该bmp文件的文件头、信息头,像素等信息。之前我们只有一个位图的句柄即,hBitmap。所以保存截图的重点是,从hBitmap着手,获得建立一张位图所需要的信息。
我们使用GetObject和GetDIBits分别得到hBitmap“携带”的位图的文件头、信息头和像素位的信息。
这里用到的主要是《windows程序设计》15章的内容
程序代码如下:
1 #include <windows.h>
2 #pragma comment(linker,"/subsystem:\"windows\"" )//我这里开始建的是控制台程序
3 HBITMAP GetBitmap();
4 LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
5 int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
6 PSTR szCmdLine, int iCmdShow)
7 {
8
9 static TCHAR szAppName [] = TEXT ("BitBlt") ;
10 HWND hwnd ;
11 MSG msg ;
12 WNDCLASS wndclass ;
13 wndclass.style = CS_HREDRAW | CS_VREDRAW ;
14 wndclass.lpfnWndProc = WndProc ;
15 wndclass.cbClsExtra = 0 ;
16 wndclass.cbWndExtra = 0 ;
17 wndclass.hInstance = hInstance ;
18 wndclass.hIcon = LoadIcon (NULL, IDI_INFORMATION) ;
19 wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
20 wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
21 wndclass.lpszMenuName = NULL ;
22 wndclass.lpszClassName = szAppName ;
23 if (!RegisterClass (&wndclass))
24 {
25 MessageBox (NULL, TEXT ("This program requires Windows NT!"),
26 szAppName, MB_ICONERROR) ;
27 return 0 ;
28 }
29 hwnd = CreateWindow (szAppName, TEXT ("BitBlt Demo"),
30 WS_OVERLAPPEDWINDOW,
31 CW_USEDEFAULT, CW_USEDEFAULT,
32 CW_USEDEFAULT, CW_USEDEFAULT,
33 NULL, NULL, hInstance, NULL) ;
34 ShowWindow (hwnd, iCmdShow) ;
35 UpdateWindow (hwnd) ;
36 while (GetMessage (&msg, NULL, 0, 0))
37 {
38 TranslateMessage (&msg) ;
39 DispatchMessage (&msg) ;
40 }
41 return msg.wParam ;
42 }
43
44 LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
45 {
46 static HDC hdcClient, hdcWindow ;
47 static HDC hdcMem;
48 HBITMAP hBitmap;
49
50 PAINTSTRUCT ps ;
51 switch (message)
52 {
53 case WM_CREATE:
54 {
55 hdcClient=GetDC(hwnd); //获得应用程序客户区窗口句柄
56 hdcWindow = GetWindowDC (NULL) ; //GetWindowDC可以获得整个应用程序窗口句柄(客户区和非客户区)
57 //当参数传值为NULL的时候,得到系统窗口的句柄
58 hBitmap=CreateCompatibleBitmap(hdcClient,100,100); //创建与设备兼容的位图,宽100像素,高100像素
59 hdcMem=CreateCompatibleDC(hdcClient); //创建内存设备环境句柄
60 SelectObject(hdcMem,hBitmap); //将位图选进内存设备环境
61 BitBlt (hdcMem, 0, 0, 100,100, hdcWindow, 0, 0, SRCCOPY) ; //将系统窗口左上角100*100的图像像素复制到内存设备环境
62
63 OpenClipboard( hwnd ) ; //打开粘贴板
64 EmptyClipboard() ; //清空粘贴板
65 SetClipboardData( CF_BITMAP, hBitmap ) ; //设置粘贴板数据,即将位图设置进粘贴板
66 //之前有将新建的位图选进内存设备环境,后来将系统窗口100*100像素图像复制移动到内存
67 //设备环境。我的理解是,将位图选进内存设备环境之后,针对内存设备环境的操作,改变了
68 //位图的内容,而不需要再将内存设备环境选进位图了
69 CloseClipboard() ; //关闭粘贴板
70
71 //Get the BITMAP from the HBITMAP
72 BITMAP bmpScreen;
73 GetObject(hBitmap,sizeof(BITMAP),&bmpScreen);
74 //设置位图信息,《windows程序设计15章节的内容》
75 BITMAPFILEHEADER bmfHeader; //位图文件头
76 BITMAPINFOHEADER bi; //信息头
77 bi.biSize = sizeof(BITMAPINFOHEADER);
78 bi.biWidth = bmpScreen.bmWidth;
79 bi.biHeight = bmpScreen.bmHeight;
80 bi.biPlanes = 1;
81 bi.biBitCount = 32;
82 bi.biCompression = BI_RGB;
83 bi.biSizeImage = 0;
84 bi.biXPelsPerMeter = 0;
85 bi.biYPelsPerMeter = 0;
86 bi.biClrUsed = 0;
87 bi.biClrImportant = 0;
88 //bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4是每一行所用的字节数
89 DWORD dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;
90
91 HANDLE hDIB = GlobalAlloc(GHND,dwBmpSize); //分配内存并锁定
92 char *lpbitmap = (char *)GlobalLock(hDIB);
93
94 //// Gets the "bits" from the bitmap and copies them into a buffer
95 // which is pointed to by lpbitmap.
96 GetDIBits(hdcWindow, hBitmap, 0,
97 (UINT)bmpScreen.bmHeight,
98 lpbitmap,
99 (BITMAPINFO *)&bi, DIB_RGB_COLORS);
100
101 // A file is created, this is where we will save the screen capture.
102
103 HANDLE hFile = CreateFile("captureqwsx.bmp",
104 GENERIC_WRITE,
105 0,
106 NULL,
107 CREATE_ALWAYS,
108 FILE_ATTRIBUTE_NORMAL,
109 NULL);
110
111 // Add the size of the headers to the size of the bitmap to get the total file size
112 DWORD dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
113
114 //Offset to where the actual bitmap bits start.
115 bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
116
117 //Size of the file
118 bmfHeader.bfSize = dwSizeofDIB;
119
120 //bfType must always be BM for Bitmaps
121 bmfHeader.bfType = 0x4D42; //BM
122 DWORD dwBytesWritten = 0;
123
124 //将位图文件头,信息头,由GetDIBits获得的保存在lpbitmap指向的内存的bit写入文件中
125 WriteFile(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
126 WriteFile(hFile, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);
127 WriteFile(hFile, (LPSTR)lpbitmap, dwBmpSize, &dwBytesWritten, NULL);
128
129 //Unlock and Free the DIB from the heap
130 GlobalUnlock(hDIB);
131 GlobalFree(hDIB);
132
133 //Close the handle for the file that was created
134 CloseHandle(hFile);
135 ReleaseDC (hwnd, hdcWindow) ;
136 return 0 ;
137 }
138 case WM_SIZE:
139
140 return 0 ;
141
142 case WM_PAINT:
143 hdcClient=BeginPaint (hwnd, &ps) ;
144 BitBlt (hdcClient, 0, 0, 100,100, hdcMem, 0, 0, SRCCOPY) ; //这里我们做一个小测试,将截取的图片显示在客户区
145 //这样需要将hdcClient和hdcMem定义成static的
146 EndPaint (hwnd, &ps) ;
147 return 0 ;
148
149 case WM_DESTROY:
150 PostQuitMessage (0) ;
151 return 0 ;
152 }
153
154 return DefWindowProc (hwnd, message, wParam, lParam) ;
155
156 }
MSDN上的实例 https://msdn.microsoft.com/en-us/library/dd183402(v=vs.85).aspx
(简单翻译了下)
捕获图像
你可以bitmap去捕获一个图像,你也能将捕获的图像存储进内存,显示在你应用窗口的不同的位置,或者显示在其他的窗口上。
有时候,你可能只是想让你的应用程序暂时地捕获一张图像和存储它们。例如,当你在绘图应用上按比例缩放一张图片,应用程序必须首先临时地保存正常尺寸的图像,再显示被缩放的图像;通过复制被临时保存的正常尺寸的图像,使用者在选择正常尺寸图片时,能够替换掉被缩放的图形。
要临时地存储一张图片,你的应用必须调用CreateCompatibleDC去创建一个和你的windowDC相兼容的DC,在你创建一个兼容的DC之后,你可以通过CreateCompatibleBitmap功能函数创建一个合适尺寸的位图,再通过SelectObject函数将其选进设备环境。
兼容设备环境被创建以及合适尺寸位图被选进设备环境之后,你就可以捕获图像了。BitBlt函数可以捕获图像,该函数执行一个位块传输,它可以将资源位图的数据复制到目标位图。然后,该函数使用的非两张位图的句柄,而是两个设备环境的句柄,复制一个被选进源DC的位图数据到一个被选进目标DC的位图上。在此情形下,目标DC是一个兼容DC,所以当BitBlt完成传输之后,图形被存储在内存中,要重新显示图形,再次调用BitBlt,指定兼容DC作为原DC,并将Window DC作为目标DC就可以了。
下面的代码示例,捕获整个桌面的图像,将它缩放当适应当前窗口的大小,并将其保存进文件。
原文如下:
Capturing an Image
You can use a bitmap to capture an image, and you can store the captured image in memory, display it at a different location in your application's window, or display it in another window.
In some cases, you may want your application to capture images and store them only temporarily. For example, when you scale or zoom a picture created in a drawing application, the application must temporarily save the normal view of the image and display the zoomed view. Later, when the user selects the normal view, the application must replace the zoomed image with a copy of the normal view that it temporarily saved.
To store an image temporarily, your application must call CreateCompatibleDC to create a DC that is compatible with the current window DC. After you create a compatible DC, you create a bitmap with the appropriate dimensions by calling the CreateCompatibleBitmap function and then select it into this device context by calling the SelectObjectfunction.
After the compatible device context is created and the appropriate bitmap has been selected into it, you can capture the image. The BitBlt function captures images. This function performs a bit block transfer that is, it copies data from a source bitmap into a destination bitmap. However, the two arguments to this function are not bitmap handles. Instead, BitBlt receives handles that identify two device contexts and copies the bitmap data from a bitmap selected into the source DC into a bitmap selected into the target DC. In this case, the target DC is the compatible DC, so when BitBlt completes the transfer, the image has been stored in memory. To redisplay the image, call BitBlt a second time, specifying the compatible DC as the source DC and a window (or printer) DC as the target DC.
The following example code is from an application that captures an image of the entire desktop, scales it down to the current window size and then saves it to a file.