C++抓图服务
程序员文章站
2022-04-15 16:18:12
基于前两篇抓图文章,本文将抓图提取为一个服务,实现不同场景下抓图需求的封装。 C++使用BitBlt进行窗口抓图 C++使用PrintWindow进行窗口抓图 首先是抓图服务: ICaptureHelper.h #pragma once #include #include < ......
基于前两篇抓图文章,本文将抓图提取为一个服务,实现不同场景下抓图需求的封装。
首先是抓图服务:
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_; };
captureservice.cpp
#include "stdafx.h" #include "captureservice.h" #include "dibcapturehelper.h" #include "printcapturehelper.h" captureservice::~captureservice() { cleanup(); } captureservice& captureservice::getinstance() { static captureservice instance; return instance; } bool captureservice::registercapture(string name, string windowname, capturetype type /* = createdibsection */) { const auto hwnd = ::findwindowa(nullptr, windowname.c_str()); return registercapture(name, hwnd, type); } bool captureservice::registercapture(string name, hwnd hwnd, capturetype type /* = createdibsection */) { if (name.empty() || capturehelpers_.find(name) != capturehelpers_.end()) { return false; } icapturehelper* helper; switch (type) { case createdibsection: helper = new dibcapturehelper(); break; case printwindow: helper = new printcapturehelper(); break; default: return false; } if (helper == nullptr) { return false; } if (!helper->init(hwnd)) { delete helper; return false; } capturehelpers_[name] = helper; return true; } void captureservice::unregistercapture(string name) { if (name.empty() || capturehelpers_.find(name) == capturehelpers_.end()) { return; } auto* capturehelper = capturehelpers_[name]; if (capturehelper != nullptr) { capturehelper->cleanup(); delete capturehelper; } capturehelpers_.erase(name); } bool captureservice::isregister(string name) { return !name.empty() && capturehelpers_.find(name) != capturehelpers_.end(); } bool captureservice::refreshwindow(string name) { if (!isregister(name)) { return false; } return capturehelpers_[name]->refreshwindow(); } bool captureservice::changewindowhandle(string name, string windowname) { if (!isregister(name)) { return false; } return capturehelpers_[name]->changewindowhandle(windowname); } bool captureservice::changewindowhandle(string name, hwnd hwnd) { if (!isregister(name)) { return false; } return capturehelpers_[name]->changewindowhandle(hwnd); } bool captureservice::capture(string name) { if (!isregister(name)) { return false; } return capturehelpers_[name]->capture(); } bool captureservice::getwindowrect(string name, rect& winrect) { if (!isregister(name)) { return false; } winrect = capturehelpers_[name]->getwindowrect(); return true; } bool captureservice::getclientrect(string name, rect& clientrect) { if (!isregister(name)) { return false; } clientrect = capturehelpers_[name]->getclientrect(); return true; } bool captureservice::getbitmapdatasize(string name, int& bmpdatasize) { if (!isregister(name)) { return false; } bmpdatasize = capturehelpers_[name]->getbitmapdatasize(); return true; } bool captureservice::getbitmap(string name, hbitmap& bitmap) { if (!isregister(name)) { return false; } bitmap = capturehelpers_[name]->getbitmap(); return true; } bool captureservice::getbitmapaddress(string name, void** bitsptr) { if (!isregister(name)) { return false; } *bitsptr = capturehelpers_[name]->getbitmapaddress(); return true; } void captureservice::cleanup() { for (auto iter = capturehelpers_.cbegin(); iter != capturehelpers_.cend(); ++iter) { auto* capturehelper = iter->second; if (capturehelper != nullptr) { capturehelper->cleanup(); delete capturehelper; } } capturehelpers_.clear(); }
其次是抓图代码封装:
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; }
下一篇: 线程的概念