【GDI+】C++屏幕截图

一、截全屏

保存为.bmp格式和保存为.png格式

完整代码: 

#include<windows.h>
#include <gdiplus.h>
using namespace Gdiplus;
#pragma comment(lib, "gdiplus.lib")


int GetEncoderClsid(const WCHAR *format, CLSID *pClsid)
{
	UINT  num = 0;          // number of image encoders      
	UINT  size = 0;         // size of the image encoder array in bytes      

	ImageCodecInfo* pImageCodecInfo = NULL;

	GetImageEncodersSize(&num, &size);
	if (size == 0)
		return -1;  // Failure      

	pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
	if (pImageCodecInfo == NULL)
		return -1;  // Failure      

	GetImageEncoders(num, size, pImageCodecInfo);

	for (UINT j = 0; j < num; ++j)
	{
		if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0)
		{
			*pClsid = pImageCodecInfo[j].Clsid;
			free(pImageCodecInfo);
			return j;  // Success      
		}
	}

	free(pImageCodecInfo);
	return -1;  // Failure 
}

//屏幕截图保存为bmp格式
void ScreenshotBmp()
{
	HWND hwnd = GetHWND();
	RECT rcClient;
	GetClientRect(hwnd, &rcClient);
	//1、获得指定窗口的dc(源dc)
	//注意GetWindowDC会把窗口的标题栏也同时截图,如果不需要窗口的标题就使用GetDC(hwnd)
	HDC sourceDC = GetWindowDC(hwnd);
	//2、根据源dc创建兼容内存DC
	HDC momDC;//内存DC
	momDC = ::CreateCompatibleDC(sourceDC);
	//3、根据源dc创建兼容位图
	HBITMAP memBitmap;
	memBitmap = ::CreateCompatibleBitmap(sourceDC, rcClient.right- rcClient.left, rcClient.bottom - rcClient.top);
	//4、将兼容位图写入内存dc
	SelectObject(momDC, memBitmap);
	//5、截图
	BitBlt(momDC, 0, 0, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, sourceDC, rcClient.left, rcClient.top, SRCCOPY);
	//6、以下代码保存截图信息到文件中
	//6.1获得位图信息
	BITMAP bmp;
	GetObject(memBitmap, sizeof(BITMAP), &bmp);
	//6.2图片保存路径和方式
	FILE* fp;
	fopen_s(&fp, "test.bmp", "w+b");
	//6.3创建位图文件头
	//位图文件头设置默认值为0
	BITMAPFILEHEADER bfh = { 0 };
	//到位图数据的偏移量(此步骤固定,位图编译量即为位图文件头 + 位图信息头 + 调色板的大小,调色板设置为0)
	bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
	//文件总的大小
	bfh.bfSize = bfh.bfOffBits + bmp.bmWidthBytes * bmp.bmHeight;
	//bfType固定为BM,(WORD)0x4d42表示为BM
	bfh.bfType = (WORD)0x4d42;
	//6.4创建文件信息头
	//位图信息头,默认设置为0
	BITMAPINFOHEADER bih = { 0 };
	//每个像素字节大小
	bih.biBitCount = bmp.bmBitsPixel;
	bih.biCompression = BI_RGB;
	//高度
	bih.biHeight = bmp.bmHeight;
	bih.biPlanes = 1;
	bih.biSize = sizeof(BITMAPINFOHEADER);
	//图像数据大小
	bih.biSizeImage = bmp.bmWidthBytes * bmp.bmHeight;
	//宽度
	bih.biWidth = bmp.bmWidth;
	//6.5写入位图文件头
	fwrite(&bfh, 1, sizeof(BITMAPFILEHEADER), fp);
	//6.6写入位图信息头
	fwrite(&bih, 1, sizeof(BITMAPINFOHEADER), fp);
	//6.7申请内存保存位图数据
	byte* p = new byte[bmp.bmWidthBytes * bmp.bmHeight];
	//6.8获取位图数据
	GetDIBits(momDC, (HBITMAP)memBitmap, 0, rcClient.bottom - rcClient.top, p,
		(LPBITMAPINFO)&bih, DIB_RGB_COLORS);
	//6.9写入位图数据        
	fwrite(p, 1, bmp.bmWidthBytes * bmp.bmHeight, fp);
	//6.10先删除开辟的内存,然后关闭文件
	delete[] p;
	fclose(fp);
	//7删除链接
	//7.1删除创建的位图
	DeleteObject(memBitmap);
	//7.2删除创建的兼容内存DC
	DeleteDC(momDC);
	//7.3#释放窗口DC
	ReleaseDC(hwnd, sourceDC);
}

//屏幕截图保存为png格式
void ScreenshotPng()
{
	HWND hwnd = GetHWND();

	HDC hdcScreen = GetDC(hwnd);
	HDC hdcWindow = CreateCompatibleDC(hdcScreen);
	RECT rcClient;
	GetClientRect(hwnd, &rcClient);
	HBITMAP hbmScreen = CreateCompatibleBitmap(hdcScreen, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top);
	SelectObject(hdcWindow, hbmScreen);
	// 拷贝屏幕内容到设备上下文
	BitBlt(hdcWindow, 0, 0, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, hdcScreen, rcClient.left, rcClient.top, SRCCOPY);

	GdiplusStartupInput gdiplusStartupInput;
	ULONG_PTR gdiplusToken;
	GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

	Gdiplus::Bitmap bmp(hbmScreen, NULL);
	CLSID pngClsid;
	int i = GetEncoderClsid(L"image/png", &pngClsid);
	bmp.Save(L"test.png", &pngClsid, NULL);

	GdiplusShutdown(gdiplusToken);
	// 释放资源
	DeleteObject(hbmScreen);
	DeleteDC(hdcWindow);
	ReleaseDC(hwnd, hdcScreen);
}


二、不截全屏

void system::ScreenshotJpg(string strImageName, HWND hwnd, int nTopPadding/* = 0*/, int nBottomPadding/* = 0*/, int nLeftPadding/* = 0*/, int nRightPadding/* = 0*/)
	{
		HDC hdcScreen = GetDC(hwnd);
		HDC hdcWindow = CreateCompatibleDC(hdcScreen);
		RECT rcClient;
		GetClientRect(hwnd, &rcClient);
		rcClient.top += nTopPadding;
		rcClient.bottom -= nBottomPadding;
        rcClient.left += nLeftPadding;
		rcClient.right -= nRightPadding;
		HBITMAP hbmScreen = CreateCompatibleBitmap(hdcScreen, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top);
		SelectObject(hdcWindow, hbmScreen);
		// 拷贝屏幕内容到设备上下文
		BitBlt(hdcWindow, 0, 0, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, hdcScreen, rcClient.left, rcClient.top, SRCCOPY);

		GdiplusStartupInput gdiplusStartupInput;
		ULONG_PTR gdiplusToken;
		GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

		Gdiplus::Bitmap bmp(hbmScreen, NULL);
		CLSID pngClsid;
		int i = GetEncoderClsid(L"image/png", &pngClsid);
		strImageName.append(".png");
		bmp.Save(convert::ANSI2Unicode(strImageName.c_str()).c_str(), &pngClsid, NULL);

		GdiplusShutdown(gdiplusToken);
		// 释放资源
		DeleteObject(hbmScreen);
		DeleteDC(hdcWindow);
		ReleaseDC(hwnd, hdcScreen);
	}

参考:

1.c++ 使用win api截图指定窗口并保存图片_截图别的窗口vc-CSDN博客

2.在Windows中使用C++截取窗口截图的最佳方法是什么?_在windows中复制fork()的最佳方法是什么?_在C++中清除容器的最佳方法是什么? - 腾讯云开发者社区 - 腾讯云

3.GDI+ 总结一: 保存图像文件_gdiplus 保存图片-CSDN博客

4.C++实现一个截图功能_c++截图-CSDN博客 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值