C++实现的屏幕截图(PNG或BMP)

上回分享了一个全屏截图的代码,保存为BMP,

C++实现屏幕截图(全屏截图)http://blog.csdn.net/sunflover454/article/details/48717731

实际使用的过程中我发现截图文件实在大,无赖又整成了PNG截图,现在分享出来。


MakePNG.h

//MakePNG.h

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

class CMakePNG
{
public:
	CMakePNG(void);
	~CMakePNG(void);

	BOOL MakePNG(HDC hDC,CRect rect,CString strFilePath);
	BOOL BMptoPNG(LPCWSTR StrBMp,LPCWSTR StrPNG);
	BOOL PNGtoBMp(LPCWSTR StrPNG,LPCWSTR StrBMp);
	BOOL GetEncoderClsid(WCHAR* pFormat,CLSID* pClsid);
private:
	GdiplusStartupInput m_gdiplusStartupInput;
	ULONG_PTR m_pGdiToken;
};

MakePNG.cpp

//MakePNG.cpp

#include "StdAfx.h"
#include "MakePNG.h"

CMakePNG::CMakePNG(void)
{
	GdiplusStartup(&m_pGdiToken,&m_gdiplusStartupInput,NULL);
}

CMakePNG::~CMakePNG(void)
{
}

/***************************************************************************/
/*	功能:		根据rect屏幕抓图,保存为文件名为strFilePath的PNG图像文件   */
/*	输入参数:	HDC	hDC					屏幕HDC;                          */
/*				CRect rect				需要的矩形;                        */
/*				CString	strFilePath		保存文件全路径(含后缀名);        */
/***************************************************************************/
BOOL CMakePNG::MakePNG(HDC hDC, CRect rect, CString strFilePath)
{
	BITMAP bmp;
	PBITMAPINFO pbmi; 
	PBITMAPINFOHEADER pbih;     // bitmap info-header 
	BITMAPFILEHEADER  hdr;      // bitmap file-header
	WORD    cClrBits; 
	LPBYTE lpBits;              // memory pointer
	DWORD dwTmp; 
	DWORD cb;                   // incremental count of bytes 
	BYTE *hp;                   // byte pointer 
	HANDLE hfile;               // file handle 
	CString szBMPFilename = strFilePath.Left(strFilePath.GetLength() - 3) + _T("bmp");//先保存成位图
	HDC hdcCompatible = CreateCompatibleDC(hDC);
	HBITMAP hbmScreen = CreateCompatibleBitmap(hDC, rect.Width(), rect.Height());

	if (hbmScreen == NULL)
	{
	    AfxMessageBox(_T("CreateCompatibleBitmap() error")); 
		return FALSE;
	}

	// Select the bitmaps into the compatible DC. 

	if (!SelectObject(hdcCompatible, hbmScreen)) 
	{
		AfxMessageBox(_T("Compatible Bitmap Selection error")); 
		return FALSE;
	}

	//Copy color data for the entire display into a 
	//bitmap that is selected into a compatible DC. 

	if (!BitBlt(hdcCompatible, 
		0,0, 
		rect.Width(), rect.Height(), 
		hDC, 
		rect.left,rect.top, 
		SRCCOPY)) 
	{
        AfxMessageBox(_T("Screen to Compat Blt Failed"));
		return FALSE;
	}



	// Retrieve the bitmap's color format, width, and height. 
	if (!GetObject(hbmScreen, sizeof(BITMAP), (LPSTR)&bmp))
	{
        AfxMessageBox(_T("GetObject()出错!"));
		return FALSE;
	}
	// Convert the color format to a count of bits. 
	cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel); 
	if (cClrBits == 1) 
		cClrBits = 1; 
	else if (cClrBits <= 4) 
		cClrBits = 4; 
	else if (cClrBits <= 8) 
		cClrBits = 8; 
	else if (cClrBits <= 16) 
		cClrBits = 16; 
	else if (cClrBits <= 24) 
		cClrBits = 24; 
	else cClrBits = 32; 

	// Allocate memory for the BITMAPINFO structure. (This structure 
	// contains a BITMAPINFOHEADER structure and an array of RGBQUAD 
	// data structures.) 

	if (cClrBits != 24) 
		pbmi = (PBITMAPINFO) LocalAlloc(LPTR, 
		sizeof(BITMAPINFOHEADER) + 
		sizeof(RGBQUAD) * (1<< cClrBits)); 

	// There is no RGBQUAD array for the 24-bit-per-pixel format. 

	else 
		pbmi = (PBITMAPINFO) LocalAlloc(LPTR, 
		sizeof(BITMAPINFOHEADER)); 

	// Initialize the fields in the BITMAPINFO structure. 

	pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 
	pbmi->bmiHeader.biWidth = bmp.bmWidth; 
	pbmi->bmiHeader.biHeight = bmp.bmHeight; 
	pbmi->bmiHeader.biPlanes = bmp.bmPlanes; 
	pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel; 
	if (cClrBits < 24) 
		pbmi->bmiHeader.biClrUsed = (1<<cClrBits); 

	// If the bitmap is not compressed, set the BI_RGB flag. 
	pbmi->bmiHeader.biCompression = BI_RGB; 

	// Compute the number of bytes in the array of color 
	// indices and store the result in biSizeImage. 
	pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8
		* pbmi->bmiHeader.biHeight; 
	// Set biClrImportant to 0, indicating that all of the device colors are important. 
	pbmi->bmiHeader.biClrImportant = 0; 

	pbih = (PBITMAPINFOHEADER) pbmi; 
	lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);

	if (!lpBits) 
	{
	    AfxMessageBox(_T("内存分配错误!"));
		return FALSE;
	}
	// Retrieve the color table (RGBQUAD array) and the bits 
	// (array of palette indices) from the DIB. 
	if (!GetDIBits(hDC, hbmScreen, 0, (WORD) pbih->biHeight, lpBits, pbmi, 
		DIB_RGB_COLORS)) 
	{
		AfxMessageBox(_T("GetDIBits() error"));
		return FALSE;
	}

	// Create the .BMP file. 
	hfile = CreateFile(szBMPFilename, 
		GENERIC_READ | GENERIC_WRITE, 
		(DWORD) 0, 
		NULL, 
		CREATE_ALWAYS, 
		FILE_ATTRIBUTE_NORMAL, 
		(HANDLE) NULL); 
	if (hfile == INVALID_HANDLE_VALUE) 
	{
		 AfxMessageBox(_T("创建文件失败"));
		return false;
	}
	hdr.bfType = 0x4d42;        // 0x42 = "B" 0x4d = "M" 
	// Compute the size of the entire file. 
	hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + 
		pbih->biSize + pbih->biClrUsed 
		* sizeof(RGBQUAD) + pbih->biSizeImage); 
	hdr.bfReserved1 = 0; 
	hdr.bfReserved2 = 0; 

	// Compute the offset to the array of color indices. 
	hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + 
		pbih->biSize + pbih->biClrUsed 
		* sizeof (RGBQUAD); 

	// Copy the BITMAPFILEHEADER into the .BMP file. 
	if (!WriteFile(hfile, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER), 
		(LPDWORD) &dwTmp,  NULL)) 
	{
		 AfxMessageBox(_T("写BMP文件头失败"));
		return FALSE;
	}

	// Copy the BITMAPINFOHEADER and RGBQUAD array into the file. 
	if (!WriteFile(hfile, (LPVOID) pbih, sizeof(BITMAPINFOHEADER) 
		+ pbih->biClrUsed * sizeof (RGBQUAD), 
		(LPDWORD) &dwTmp, ( NULL))) 
	{
		 AfxMessageBox(_T("写BMP文件头失败"));
		return FALSE;
	}

	// Copy the array of color indices into the .BMP file. 
	cb = pbih->biSizeImage; 
	hp = lpBits; 
	if (!WriteFile(hfile, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL)) 
	{
		AfxMessageBox(_T("写入BMP文件失败"));
		return FALSE;
	}

	// Close the .BMP file. 
	if (!CloseHandle(hfile)) 
	{
		 AfxMessageBox(_T("Can't close BMP file.")); 
	}

		// Free memory. 
		GlobalFree((HGLOBAL)lpBits);
	
	//转换成PNG
	if(!BMptoPNG(szBMPFilename,strFilePath))
	{
		DeleteFile(szBMPFilename);
		return FALSE;
	}
	DeleteObject(hbmScreen);
	DeleteFile(szBMPFilename);
	return TRUE;
}
// //转换BMP文件为PNG文件            
BOOL CMakePNG::BMptoPNG(LPCWSTR StrBMp,LPCWSTR StrPNG)
{
	CLSID encoderClsid;
	Status stat;
	Image* image = NULL;
	image = Bitmap::FromFile(StrBMp,TRUE);
	if (!GetEncoderClsid(L"image/png",&encoderClsid))
	{
		return FALSE;
	}
	stat = image->Save(StrPNG,&encoderClsid,NULL);
	if (stat != Ok)
	{
		return FALSE;
	}
	delete image;
	return TRUE;
}

//	功能描述:		转换PNG文件为BMP文件      
BOOL CMakePNG::PNGtoBMp(LPCWSTR StrPNG,LPCWSTR StrBMp)
{
	CLSID encoderClsid;
	Status stat;
	Image* pImage;
	pImage = Bitmap::FromFile(StrPNG,TRUE);
	if (!GetEncoderClsid(L"image/bmp",&encoderClsid))
	{
		return FALSE;
	}
	stat = pImage->Save(StrBMp,&encoderClsid,NULL);
	if (stat != Ok)
	{
		return FALSE;
	}
	delete pImage;
	return TRUE;
}

BOOL CMakePNG::GetEncoderClsid(WCHAR* pFormat,CLSID* pClsid)
{
	UINT num = 0,size = 0;
	ImageCodecInfo* pImageCodecInfo = NULL;
	GetImageEncodersSize(&num,&size);
	if (size == 0)
	{
		return FALSE;
	}
	pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
	if (pImageCodecInfo == NULL)
	{
		return FALSE;
	}
	GetImageEncoders(num,size,pImageCodecInfo);
	BOOL bfound = FALSE;
	for (UINT i = 0;!bfound && i < num;  i++)
	{
		if (_wcsicmp(pImageCodecInfo[i].MimeType,pFormat) == 0)
		{
			*pClsid = pImageCodecInfo[i].Clsid;
			bfound = TRUE;
		}
	}
	free(pImageCodecInfo);
	return bfound;
}

以上两个文件实际上是CMakePNG类,使用时需要把他们添加到项目中,调用方法如下:

wstring GetAppPathW()
{
	wchar_t szExePath[MAX_PATH] = {0};
	GetModuleFileNameW(NULL, szExePath, MAX_PATH);
	wchar_t *pstr = wcsrchr(szExePath, '\\');
	memset(pstr + 1, 0, 2);
	wstring strAppPath(szExePath);
	return strAppPath;
}

// 屏幕截图
CString CDemoDlg::ScreenShot(void)
{
	CWnd *pDesktop = GetDesktopWindow();  
	CDC *pDC = pDesktop->GetDC();  
	CRect rect;  
	//获取窗口的大小  
	pDesktop->GetClientRect(&rect);

	//保存到的文件名
	CString strFileName(GetAppPathW().c_str());
	strFileName += _T("ScreenShot\\");
	CreateDirectory((LPCTSTR)strFileName,NULL);
	CTime t = CTime::GetCurrentTime();
	CString tt = t.Format("%Y%m%d_%H%M%S");
	strFileName += tt;
	strFileName += _T(".PNG");
	//保存为PNG
	CMakePNG MakePNG;
	MakePNG.MakePNG(pDC->m_hDC,rect,strFileName);
	ReleaseDC(pDC);
	return strFileName;
}


  • 4
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要将 BMP 图像转换为 PNG 格式并添加透明度,您可以使用 C++ 的第三方库,例如 libpng 和 zlib。以下是一个简单的示例代码,它使用这些库来执行所需的 BMPPNG 转换和透明度添加: ``` #include <iostream> #include <fstream> #include <cstring> #include <png.h> #include "CImage.h" void write_png_file(char* file_name, int width, int height, png_bytep* row_pointers) { FILE* fp = fopen(file_name, "wb"); if (!fp) { std::cerr << "Error: Failed to open PNG file for writing\n"; return; } png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (!png_ptr) { std::cerr << "Error: Failed to create PNG write structure\n"; fclose(fp); return; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { std::cerr << "Error: Failed to create PNG info structure\n"; png_destroy_write_struct(&png_ptr, nullptr); fclose(fp); return; } if (setjmp(png_jmpbuf(png_ptr))) { std::cerr << "Error: Failed to initialize PNG write\n"; png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); return; } png_init_io(png_ptr, fp); if (setjmp(png_jmpbuf(png_ptr))) { std::cerr << "Error: Failed to write PNG image header\n"; png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); return; } png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_write_info(png_ptr, info_ptr); if (setjmp(png_jmpbuf(png_ptr))) { std::cerr << "Error: Failed to write PNG image data\n"; png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); return; } png_write_image(png_ptr, row_pointers); if (setjmp(png_jmpbuf(png_ptr))) { std::cerr << "Error: Failed to complete PNG write\n"; png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); return; } png_write_end(png_ptr, nullptr); png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); } void bmp_to_png_with_alpha(const char* bmp_file, const char* png_file) { CImage img; if (!img.Load(bmp_file)) { std::cerr << "Error: Failed to load BMP file\n"; return; } int width = img.GetWidth(); int height = img.GetHeight(); png_bytep* row_pointers = new png_bytep[height]; for (int y = 0; y < height; ++y) { row_pointers[y] = new png_byte[4 * width]; for (int x = 0; x < width; ++x) { COLORREF color = img.GetPixel(x, y); png_byte red = GetRValue(color); png_byte green = GetGValue(color); png_byte blue = GetBValue(color); png_byte alpha = (color != RGB(255, 0, 255)) ? 0xFF : 0x00; png_bytep pixel = &(row_pointers[y][4 * x]); pixel[0] = red; pixel[1] = green; pixel[2] = blue; pixel[3] = alpha; } } write_png_file(png_file, width, height, row_pointers); for (int y = 0; y < height; ++y) { delete[] row_pointers[y]; } delete[] row_pointers; } int main() { const char* bmp_file = "test.bmp"; const char* png_file = "test.png"; bmp_to_png_with_alpha(bmp_file, png_file); return 0; } ``` 在这个示例中,我们首先使用 CImage 类加载 BMP 图像文件。然后,我们遍历每个像素,并将其值转换为 PNG 格式,同时添加透明度(即,如果像素值为 RGB(255, 0, 255),则将其 alpha 值设置为 0,否则将其 alpha 值设置为 255)。最后,我们使用 write_png_file() 函数将转换后的 PNG 图像写入磁盘。 请注意,该示例仅提供了一个基本的转换功能。如果您需要处理大量图像或需要更高级的功能(例如,调整大小、旋转或滤镜等),则可能需要使用更强大的图像处理库,例如 OpenCV 或 ImageMagick。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值