C++实现屏幕截图

上回分享了一个全屏截图的代码,保存为BMP,参考:C++实现屏幕截图(全屏截图)

实际使用的过程中我发现截图文件实在大,无奈又整成了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++实现屏幕截图功能
  • VC++基于Dx实现的截图程序示例代码
(0)

相关推荐

  • C++实现屏幕截图功能

    本文实例为大家分享了C++实现全屏截图功能的具体代码,供大家参考,具体内容如下 最近维护的项目,在某些情况下,光有日志还不行,于是添加了截图功能,特定情况下,会自动截图,辅助分析,从而改进程序.以下是截图实现代码. void CDemoDlg::ScreenShot(void) { CWnd *pDesktop = GetDesktopWindow(); CDC *pdeskdc = pDesktop->GetDC(); CRect re; //获取窗口的大小 pDesktop->GetCli

  • VC++基于Dx实现的截图程序示例代码

    本文所述的程序示例为VC++图象特效的截图示例,需要DirectX 3.0以上版,代码中的GetScreen函数是本截图程序的关键.运行这个程序可用Esc键结束.代码中需要ddutil.h与ddutil.cpp文件,请自行下载添加.关于InitDDraw()函数,功能是初始化DirectDraw环境,创建换页链(主页面,一个后台缓冲区),以及创建一个定时器. 具体的功能代码如下: #include <windows.h> #include <windowsx.h> #include

  • 分享js粘帖屏幕截图到web页面插件screenshot-paste

    在很多场合下,我们可能有这样的需求:提供个屏幕截图上传到系统,作为一个凭证.传统的操作方式是:屏幕截图,保存文件到本地,在web页面上选择本地文件并上传,这里至少需要三步.有没有可能直接将截图粘帖到web页面上,然后上传?答案是:可以的.这就是本文要介绍的内容了. 由于我的项目有上传屏幕截图这样的需求,为了用户体验更佳,减少操作步骤,我在网上搜了一遍之后,找到了一些眉目.为了便于复用和共享,我又对该功能做了一些封装,于是便有了这个插件 screenshot-paste.运行效果如下图: 插件调用

  • Python实现屏幕截图的代码及函数详解

    废话不多说,先给大家看下python实现屏幕截图的代码,具体代码如下所述: from selenium import webdriver import time def capture(url, save_fn="capture.png"): browser = webdriver.Firefox() # Get local session of firefox browser.set_window_size(1200, 900) browser.get(url) # Load pag

  • Android中通过view方式获取当前Activity的屏幕截图实现方法

    此方法是通过view的方式获取当前activity的屏幕截图,并不是framebuffer的方式,所以有一定的局限性.但是这种方法相对简单,容易理解. 首先通过下面的函数获取Bitmap格式的屏幕截图: 复制代码 代码如下: public Bitmap myShot(Activity activity) { // 获取windows中最顶层的view View view = activity.getWindow().getDecorView(); view.buildDrawingCache()

  • java编程实现屏幕截图(截屏)代码总结

    本文实例总结了常见的java编程实现屏幕截图方法.分享给大家供大家参考,具体如下: 方法一: import java.awt.Desktop; import java.awt.Dimension; import java.awt.Rectangle; import java.awt.Robot; import java.awt.Toolkit; import java.awt.image.BufferedImage; import java.io.File; import javax.image

  • Java实现屏幕截图及剪裁

    Java标准API中有个Robot类,该类可以实现屏幕截图,模拟鼠标键盘操作这些功能.这里只展示其屏幕截图. 截图的关键方法createScreenCapture(Rectangle rect) ,该方法需要一个Rectangle对象,Rectangle就是定义屏幕的一块矩形区域,构造Rectangle也相当容易: new Rectangle(int x, int y, int width, int height),四个参数分别是矩形左上角x坐标,矩形左上角y坐标,矩形宽度,矩形高度.截图方法返

  • Python实现屏幕截图的两种方式

    使用windows API 使用PIL中的ImageGrab模块 下面对两者的特点和用法进行详细解释. 一.Python调用windows API实现屏幕截图 好处是 灵活 速度快 缺点是: 写法繁琐 不跨平台 import time import win32gui, win32ui, win32con, win32api def window_capture(filename): hwnd = 0 # 窗口的编号,0号表示当前活跃窗口 # 根据窗口句柄获取窗口的设备上下文DC(Divice C

  • C++实现屏幕截图

    上回分享了一个全屏截图的代码,保存为BMP,参考:C++实现屏幕截图(全屏截图) 实际使用的过程中我发现截图文件实在大,无奈又整成了PNG截图,现在分享出来. MakePNG.h //MakePNG.h #pragma once #include <GdiPlus.h> using namespace Gdiplus; #pragma comment(lib,"GdiPlus.lib") class CMakePNG { public: CMakePNG(void); ~C

  • 关于Selenium的UI自动化测试屏幕截图功能实例代码

    UI自动化测试执行过程中,当遇到检查失败的情况,往往会发现打印的log并不能有效地帮助我们定位问题.我们需要失败时刻的屏幕截图来重现当时的失败场景,进而排查出错原因. 基于这种需求可以使用Selenium的屏幕截图功能. 实现代码如下: import java.io.File; import java.io.IOException; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.time.DateU

  • 对Python获取屏幕截图的4种方法详解

    Python获取电脑截图有多种方式,具体如下: PIL中的ImageGrab模块 windows API PyQt pyautogui PIL中的ImageGrab模块 import time import numpy as np from PIL import ImageGrab img = ImageGrab.grab(bbox=(100, 161, 1141, 610)) img = np.array(img.getdata(), np.uint8).reshape(img.size[1]

随机推荐