c++ 封装一个截图服务

首先是抓图服务:

ICaptureHelper.h

#pragma once

#include <windows.h>
#include <string>
using std::string;

class ICaptureHelper
{
public:
  virtual ~ICaptureHelper() {}
  virtual bool Init(const string& windowName) = 0;
  virtual bool Init(HWND hwnd) = 0;
  virtual void Cleanup() = 0;
  virtual bool RefreshWindow() = 0;
  virtual bool ChangeWindowHandle(const string& windowName) = 0;
  virtual bool ChangeWindowHandle(HWND hwnd) = 0;
  virtual bool Capture() = 0;

  virtual const RECT& GetWindowRect() const = 0;
  virtual const RECT& GetClientRect() const = 0;
  virtual int GetBitmapDataSize() const = 0;
  virtual HBITMAP GetBitmap() const = 0;
  virtual void* GetBitmapAddress() const = 0;
};

CaptureService.h

#pragma once

#include "ICaptureHelper.h"
#include <map>
using std::map;

class CaptureService
{
public:
  CaptureService() = default;
  static CaptureService& GetInstance();

  enum CaptureType
  {
    //使用CreateDIBSection抓图,速度快,但是无法抓取D3D等渲染的窗口
    CreateDibSection = 0,

    //使用PrintWindow抓图,速度慢(16ms左右),但是可以抓取D3D等渲染的窗口
    PrintWindow
  };

  bool RegisterCapture(string name, string windowName, CaptureType type = CreateDibSection); //注册抓图服务
  bool RegisterCapture(string name, HWND hwnd, CaptureType type = CreateDibSection); //注册抓图服务
  void UnRegisterCapture(string name); //注销抓图服务
  bool IsRegister(string name); //获取是否已注册抓图服务

  bool RefreshWindow(string name); //刷新窗口
  bool ChangeWindowHandle(string name, string windowName); //修改窗口句柄
  bool ChangeWindowHandle(string name, HWND hwnd); //修改窗口句柄
  bool Capture(string name); //抓图

  bool GetWindowRect(string name, RECT& winRect); //获取窗口尺寸
  bool GetClientRect(string name, RECT& clientRect); //获取窗口客户区尺寸
  bool GetBitmapDataSize(string name, int& bmpDataSize); //获取抓图数据大小
  bool GetBitmap(string name, HBITMAP& bitmap); //获取窗口位图
  bool GetBitmapAddress(string name, void** bitsPtr); //获取窗口位图地址

  void Cleanup(); //清理所有抓图服务

private:
  ~CaptureService();

private:
  map<string, ICaptureHelper*> captureHelpers_;
};

其次是抓图代码封装:

AbsCaptureHelper.h

#pragma once

#include "ICaptureHelper.h"

class AbsCaptureHelper : public ICaptureHelper
{
public:
  AbsCaptureHelper();
  virtual ~AbsCaptureHelper();

  bool Init(const string& windowName) override;
  bool Init(HWND hwnd) override;
  void Cleanup() override;
  bool RefreshWindow() override;
  bool ChangeWindowHandle(const string& windowName) override;
  bool ChangeWindowHandle(HWND hwnd) override;
  bool Capture() override;

  const RECT& GetWindowRect() const override { return windowRect_; }
  const RECT& GetClientRect() const override { return clientRect_; }
  int GetBitmapDataSize() const override { return bmpDataSize_; }
  HBITMAP GetBitmap() const override { return bitmap_; }
  void* GetBitmapAddress() const override { return bitsPtr_; }

protected:
  virtual bool InitDC(const BITMAPINFO& bitmapInfo) = 0;
  virtual bool DoCapture() = 0;

protected:
  HWND hwnd_;
  HDC scrDc_;
  HDC memDc_;
  HBITMAP bitmap_;
  HBITMAP oldBitmap_;
  void* bitsPtr_;

  RECT windowRect_;
  RECT clientRect_;
  int bmpDataSize_;
};

AbsCaptureHelper.cpp

#include "stdafx.h"
#include "AbsCaptureHelper.h"

AbsCaptureHelper::AbsCaptureHelper()
  : hwnd_(nullptr)
  , scrDc_(nullptr)
  , memDc_(nullptr)
  , bitmap_(nullptr)
  , oldBitmap_(nullptr)
  , bitsPtr_(nullptr)
  , windowRect_{ 0, 0, 0, 0 }
  , clientRect_{ 0, 0, 0, 0 }
  , bmpDataSize_(0)
{
}

AbsCaptureHelper::~AbsCaptureHelper()
{
  AbsCaptureHelper::Cleanup();
}

bool AbsCaptureHelper::Init(const string& windowName)
{
  const auto handle = ::FindWindowA(nullptr, windowName.c_str());
  if (handle == nullptr)
  {
    return false;
  }

  return Init(handle);
}

bool AbsCaptureHelper::Init(HWND hwnd)
{
  hwnd_ = hwnd;

  //获取窗口大小
  if (!::GetWindowRect(hwnd_, &windowRect_) || !::GetClientRect(hwnd_, &clientRect_))
  {
    return false;
  }

  const auto clientRectWidth = clientRect_.right - clientRect_.left;
  const auto clientRectHeight = clientRect_.bottom - clientRect_.top;
  bmpDataSize_ = clientRectWidth * clientRectHeight * 4;

  //位图信息
  BITMAPINFO bitmapInfo;
  bitmapInfo.bmiHeader.biSize = sizeof(bitmapInfo);
  bitmapInfo.bmiHeader.biWidth = clientRectWidth;
  bitmapInfo.bmiHeader.biHeight = clientRectHeight;
  bitmapInfo.bmiHeader.biPlanes = 1;
  bitmapInfo.bmiHeader.biBitCount = 32;
  bitmapInfo.bmiHeader.biSizeImage = clientRectWidth * clientRectHeight;
  bitmapInfo.bmiHeader.biCompression = BI_RGB;

  return InitDC(bitmapInfo);
}

void AbsCaptureHelper::Cleanup()
{
  if (bitmap_ == nullptr)
  {
    return;
  }

  //删除用过的对象
  ::SelectObject(memDc_, oldBitmap_);
  ::DeleteObject(bitmap_);
  ::DeleteDC(memDc_);
  ::ReleaseDC(hwnd_, scrDc_);

  hwnd_ = nullptr;
  scrDc_ = nullptr;
  memDc_ = nullptr;
  bitmap_ = nullptr;
  oldBitmap_ = nullptr;
  bitsPtr_ = nullptr;
}

bool AbsCaptureHelper::RefreshWindow()
{
  const auto hwnd = hwnd_;
  Cleanup();
  return Init(hwnd);
}

bool AbsCaptureHelper::ChangeWindowHandle(const string& windowName)
{
  Cleanup();
  return Init(windowName);
}

bool AbsCaptureHelper::ChangeWindowHandle(HWND hwnd)
{
  Cleanup();
  return Init(hwnd);
}

bool AbsCaptureHelper::Capture()
{
  if (bitmap_ == nullptr || memDc_ == nullptr || scrDc_ == nullptr)
  {
    return false;
  }

  return DoCapture();
}

DibCaptureHelper.h

#pragma once

#include "AbsCaptureHelper.h"

class DibCaptureHelper : public AbsCaptureHelper
{
public:
  DibCaptureHelper();
  virtual ~DibCaptureHelper();

protected:
  bool InitDC(const BITMAPINFO& bitmapInfo) override;
  bool DoCapture() override;

private:
  bool saveBitmap_;
  int mockPageNumber;
  int bmpCount_;
};

DibCaptureHelper.cpp

#include "stdafx.h"
#include "DibCaptureHelper.h"
#include <sstream>

static int BmpCount = 0;
static int BmpMaxCount = 50;

DibCaptureHelper::DibCaptureHelper()
  : saveBitmap_(false)
  , mockPageNumber(++BmpCount)
  , bmpCount_(0)
{
}

DibCaptureHelper::~DibCaptureHelper()
{
}

bool DibCaptureHelper::InitDC(const BITMAPINFO& bitmapInfo)
{
  scrDc_ = ::GetWindowDC(hwnd_);
  memDc_ = ::CreateCompatibleDC(scrDc_);

  bitmap_ = ::CreateDIBSection(memDc_, &bitmapInfo, DIB_RGB_COLORS, &bitsPtr_, nullptr, 0);
  if (bitmap_ == nullptr)
  {
    ::DeleteDC(memDc_);
    ::ReleaseDC(hwnd_, scrDc_);
    return false;
  }

  oldBitmap_ = static_cast<HBITMAP>(::SelectObject(memDc_, bitmap_));
  return true;
}

bool DibCaptureHelper::DoCapture()
{
  const auto clientRectWidth = clientRect_.right - clientRect_.left;
  const auto clientRectHeight = clientRect_.bottom - clientRect_.top;

  const auto ret = ::BitBlt(
    memDc_, 0, 0, clientRectWidth, clientRectHeight,
    scrDc_, 0, 0, SRCCOPY);

  return ret != 0;
}

PrintCaptureHelper.h

#pragma once

#include "AbsCaptureHelper.h"

class PrintCaptureHelper : public AbsCaptureHelper
{
public:
  PrintCaptureHelper();
  virtual ~PrintCaptureHelper();

protected:
  bool InitDC(const BITMAPINFO& bitmapInfo) override;
  bool DoCapture() override;
};

PrintCaptureHelper.cpp

#include "stdafx.h"
#include "PrintCaptureHelper.h"

PrintCaptureHelper::PrintCaptureHelper()
{
}

PrintCaptureHelper::~PrintCaptureHelper()
{
}

bool PrintCaptureHelper::InitDC(const BITMAPINFO& bitmapInfo)
{
  scrDc_ = ::GetWindowDC(hwnd_);
  memDc_ = ::CreateCompatibleDC(scrDc_);

  bitmap_ = ::CreateDIBSection(scrDc_, &bitmapInfo, DIB_RGB_COLORS, &bitsPtr_, nullptr, 0);
  if (bitmap_ == nullptr)
  {
    ::DeleteDC(memDc_);
    ::ReleaseDC(hwnd_, scrDc_);
    return false;
  }

  oldBitmap_ = static_cast<HBITMAP>(::SelectObject(memDc_, bitmap_));
  return true;
}

bool PrintCaptureHelper::DoCapture()
{
  const auto ret = ::PrintWindow(hwnd_, memDc_, PW_CLIENTONLY | PW_RENDERFULLCONTENT);
  return ret != 0;
}

以上就是c++ 封装一个截图服务的详细内容,更多关于c++ 截图的资料请关注我们其它相关文章!

(0)

相关推荐

  • C++ 使用PrintWindow实现窗口截图功能

    本文使用C++双缓存进行指定窗口截图.CreateDIBSection创建应用程序可以直接写入的.与设备无关的位图(DIB),它提供内存中位图的指针,外部程序可以直接使用. 需要注意的是,PrintWindow方法能够抓取使用D3D渲染的窗口(例如Excel.Win10自带视频播放器),如果抓取普通窗口则会附带窗口阴影,可见窗口阴影是Windows使用D3D渲染出来的. 1.PrintCaptureHelper.h #pragma once #include <windows.h> #incl

  • 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

  • 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

  • c++ 封装一个截图服务

    首先是抓图服务: ICaptureHelper.h #pragma once #include <windows.h> #include <string> using std::string; class ICaptureHelper { public: virtual ~ICaptureHelper() {} virtual bool Init(const string& windowName) = 0; virtual bool Init(HWND hwnd) = 0;

  • 一篇文章带你使用Typescript封装一个Vue组件(简单易懂)

    一.搭建项目以及初始化配置 vue create ts_vue_btn 这里使用了vue CLI3自定义选择的服务,我选择了ts.stylus等工具.然后创建完项目之后,进入项目.使用快捷命令code .进入Vs code编辑器(如果没有code .,需要将编辑器的bin文件目录地址放到环境变量的path中).然后,我进入编辑器之后,进入设置工作区,随便设置一个参数,这里比如推荐设置字号,点下.这里是为了生成.vscode文件夹,里面有个json文件. 我们在开发项目的时候,项目文件夹内的文件很

  • 手把手教你将Flask应用封装成Docker服务的实现

    项目背景   在之前的一个项目中用Python的Flask写了一个提供公共基础服务的Rest应用,上面大佬的意思是需要将这一部分封装成容器化服务,实现快速部署.管理以保证连续可用性.你知道如何将你的Flask项目部署到Docker中吗? 大佬安排嘉宾席!不会的那咱们就接着往下看- 看完请记得点赞哟!点赞的人最可爱.偷偷告诉你们这段时间出于文章题材跟挑战面试了一些公司,也收到了一些offer!Python领域岗(大部分爬虫).点赞过一百的话我整理之后开篇专场如何?说不定里面就有你下一次要采得大坑!

  • 封装一个最简单ErrorBoundary组件处理react异常

    前言 从 React 16 开始,引入了 Error Boundaries 概念,它可以捕获它的子组件中产生的错误,记录错误日志,并展示降级内容,具体 官网地址 错误边界避免一个组件错误导致整个页面白屏不能使用等情况,使用优雅降级的方式呈现备用的 UI,错误边界可以在渲染期间.生命周期和整个组件树的构造函数中捕获错误.自 React 16 起,任何未被错误边界捕获的错误将会导致整个 React 组件树被卸载 ErrorBoundary 意义 某些 UI 崩溃,不至于整个 webapp 崩溃 在浏

  • 如何用C写一个web服务器之CGI协议

    目录 前言 CGI CGI请求 CGI响应 Nginx和PHP的CGI实现 SAPI PHP-FPM 纠偏 代码实现 http_parser cJSON 前言 这次更新主要实现一下 CGI 协议. 先放上GitHub链接https://github.com/zhenbianshu/tinyServer 作为一个服务器,基本要求是能受理请求,提取信息并将消息分发给 CGI 解释器,再将解释器响应的消息包装后返回客户端.在这个过程中,除了和客户端 socket 之间的交互,还要牵扯到第三个实体 -

  • 十分钟封装一个好用的axios步骤示例

    目录 前言 想想需要做什么 通用能力 一步一步添加功能实现 正常请求该有的 请求响应拦截器 全局的loading配置 统一文件下载处理 使用 前言 项目启动会议上,大家各种出排期,各种出方案,大多数人的焦点都放在后端技术方案上,感情大家好像都觉得前期准备工作前端没啥好做的,不都有现成的脚手架吗?别人不都帮你做好了吗?我丢....你说的好像不是没有道理,但是你真的用过官方的脚手架吗,除了帮我生成项目目录和打包编译之类的配置,还是有些框架层面的东西要我自己做的好吧.我不管我不管,你们都有启动准备排期

  • 用vue3封装一个符合思维且简单实用的弹出层

    目录 前言 服务式弹出层 用Promise来创建吧! 写在后头 前言 在平常开发中,弹出层算是一个最常用的组件了,尤其是后台的表单页,详情页,用户端的各种确认都很适合使用弹出层组件展示,但是一般组件库提供给我们的一般还是组件的形式,或者是一个简单的服务. 组件形式的弹出层,在我看来应该是组件库提供给我们二次封装用的,如果直接其实很不符合直觉 写在页面结构里,但是却不是在页面结构中展示,放在那个位置都不合适只能放在最下边 一个页面如果只有一个弹出层还好维护,多几个先不说放在那里,光维护弹出层的展示

  • iOS实现封装一个获取通讯录的工具类详解

    前言 本文给大家介绍了关于iOS如何封装一个获取通讯录工具类的相关内容,iOS获取通讯录一共有4个framework: AddressBook, AddressBookUI, Contacts, ContactsUI; 其中 AddressBook 和 AddressBookUI 已经被iOS9时 deprecated 了, 而推出了Contacts 和 ContactsUI 取代之. 其中 AddressBookUI 和 ContactsUI 是picker出一个界面提供选择一条联系人信息并且

  • 利用express启动一个server服务的方法

    安装express $ npm install express --save 在node.js中,我们最常用的框架就是express Express 是一个基于 Node.js 平台的极简.灵活的 web 应用开发框架,它提供一系列强大的特性,帮助你创建各种 Web 和移动设备应用. 第一步 我们要引用这个框架 let express=require('express'); 第二步 我们把这个框架挂载在一个变量上面,使我们后面调用express内置方法方便 let app=express() 第

  • Android如何从实现到封装一个MVP详解

    前言 MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负 责显示.下面这篇文章主要给大家介绍了关于Android从实现到封装MVP的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. MVP之间的联系 大概简单的解释就是M->module处理数据,V->Act显示界面,P->M和V沟通的渠道,即P用来将数据和界面联系到一起,这样子界面和数据就可以完全独立开来,Ac

随机推荐