QRegion 限制 QPainter 的绘制区域

news2024/11/26 8:17:22

我有这样一个需求。

有一张图片,这张图片上面被我用不同的颜色画了不同的区域,然后我想选择这张图片中的某一种颜色,只在这种颜色所在的区域内进行绘制或者用橡皮擦擦除这种颜色,而不会影响其他颜色。

看着这个需求的时候,我首先想到的是图层,就是类似PS的图层一样,就是将这张图片中的每一种颜色单独提取出来另作一种图层,这样就会得到多张只包含一种颜色的图片,这些图片的其他区域是透明的。然后利用 QPainter::CompositionMode_SourceOver模式将这些图形进行绘制。

如果需要在某种颜色上绘制的时候,就在对应的图片上进行绘制。

最后在绘制完成后,将这些图片进行合并,每个像素都进行重合而得到开始的一张图像。

想法是好的,但测试的过程应该是痛苦的,因为要不停地进行图像的分层,并且在多层像素颜色冲突的时候,无法确定具体应该选择哪种进行显示。所以我没测,转而寻找其他更简单的方法,毕竟人都是要学会偷懒的。

也是在找如何设置图片的透明度的过程中,偶然的发现了QRegion这个类。Qt帮助文档中这样说:

The QRegion class specifies a clip region for a painter.
QRegion is used with QPainter::setClipRegion() to limit the paint area to what needs to be painted. There is also a QWidget::repaint() function that takes a QRegion parameter. QRegion is the best tool for minimizing the amount of screen area to be updated by a repaint.
This class is not suitable for constructing shapes for rendering, especially as outlines. Use QPainterPath to create paths and shapes for use with QPainter.
QRegion is an implicitly shared class. 

说白了,就是这个类提供一个绘制区域的限制功能

这个类的构造函数有好几种,但是我们理解一下,因为这个类是为QPainter提供了一个绘制的限制区域。也就不难理解,我们肯定是要给它一个区域类型的参数。看看他的构造函数我们也基本上能明白。

QRegion()
QRegion(int x, int y, int w, int h, QRegion::RegionType t = Rectangle)
QRegion(const QRect &r, QRegion::RegionType t = Rectangle)
QRegion(const QPolygon &a, Qt::FillRule fillRule = Qt::OddEvenFill)
QRegion(const QRegion &r)
QRegion(QRegion &&other)
QRegion(const QBitmap &bm)

下面是我找了其中的一个做了下测试。鼠标左键绘制,右键删除。

void ImageWidget::drawBrush(QMouseEvent *event)
{
    QPen pen = QPen(QColor(Qt::red), 10, Qt::DashLine, Qt::RoundCap);
    pen.setCapStyle(Qt::RoundCap);

    QPainter painter(&m_draw);
    painter.setRenderHint(QPainter::SmoothPixmapTransform);

    painter.setRenderHint(QPainter::Antialiasing);
    painter.setClipRegion(m_region);
    if (m_button == Qt::RightButton)
    {
        painter.setClipRegion(m_backregion);
        painter.setCompositionMode(QPainter::CompositionMode_Clear);
    }
    painter.setPen(pen);

    if (event->type() == QEvent::MouseButtonPress)
    {
        m_brushPt = event->pos();
        painter.drawPoint(event->pos());
    }
    if (event->type() == QEvent::MouseMove)
    {
        painter.drawLine(m_brushPt, event->pos());
        m_brushPt = event->pos();
    }
    if (event->type() == QEvent::MouseButtonRelease)
    {
        m_brushPt = QPoint(-1, -1);
    }

    painter.end();
    update();
}

假设我们需要设定一个矩形的限制区域。

QRegion region(QRect( 40, 40, 100, 100));
m_region.swap(region);

我们今天主要要看的是通过QBitmap构建的绘制区域,QRegion(const QBitmap &bm) 因为我们给定的限制区域是一个QImage上指定的颜色,并且这些颜色的区域是不规则的。

帮助文档中这样说明:

Constructs a region from the bitmap bm.
The resulting region consists of the pixels in bitmap bm that are Qt::color1, as if each pixel was a 1 by 1 rectangle.
This constructor may create complex regions that will slow down painting when used. Note that drawing masked pixmaps can be done much faster using QPixmap::setMask().

结果区域由位图bm中Qt::color1的像素组成,每个像素都是一个1乘1的矩形。

为什么是位图呢?因为位图只有两种颜色,非黑即白,每个像素的值也只有两种,要么是 0 要么是 1,而通过位图构造的QRegion对象,在绘制的时候,只有在像素值为 0 的区域生效。这也就让我们的问题发生了变化。

这样, 我们的问题就从刚开始的如何创建一个绘制的限制区域,转换为了如何将一个QImage图像转换为位图

下面的代码是一个根据给定的图片及设定的颜色来创建一个QRegion对象的过程。我实际的测试代码中因为有右键删除,所以用的不是这个。但也相差不大,这段代码也是通过测试的。

void ImageWidget::createRegion(const QImage& img, const QColor& color, bool all)
{
    QImage imgRegion(img.size(), QImage::Format_MonoLSB);

    for (int x = 0, w = imgRegion.width(); x < w; ++x)
    {
        for (int y = 0, h = imgRegion.height(); y < h; ++y)
        {
            imgRegion.setPixel(x, y, all ? 0 : (img.pixelColor(x, y) == color ? 0 : 1));
        }
    }

    QBitmap bp = QBitmap::fromImage(imgRegion);
    QRegion region(bp);
    m_region.swap(region);
}

上面的这个函数我们可以这样理解,参数 color 可以理解为是需要创建区域的颜色, all 是是否不指定颜色,对整张图像都有效。

紧接着首先根据给定的模版构造一个QImage对象,这个QImage对象的颜色是透明的,然后通过遍历模版每个像素的颜色,来设定我们构建的QImage对象的像素值,要注意一点,QRegion只有在像素值为 0 的像素上生效。

然后通过QBitmap生成QRegion

基本上我们的测试就完成了,但是一般在绘制的过程中,我们有很大的可能性是需要擦除的,擦除的时候也只能擦除我们目前在画的颜色区域,并不会将所有的都擦除。这种情况下,就需要我们对擦除时候生效轨迹做一次限制。

并且在每次绘制完成,也就是鼠标事件 mouseRelease的时候,更新擦除的区域。创建方式跟我们上面的是一样的。

如图所示,首先我们选择背景标签为 alllabels,前景标签为红色在图片上进行绘制,效果如下:
在这里插入图片描述

接着我们选择背景标签为红色,前景标签为绿色在图片上进行绘制,效果如下:
在这里插入图片描述

擦除的标签其实是和我们当前选择的前景标签是一致的,创建限制区域是一样的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/534101.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java【网络原理2】TCP 协议的连接管理机制 : 三次握手和四次挥手到底是怎么回事?

文章目录 前言一、三次握手二、四次挥手总结 前言 &#x1f4d5;各位读者好, 我是小陈, 这是我的个人主页 &#x1f4d7;小陈还在持续努力学习编程, 努力通过博客输出所学知识 &#x1f4d8;如果本篇对你有帮助, 烦请点赞关注支持一波, 感激不尽 &#x1f4d9; 希望我的专栏能够…

让AI来预测一下2023年软考系统分析师案例分析的新技术考点

预测 AI对考试的帮助可能没法雪中送炭&#xff0c;但是也许可以锦上添花。AI的预测新技术考点内容&#xff08;仅供参考&#xff09;如下&#xff1a; 由于我是一个AI模型&#xff0c;无法准确预测未来的技术内容。但是根据当前的发展趋势和历史变化&#xff0c;以下是可能出…

将核心交换机配置为NTP服务器

AR配置外源NTP 1&#xff0e;配置ntp <XQ-R1220>sys [XQ-R1220]ntp-service unicast-server 120.25.115.20 #阿里云ntp [XQ-R1220]ntp-service unicast-server 203.107.6.88 #阿里云ntp 2&#xff0e;查看ntp状态 <XQ-R1220>display ntp status clock sta…

什么是以太坊Layer2?

目录 1. Plasma2. State Channels3. Sidechains4. Rollups5. Optimistic Rollups 以太坊&#xff08;Ethereum&#xff09;是一种基于区块链技术的分布式计算平台&#xff0c;提供了智能合约的支持&#xff0c;使得开发者可以构建基于以太坊的去中心化应用&#xff08;DApps&am…

什么是【网络安全】?给你一步到位了解清楚

网络安全是什么&#xff1f; 在俺的私信里经常有人问&#xff1a; 网络安全技术是否就等同于”黑客”技术&#xff1f; 大漏特漏&#xff01;&#xff01;&#xff01; 所谓的「黑客」或「渗透」技术&#xff0c;仅仅是网络安全领域的分支&#xff0c;不能代表其全貌。 随着…

Open Judge——动态规划练习

目录 了解动态规划 2760:数字三角形 1、题目 2、代码 4120:硬币 1、题目 2、代码 了解动态规划 动态规划 是编程解题的一种重要手段。1951 年美国数学家 R.Bellman 等人&#xff0c;根据一类多阶段问题的特点&#xff0c;把多阶段决策问题变换为一系列互相联系的单阶段问…

Centos7连接外网的相关配置与实现yum本地与网络配置(yum配置不使用wget)

目录 一、背景 二、实现连接外网的相关配置 1&#xff09;查看物理机的IP相关信息 2&#xff09;配置物理机指定IP 3&#xff09;根据物理机配置虚拟机网卡 4&#xff09;进入虚拟机&#xff0c;配置网卡 三、yum配置 1&#xff09;切换到yum软件仓库配置文件目录中 2…

队列的基本操作详细介绍 看了就会!!!

文章目录 队列的介绍队列的概念队列的结构生活中队列的运用实例 队列的实现初始化队列队尾入队列队头出队列获取队列头部元素获取队列尾部元素判断队列是否为空获取队列中有效元素个数销毁队列 队列的介绍 队列的概念 队列&#xff1a;只允许在一端进行插入数据操作&#xff…

React18.x + i18next + antd 国际化正确使用姿势及避坑指南

如果你使用这个教程还不能够解决你的问题的话&#xff0c;直接私信我&#xff0c;免费一对一给你解决。 一、使用vite创建一个react项目 具体的创建方法大家参考vite官方文档&#xff0c;大概的操作如下&#xff0c;如果需要更详细的&#xff0c;大家去自行搜索即可 pnpm cr…

【LeetCode】172. 阶乘后的零

172. 阶乘后的零&#xff08;中等&#xff09; 方法一 思路 当一个数乘以 10 &#xff0c;此时数字结尾会增加一个 0&#xff0c;因此我们可以计算 n! 能够得出多少个 10 &#xff0c;就说明能得到多少个 0 。 具体对于5!&#xff0c;也就是 5 * 4 * 3 * 2 * 1 120&#xf…

CSS第一天总结

css第一天总结 css简介 CSS 是层叠样式表 ( Cascading Style Sheets ) 的简称. 有时我们也会称之为 CSS 样式表或级联样式表。 CSS 是也是一种标记语言 CSS 主要用于设置 HTML 页面中的文本内容&#xff08;字体、大小、对齐方式等&#xff09;、图片的外形&#xff08;宽高、…

【pyq文案】合理但有病の自拍文案

1、丑一眼 2、强子&#xff0c;妈发自拍了 3、真是方向失了南北&#xff0c;美的有点东西 4、妈的看自己就烦&#xff0c;800块出了&#xff0c;完美无瑕 5、拍了拍自己 6、这张脸&#xff0c;全是这双手给的 7、糟糕&#xff0c;没有酷起来 8、制造美女我比女娲还牛 …

ANR原理篇 - ANR原理总览

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 文章目录 系列文章目录前言ANR流程概览ANR触发机制一、service超时机制二、broadcast超时机制三、provider超…

支付系统设计四:支付核心设计01-总览

文章目录 前言一、应用架构二、开发框架三、逻辑架构四、分层架构1. 松散分层架构2. 分层职责 总结 前言 在《支付系统设计一&#xff1a;支付系统产品化》文章中&#xff0c;我们知道支付核心对应于平台产品层&#xff0c;主要具有以下功能&#xff1a; 为公司各业务线提供丰…

LangChain实现自主代理(Autonomous Agents)

LangChain实现自主代理&#xff08;Autonomous Agents&#xff09; LangChain实现自主代理&#xff08;Autonomous Agents&#xff09;简介核心技术让 AI 使用工具的案例使用搜索引擎使用知识库 Here’s the table of contents: LangChain实现自主代理&#xff08;Autonomous …

【A*算法——清晰解析 算法逻辑——算法可以应用到哪些题目】例题1.第K短路 例题2.

A*算法 A*算法是什么例题1. 第K短路题意解析 例题2. 八数码 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1…

初识Linux:第四篇

初识Linux&#xff1a;第四篇 初识Linux&#xff1a;第四篇1.配置自己的公网ip2.时间相关的指令3.cal指令4.find指令5.grep指令6.zip/unzip指令7.tar指令8.bc命令9.uname -r指令10.一些其他热键11.关机12.shell命令以及运行原理 总结 初识Linux&#xff1a;第四篇 &#x1f449…

华为OD机试真题 Java 实现【最佳对手】【2023Q1 200分】

一、题目描述 游戏里面&#xff0c;队伍通过匹配实力相近的对手进行对战。但是如果匹配的队伍实力相差太大&#xff0c;对于双方游戏体验都不会太好。 给定 n 个队伍的实力值&#xff0c;对其进行两两实力匹配&#xff0c;两支队伍实例差距在允许的最大差距 d内&#xff0c;则…

深度学习之迁移学习

数据增强 数据太少可能会过拟合。 # data_transforms中指定了所有图像预处理&#xff08;变换&#xff09;操作&#xff08;图像数据增强&#xff09; data_transforms {train: transforms.Compose([transforms.RandomRotation(45), # 随机旋转&#xff0c;-45到45度之间随…

本地测试使用自签名证书以开启网站https(例子说明:Nginx、Tomcat)

文章目录 数字证书简介工作原理证书链获取SSL证书和自签名证书前提条件创建根 CA 证书1.生成 RSA 私钥2.生成根证书签名请求&#xff08;CSR&#xff09;3.生成自签根证书 创建服务器证书1.创建服务器 RSA 私钥2.创建 CSR&#xff08;证书签名请求&#xff09;3.使用 CSR 和私钥…