4.窗口截图

一、前言

窗口本质上就是高速刷新的、由大量像素点组成的图片,所谓“截图”,实际上就是将某一时刻的窗口上的像素数据保存为文件的过程。

图片格式有很多,并且大都很复杂,但我们也无需过于担忧,因为这些常用的格式、都已经有别人写好的现成的库可以让我们使用了。

比如在vs中,就有官方提供的方法可以让我们非常轻易的达到这一目的。

二、使用方法

vs提供了一个atlimage.h头文件,其内存在一个图像类CImage

只要将一个窗口的设备上下文(Device context,简称DC)复制到该类,就能将该窗口的图像直接保存为图片,使用起来非常的简单。

主要用到的类和函数:

GetDeviceCaps(m_hDc, BITSPIXEL); //获取窗口DC像素的大小

GetDeviceCaps(m_hDc, HORZRES);  //获取窗口DC宽度

GetDeviceCaps(m_hDc, VERTRES);  //获取窗口DC高度

GetDpiForWindow(m_hWnd); //获取窗口单位英寸像素个数,一般电脑像素过大,windows为正常显示图标,会放大该数值,所以需要依靠该数值调整DC大小,否则截图会出现大小不适配的问题

CImage image;//用于图片操作的类

image.Create(m_width, m_hight, m_bitOfPix);//为该类创建与原窗口一样大小的DC

BitBlt(m_hImgDc, 0, 0, m_width, m_hight, m_hDc, 0, 0, SRCCOPY); //将窗口DC图像复制到image

 m_image.Save(name, Gdiplus::ImageFormatBMP); //将图像数据保存为对应文件

注意这些函数用到的参数,一般都涉及到两个概念:

  • 窗口句柄(HWND)
  • 设备上下文(Device context)

窗口句柄是用来标识一个窗口的,比如我们的操作系统桌面其实也是一个窗口,微信软件界面同样是一个窗口。

在上一章我们创建一个窗口时,相应的api的返回值也是一个窗口句柄,它的作用就是用来标识该窗口的。

有了窗口句柄,我们才能更进一步去操作这个窗口,比如通过GetDC函数拿到该窗口的设备上下文(简称DC)。

所谓设备上下文,更直白点来说就是拿到该窗口所有相关数据信息的标识,比如我们想要截图,就得拿到该窗口的所有像素数据,而像素数据就被包含在了设备上下文中。

有了窗口的DC,那么我们就可以将该窗口当前所有的像素给拷贝出来,将其存放到文件中,也就是实现了所谓的“截图”。

三、完整代码

#include<string>
#include<atlimage.h>
using namespace std;
//name:保存的文件名
//hWnd:要截图的窗口句柄,NULL表示对桌面截图
bool SavePic(wstring name,HWND hWnd) {
	HDC hDc=NULL;
	hWnd = (hWnd == NULL) ? GetDesktopWindow() : hWnd; //判断窗口句柄是否为NULL,如果为NULL则默认获取桌面DC
	hDc = GetDC(hWnd); //获取DC
	if (hDc == NULL) return false;
	int bitOfPix = GetDeviceCaps(hDc, BITSPIXEL); //获取DC像素的大小
	int width = GetDeviceCaps(hDc, HORZRES);  //获取DC宽度
	int hight = GetDeviceCaps(hDc, VERTRES);  //获取DC高度
	UINT dpi = GetDpiForWindow(hWnd); //获取dpi
	float fold; //根据dpi计算放大倍数
	switch (dpi) { 
	case 96:
		fold = 1;
		break;
	case 120:
		fold = 1.25;
		break;
	case 144:
		fold = 1.5;
		break;
	case 192:
		fold = 2;
		break;
	case 216:
		fold = 2.25;
		break;
	default:
		fold = 1;
		break;
	}
	width *= fold; //复原宽度
	hight *= fold; //复原高度
	CImage image;
	image.Create(width, hight, bitOfPix); //为图像类创建与窗口DC相同大小的DC
	BitBlt(image.GetDC(), 0, 0, width, hight, hDc, 0, 0, SRCCOPY); //将窗口DC图像复制到image
	image.Save(name.data(), Gdiplus::ImageFormatPNG); //保存为png格式图片文件
	image.ReleaseDC(); //释放DC
	ReleaseDC(hWnd, hDc); //释放DC资源
}
int main() {
	SavePic(L"1.png",NULL);//对桌面截图,保存为1.png文件
}

上面的过程总的来说都比较简单,只要你有C/C++基础,我相信你应该很容易看懂。

无非就是用到了几个相关的win api而已,如果不理解的可以直接浏览器中搜索。

主要需要注意的是这个dpi(Dots per inch),也就是“每英寸像素点”,默认情况下为96

但由于当下很多了电脑屏幕的像素都非常大,如果按照这种原有的方式进行展示,就会导致应用图标、字体都非常的小。

所以操作系统就会提供缩放功能:

image-20240329104455270

一旦调整了缩放,比如程序图标放大了,实际的效果就是单位尺寸内存的像素更多了,所以根据这个值,我们就能计算出当前系统的缩放比例,从而复原图片应该有的大小去存放像素。

不恢复的话,就会导致你的截图会比原本窗口大小更小。

其支持保存的图片格式参数有如下内容:

Gdiplus::ImageFormatUndefined
Gdiplus::ImageFormatMemoryBMP 
Gdiplus::ImageFormatBMP
Gdiplus::ImageFormatEMF 
Gdiplus::ImageFormatWMF 
Gdiplus::ImageFormatJPEG 
Gdiplus::ImageFormatPNG 
Gdiplus::ImageFormatGIF 
Gdiplus::ImageFormatTIFF 
Gdiplus::ImageFormatEXIF 
Gdiplus::ImageFormatIcon 
Gdiplus::ImageFormatHEIF
Gdiplus::ImageFormatWEBP

可根据参数后缀确定保存文件类型,但并不一定所有格式都是可用的,但基本的jpegbmpjpeg格式应该都是没问题的。

运行后,可在当前程序目录查看图片。

作者:余识
全部文章:0
会员文章:0
总阅读量:0
c/c++pythonrustJavaScriptwindowslinux