Windows抓屏(1)GDI-bitblt

1GDI- bitblt方法

BitBlt 用于从原设备中复制位图到目标设备,弊端,做投屏抓屏时候可能会比较慢,帧率比较低

头文件:(代码来源于网络,目前无法溯源)

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



//本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
class DibCaptureHelper
{
public:
    DibCaptureHelper();
    virtual ~DibCaptureHelper();

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

    void SaveDCtoBmp();


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

private:
    HWND hwnd_;//窗体句柄
    HDC scrDc_;//设备场景句柄
    HDC memDc_;
    HBITMAP bitmap_;//位图句柄 
    HBITMAP oldBitmap_;
    void* bitsPtr_;

    RECT windowRect_;//rect这个对象是用来存储成对出现的参数,比如,一个矩形框的左上角坐标、宽度和高度
    RECT clientRect_;
    POINT bitbltStartPoint_;//点坐标
    int bmpDataSize_;//位图缓冲大小
};

实现:

#include "stdafx.h"
#include "Bit.h"

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


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

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

    return Init(handle);
}

bool DibCaptureHelper::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 * 3;//24bit

    bitbltStartPoint_.x = 0;
    bitbltStartPoint_.y = 0;

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

    scrDc_ = ::GetWindowDC(hwnd_); //获取窗口DC(设备场景)
    memDc_ = ::CreateCompatibleDC(scrDc_); //缓冲内存DC
    //创建应用程序可以直接写入的、与设备无关的位图(DIB)
    bitsPtr_ = nullptr;
    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;
}

void DibCaptureHelper::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 DibCaptureHelper::RefreshWindow()
{
    const auto hwnd = hwnd_;
    Cleanup();
    return Init(hwnd);
}

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

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

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

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

    const auto ret = ::BitBlt(
        memDc_, 0, 0, clientRectWidth, clientRectHeight,
        scrDc_, bitbltStartPoint_.x, bitbltStartPoint_.y,
        SRCCOPY);//将源矩形区域直接拷贝到目标矩形区域。

    return ret != 0;
}
void DibCaptureHelper::SaveDCtoBmp()
{
    if (bitsPtr_)
    {
        BITMAPINFOHEADER bmInfoHeader = { 0 };
        bmInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
        bmInfoHeader.biWidth = clientRect_.right - clientRect_.left;
        bmInfoHeader.biHeight = clientRect_.bottom - clientRect_.top;
        bmInfoHeader.biPlanes = 1;
        bmInfoHeader.biBitCount = 24;

        //Bimap file header in order to write bmp file  
        BITMAPFILEHEADER bmFileHeader = { 0 };
        bmFileHeader.bfType = 0x4d42;  //bmp   
        int size1 = sizeof(BITMAPFILEHEADER);
        int size2 = sizeof(BITMAPINFOHEADER);
        bmFileHeader.bfOffBits = size1 + size2;
        bmFileHeader.bfSize = bmFileHeader.bfOffBits + ((bmInfoHeader.biWidth * bmInfoHeader.biHeight) * 3); ///3=(24 / 8) 
        
        
        FILE* fptr = fopen("./desp.bmp", "wb+");
        if (fptr)
        {
            fwrite(&bmFileHeader, sizeof(BITMAPFILEHEADER),1,fptr);
            fwrite(&bmInfoHeader, sizeof(BITMAPINFOHEADER), 1, fptr);
            
            DWORD len = ((bmInfoHeader.biWidth * bmInfoHeader.biHeight) * 3);
            fwrite(bitsPtr_, len, 1, fptr);
            fclose(fptr);
        }
        
    
    }


}

调用:

#include "stdafx.h"
#include"BIt.h"
#include <windows.h>


int main()
{
    HWND winHandle =  GetDesktopWindow();
    
    auto obj = new DibCaptureHelper();
    obj->Init(winHandle);
    obj->Capture();
    obj->SaveDCtoBmp();


    return 0;
}

屏幕截图结果:

 

posted on 2022-11-06 17:04  邗影  阅读(264)  评论(0编辑  收藏  举报

导航