欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > QtC++截图支持获取鼠标光标

QtC++截图支持获取鼠标光标

2024/10/25 5:07:23 来源:https://blog.csdn.net/LuXiaoXin1999/article/details/142168714  浏览:    关键词:QtC++截图支持获取鼠标光标

介绍

在截图工具中你会发现,屏幕截图大部分软件都无法获取鼠标指针,显示鼠标样式这个功能使用频率较低,对于专业的截图工具会有此功能,例如Snipaste。

1.获取当前鼠标图像绘制到截图中,并反色处理

此函数调用winapi来返回QImage 类型的图像,尺寸固定32,32,这里有一个坑不能使用bmpCursor.bmWidth,鼠标信息的宽高,这个值可能会为0,导致无法获取图像。


#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QImage>
#include <QPainter>
#include <QPixmap>
#include <Windows.h>
#include <QtWinExtras>
#include <QDebug>
#include <QElapsedTimer>#include <Windows.h>
#include <QImage>
#include <QtWinExtras>
#include <QThread>
#include <QtWidgets>QImage getMouseImg(int& hotspotX, int& hotspotY) {// 获取桌面窗口句柄HWND hwnd = GetDesktopWindow();// 获取桌面窗口的设备上下文 (HDC),用于图形操作HDC hdc = GetWindowDC(hwnd);// 创建一个内存设备上下文 (HDC),用于在内存中绘制图像HDC hdcMem = CreateCompatibleDC(hdc);// 创建一个兼容的位图,用于存储光标的图像,大小为光标的宽和高HBITMAP hbitmap = nullptr;hbitmap = CreateCompatibleBitmap(hdc, 32, 32);// 将新创建的位图选入内存设备上下文 (HDC)SelectObject(hdcMem, hbitmap);// 初始化 CURSORINFO 结构体,用于存储当前光标的信息CURSORINFO cursor = { sizeof(cursor) };// 检查是否成功获取到当前光标的信息,且光标是否显示if (GetCursorInfo(&cursor) && cursor.flags == CURSOR_SHOWING) {// 获取桌面窗口的尺寸RECT rect;GetWindowRect(hwnd, &rect);// 初始化 ICONINFO 结构体,获取光标的图标信息ICONINFO info = { sizeof(info) };if (GetIconInfo(cursor.hCursor, &info)) {// 获取热点位置hotspotX = info.xHotspot;hotspotY = info.yHotspot;// 定义 BITMAP 结构体来存储光标的位图信息BITMAP bmpCursor = { 0 };GetObject(info.hbmColor, sizeof(bmpCursor), &bmpCursor);// 将当前光标绘制到内存设备上下文的位图上DrawIconEx(hdcMem, 0, 0, cursor.hCursor, 32, 32, 0, nullptr, DI_NORMAL);// 使用 QtWin::imageFromHBITMAP 函数,将 Windows 的 HBITMAP 转换为 Qt 的 QImage 对象QImage cursorImage = QtWin::imageFromHBITMAP(hdcMem, hbitmap, 32, 32);// 释放资源DeleteObject(info.hbmColor);DeleteObject(info.hbmMask);ReleaseDC(hwnd, hdc);DeleteDC(hdcMem);return cursorImage;}}// 如果光标不可见或获取失败,返回一个空的 QImage 对象return QImage();
}MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);
}MainWindow::~MainWindow()
{delete ui;
}QScreen *getScreenOfRect(const int &x)
{for (QScreen *screen : QGuiApplication::screens()){if (screen->geometry().contains(x, 0)){return screen;}}return nullptr;
}// 反色函数
QImage invertImageColors(const QImage& image) {QImage invertedImage = image.copy();  // 创建图像副本// 遍历图像的每个像素,并进行反色for (int y = 0; y < invertedImage.height(); ++y) {for (int x = 0; x < invertedImage.width(); ++x) {QColor pixelColor = invertedImage.pixelColor(x, y);QColor invertedColor = QColor(255 - pixelColor.red(),255 - pixelColor.green(),255 - pixelColor.blue(),pixelColor.alpha());  // 保留透明度invertedImage.setPixelColor(x, y, invertedColor);}}return invertedImage;
}// 判断颜色是否相似
bool isColorSimilar(const QColor& c1, const QColor& c2, int threshold = 50) {int rDiff = abs(c1.red() - c2.red());int gDiff = abs(c1.green() - c2.green());int bDiff = abs(c1.blue() - c2.blue());// 如果颜色的 RGB 差异小于阈值,认为颜色相似return (rDiff < threshold && gDiff < threshold && bDiff < threshold);
}// 检查鼠标区域是否容易看见
QImage checkCursorVisibilityAndAdjust(const QImage& largeImage, int x, int y, QImage cursorImage) {bool needsInversion = false;// 确保鼠标的区域不会超出 largeImage 的范围if (x < 0 || y < 0 || x + cursorImage.width() > largeImage.width() || y + cursorImage.height() > largeImage.height()) {qWarning() << "Mouse position or cursor image exceeds the bounds of largeImage.";return cursorImage;  // 返回原始鼠标图像}// 遍历光标图像区域,并与 largeImage 的对应区域进行比较for (int cy = 0; cy < cursorImage.height(); ++cy) {for (int cx = 0; cx < cursorImage.width(); ++cx) {QColor cursorPixel = cursorImage.pixelColor(cx, cy);// 如果鼠标像素是透明的 (A == 0),跳过该像素的比较if (cursorPixel.alpha() == 0) {continue;}QColor backgroundPixel = largeImage.pixelColor(x + cx, y + cy);// 如果光标像素和背景像素颜色非常相似,标记需要反色处理if (isColorSimilar(cursorPixel, backgroundPixel)) {needsInversion = true;break;  // 发现需要反色时,停止进一步检查}}if (needsInversion) break;}// 如果颜色太相似,对鼠标图像进行反色处理if (needsInversion) {return invertImageColors(cursorImage);  // 反色后返回新的图像}return cursorImage;  // 如果不需要反色,返回原图像
}void MainWindow::on_pushButton_clicked()
{QThread::msleep(2000);QElapsedTimer s;s.start();//获取屏幕QScreen* screen = getScreenOfRect(QCursor::pos().x());//屏幕截图QImage largeImage = screen->grabWindow(0).toImage();// 获取鼠标图及其热点位置int hotspotX = 0, hotspotY = 0;QImage cursorImage = getMouseImg(hotspotX, hotspotY);// 获取当前鼠标位置POINT mousePos;GetCursorPos(&mousePos);// 检查鼠标绘制区域是否容易看见,若不易见则进行反色处理cursorImage = checkCursorVisibilityAndAdjust(largeImage, mousePos.x, mousePos.y, cursorImage);// 调整鼠标绘制位置,考虑热点偏移int drawX = mousePos.x - hotspotX;int drawY = mousePos.y - hotspotY;// 在 largeImage 上绘制光标QPainter painter(&largeImage);painter.drawImage(drawX, drawY, cursorImage);painter.end();largeImage.save("C:/1111111111111111.png");qDebug() << s.elapsed();
}

2.关于鼠标样式反色问题

在windows系统例如输入样式的鼠标类似于 工 字,这个鼠标样式在白底下是黑色,在黑底下是白色,那么对于getMouseImg接口返回的只会是纯白色,所以我们需要对此做一个反色处理,以及判断颜色。

结尾

以上代码就是完整代码,可自行复制接口拼接项,int threshold = 50是相似度判断,可自行修改判断反色。
注意:反色做的不是很完美,可能没有win那么完美,例如不能根据一个色点判断就进行反色,完美点做就取出所有色点然后做一个相似比例。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com