C++实现屏幕截图(全屏截图)

 更新时间:2021年11月10日 11:01:43   作者:link-初扬  
屏幕截图已经成为了所有IM即时通讯软件的必备模块,也是日常办公中使用最频繁的功能之一。今天我们从C++开发的角度,来看看屏幕截图的主要功能点是如何实现的,感兴趣的可以了解一下

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

C++实现屏幕截图(全屏截图):https://www.jb51.net/article/140184.htm

实际使用的过程中我发现截图文件实在大,无赖又整成了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;
}

到此这篇关于C++实现屏幕截图(全屏截图)的文章就介绍到这了,更多相关C++ 屏幕截图内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Matlab中图像数字水印算法的原理与实现详解

    Matlab中图像数字水印算法的原理与实现详解

    数字水印技术作为信息隐藏技术的一个重要分支,是将信息(水印)隐藏于数字图像、视频、音频及文本文档等数字媒体中,从而实现隐秘传输、存储、标注、身份识别、版权保护和防篡改等目的。本文就来讲讲图像数字水印算法的原理与实现,感兴趣的可以了解一下
    2023-04-04
  • 基于opencv实现视频中的颜色识别功能

    基于opencv实现视频中的颜色识别功能

    这篇文章主要介绍了基于opencv实现视频中的颜色识别功能,文章详细介绍了颜色识别的原理及opencv中的颜色模型,基于c++代码实现颜色识别功能,需要的朋友可以参考下
    2022-07-07
  • C++17 使用 std::string_view避免字符串拷贝优化程序性能

    C++17 使用 std::string_view避免字符串拷贝优化程序性能

    这篇文章主要介绍了C++17 使用 std::string_view避免字符串拷贝优化程序性能,帮助大家提高程序运行速度,感兴趣的朋友可以了解下
    2020-10-10
  • C++实现十大排序算法及排序算法常见问题

    C++实现十大排序算法及排序算法常见问题

    法是程序的灵魂,无论学习什么语言,做什么工程项目,都要考虑算法的效率实现,下面这篇文章主要给大家介绍了关于C++实现十大排序算法及排序算法常见问题的相关资料,需要的朋友可以参考下
    2021-09-09
  • VC运用OPENGL加载BMP纹理图的实现方法汇总

    VC运用OPENGL加载BMP纹理图的实现方法汇总

    这篇文章主要介绍了VC运用OPENGL加载BMP纹理图的实现方法,对于更好的了解OpenGL很有帮助,需要的朋友可以参考下
    2014-07-07
  • C语言实现简单贪吃蛇小游戏

    C语言实现简单贪吃蛇小游戏

    这篇文章主要为大家详细介绍了C语言实现简单贪吃蛇小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-09-09
  • C语言逻辑运算符知识整理

    C语言逻辑运算符知识整理

    本文主要介绍C语言逻辑运算符,这里详细讲解了C语言中的逻辑运算符,并提供了实例代码以便大家学习参考,希望能帮助有需要的小伙伴
    2016-07-07
  • C语言代码实现2048游戏

    C语言代码实现2048游戏

    这篇文章主要为大家详细介绍了C语言代码实现2048游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-02-02
  • C语言实现三子棋

    C语言实现三子棋

    这篇文章主要为大家详细介绍了C语言实现三子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-01-01
  • C++数据结构之搜索二叉树的实现

    C++数据结构之搜索二叉树的实现

    了解搜索二叉树是为了STL中的map和set做铺垫,我们所熟知的AVL树和平衡搜索二叉树也需要搜索二叉树的基础。本文将详解如何利用C++实现搜索二叉树,需要的可以参考一下
    2022-05-05

最新评论