• C++抓图服务


    基于前两篇抓图文章,本文将抓图提取为一个服务,实现不同场景下抓图需求的封装。

    C++使用BitBlt进行窗口抓图

    C++使用PrintWindow进行窗口抓图

    首先是抓图服务:

    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;
    }
  • 相关阅读:
    Servlet会话管理一(URL重写和表单隐藏域)
    Eclipse自动补全设置
    String类为什么设计成不可变的
    部署描述符(web.xml)和标注(annotation)
    html中 &nbsp; 和空格的区别
    HTML的基本知识点
    Eclipse中配置Tomcat服务器并创建标准Web目录
    Sevlet处理HTML表单
    Servlet API
    Servlet开发的三种方法
  • 原文地址:https://www.cnblogs.com/xhubobo/p/12604983.html
Copyright © 2020-2023  润新知