Qt(C++) 截屏的方法

最近一个Qt(C++)的项目需要用到截屏的功能,就花时间研究了一下如何实现。
Qt 确实是好用,截屏只需要下面三行代码就够了。

QDesktopWidget *desk = QApplication::desktop();
QScreen * screen = QGuiApplication::primaryScreen();
QPixmap p = screen->grabWindow(desk->winId());

这三行代码第一行是获取桌面的窗体对象。
第二行是获得一个 QScreen 对象。
第三行是截取屏幕上窗体对象所在区域的图像。

截取的结果是个QPixmap ,如果需要进一步处理的话,可以转化为 QIamge,一行代码就可以了。

QImage image = p.toImage();

原理就这么简单,但是我将这个代码封装了一下,将截屏功能封装成了一个 Camera。一次截屏操作就相当于相机拍一张照片。这样的好处是我这里有大量的相机图像处理的代码模块。将截屏封装成相机之后,就可以非常便捷的连接我的既有代码了。这种方法在设计模式中成为“适配器模式”。

下面是代码:

#ifndef SCREENCAMERA_H
#define SCREENCAMERA_H

#include <QThread>
#include <QObject>
#include <QScreen>
#include <QTimer>

class ScreenCamera;

/**
 * @brief The ScreenCameraInfo class 查询屏幕相机的信息的类
 * 用这个类可以查到当前计算机接了几个显示器,给出每个显示器的名称(deviceName)
 */
class ScreenCameraInfo
{
    friend class ScreenCamera;
public:
    explicit ScreenCameraInfo(QScreen * screen = nullptr);
    ScreenCameraInfo(const ScreenCameraInfo &info);
    /**
     * @brief description 没有实现,返回空字符串
     * @return 返回空字符串。
     */
    QString description() const;
    /**
     * @brief deviceName 给出屏幕的名称,比如 "\\\\.\\DISPLAY1", "VGA1" 一类的名称。
     * @return
     */
    QString deviceName() const;
    bool isNull() const;
    bool operator!=(const ScreenCameraInfo &other) const;
    ScreenCameraInfo &operator=(const ScreenCameraInfo &other);
    bool operator==(const ScreenCameraInfo &other) const;

    static QList<ScreenCameraInfo> availableCameras();
    static ScreenCameraInfo defaultCamera();

private:
    QScreen* m_screen;
};

/**
 * @brief The ScreenCamera class 将截屏功能封装成一个相机,可以像相机一样的操作。
 */
class ScreenCamera : public QThread
{
    Q_OBJECT
public:
    explicit ScreenCamera(QObject *parent = 0);
    explicit ScreenCamera(ScreenCameraInfo &info, QObject *parent = 0);
    /**
     * @brief openDevice 打开一个特定的截屏相机,当计算机连接了多个显示器时通过这个 info 指定截取某一个屏幕的图像
     * @param info
     * @return
     */
    bool openDevice(const ScreenCameraInfo &info);
    /**
     * @brief setFrameRate 设置定时截屏的帧率。这里模仿相机的帧率设置。
     * @param fps  frame per second 每秒的截屏数量。 [0.001 - 50]
     */
    void setFrameRate(double fps);
    /**
     * @brief setRoi 设置感兴趣的区域,利用这个函数我们可以只截取屏幕的一部分区域
     * @param x 截屏区域的起始X坐标
     * @param y 截屏区域的起始Y坐标
     * @param width 截屏区域的宽度,-1 表示完整的屏幕宽度
     * @param height 截屏区域的高度,-1 表示完整的屏幕高度
     */
    void setRoi(int x, int y, int width, int height);
    void run() override;
    /**
     * @brief capture 获取截屏图像
     * @return
     */
    QImage capture();
signals:
    /**
     * @brief imageChanged 定时截取图像时没截取一帧图像就激发一次这个信号
     * @param image
     */
    void imageChanged(const  QImage& image);
public slots:
    /**
     * @brief start 开始图像采集
     */
    void start();
    /**
     * @brief stop 停止图像采集
     */
    void stop();

private:
    int m_sleepInterval;
    QScreen* m_screen;
    int m_x;
    int m_y;
    int m_width;
    int m_height;
};

#endif // SCREENCAMERA_H
#include "ScreenCamera.h"
#include <QApplication>
#include <QDesktopWidget>
#include <QDebug>

ScreenCameraInfo::ScreenCameraInfo(const ScreenCameraInfo &info)
    :m_screen(nullptr)
{
    m_screen = info.m_screen;
}

ScreenCameraInfo::ScreenCameraInfo(QScreen * screen)
    :m_screen(nullptr)
{
    m_screen = screen;
}

bool ScreenCameraInfo::isNull() const
{
    return (m_screen == nullptr);
}

QString ScreenCameraInfo::description() const
{
    return "";
}
QString ScreenCameraInfo::deviceName() const
{
    if(m_screen == nullptr) return "";
    return m_screen->name();
}

ScreenCameraInfo ScreenCameraInfo::defaultCamera()
{
    QScreen * w = QGuiApplication::primaryScreen();
    return ScreenCameraInfo(w);
}

QList<ScreenCameraInfo> ScreenCameraInfo::availableCameras()
{
    QList<QScreen *> list = QGuiApplication::screens();
    QList<ScreenCameraInfo> info;
    foreach (QScreen * s, list)
    {
        ScreenCameraInfo i(s);
        info.append(i);
    }

    return info;
}

bool ScreenCameraInfo::operator!=(const ScreenCameraInfo &other) const
{
    return (m_screen != other.m_screen);
}

ScreenCameraInfo & ScreenCameraInfo::operator=(const ScreenCameraInfo &other)
{
    m_screen = other.m_screen;
    return *this;
}

bool ScreenCameraInfo::operator==(const ScreenCameraInfo &other) const
{
    return m_screen == other.m_screen;
}


ScreenCamera::ScreenCamera(ScreenCameraInfo &info, QObject *parent) : QThread(parent)
{
    m_screen = info.m_screen;
    m_sleepInterval = 500;
    m_x = 0;
    m_y = 0;
    m_width = -1;
    m_height = -1;
}

ScreenCamera::ScreenCamera(QObject *parent) : QThread(parent)
{
    m_screen = nullptr;
    m_sleepInterval = 500;
    m_x = 0;
    m_y = 0;
    m_width = -1;
    m_height = -1;
}

bool ScreenCamera::openDevice(const ScreenCameraInfo &info)
{
    m_screen = info.m_screen;
    return (m_screen);
}

void ScreenCamera::setFrameRate(double fps)
{
    fps = qBound(0.001, fps, 50.0);
    m_sleepInterval = 1000 / fps;  
}

void ScreenCamera::setRoi(int x, int y, int width, int height)
{
    if(m_screen)
    {
        QRect rect = m_screen->geometry();

        m_x = qBound(0, x, rect.width());
        m_y = qBound(0, y, rect.height());
        m_width = qBound(-1, width, rect.width());
        m_height = qBound(-1, height, rect.height());
    }
}

void ScreenCamera::run()
{
    while(1)
    {
        if(m_screen)
        {
            QDesktopWidget *desk = QApplication::desktop();
            //qDebug() << "m_width = " << m_width;
            //qDebug() << "m_height = " << m_height;
            QPixmap p = m_screen->grabWindow(desk->winId(), m_x, m_y, m_width, m_height);
            QImage image = p.toImage();
            emit imageChanged(image);
        }
        msleep(m_sleepInterval);
    }
}

QImage ScreenCamera::capture()
{
    if(m_screen)
    {
        QDesktopWidget *desk = QApplication::desktop();
        QPixmap p = m_screen->grabWindow(desk->winId(), m_x, m_y, m_width, m_height);
        QImage image = p.toImage();
        return image;
    }
    return QImage();
}

void ScreenCamera::stop()
{
    terminate();
}

void ScreenCamera::start()
{
    QThread::start(QThread::InheritPriority);
}

用法很简答,下面给个代码片段:

ScreenCameraInfo info = ScreenCameraInfo::defaultCamera();
    qDebug() << info.deviceName();
    m_screenCamera = new ScreenCamera(info);
    connect(m_screenCamera, SIGNAL(imageChanged(QImage)), m_cameraImage, SLOT(setImage(QImage)));
    m_screenCamera->setRoi(0, 0, 500, 500);
    m_screenCamera->start();
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值