QImage 如何设置图片的透明度

news2024/11/27 2:18:55

最近遇到了一些这样的需求,在窗口可以调节显示图片的透明度,但是不能影响其他图片。一个窗口显示的图片并不是一张,而是多张通过绘制的形式叠加起来的。可以理解为类似图层。

就像下面这个组合一样,想法是在拖动右侧透明度的滑条的时候,只修改上层图像的透明度,并不会修改底层背景图的透明度。

先看下预期效果:
在这里插入图片描述

1、通过 QPainter::CompositionMode_DestinationIn 模式模拟显示透明度

偶然的通过了解 QPainter::CompositionMode 的过程中发现了 QPainter::CompositionMode_DestinationIn,帮助文档中解释为:

The output is the destination, where the alpha is reduced by that of the source. This mode is the inverse of CompositionMode_SourceIn.

输出的是目标,并且其alpha的值与绘制源的相关。初次就有了下面的想法:

void ImageWidget::paintEvent(QPaintEvent *event)
{
    QSize sizeImg = size();
    QImage imgBack(sizeImg, QImage::Format_ARGB32);
    imgBack.fill(Qt::black);

    DrawTool::ImageShow img = m_img;
    DrawTool::DrawToolData op = m_operate;

    QImage imgDraw(img.size, QImage::Format_ARGB32);
    imgDraw.fill(Qt::transparent);
    m_draw = imgDraw.scaled(img.size * m_dScale, Qt::KeepAspectRatio, Qt::FastTransformation);

    QPainter painter;
    painter.begin(&imgBack);
    painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
    painter.drawImage(m_paintPt, m_show);
    painter.drawImage(m_paintPt, m_mask);
    painter.drawImage(m_paintPt, m_draw);

    painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
    painter.fillRect(imgBack.rect(), QColor(0, 0, 0, op.diaphaneity));
    painter.end();

    painter.begin(this);
    painter.setCompositionMode(QPainter::CompositionMode_Source);
    painter.drawImage(QPoint(0, 0), imgBack);
    painter.end();
}

上面这个绘制函数的过程是,先在一张纯黑的图像上以 QPainter::CompositionMode_SourceOver 的模式绘制三张图像,然后修改 QPainter 的 CompositionMode 为 QPainter::CompositionMode_DestinationIn,绘制并填充一个矩形,填充的颜色设定了我们前面说的透明度,并且这个透明度的值是可以动态修改的。

经过测试发现,这样的操作会将整个窗口的透明度都修改。效果如下:
在这里插入图片描述
虽然只是修改了窗口的透明程度,并不会实际的修改图片的通明度。但与我们的目标想不好像多了一点。所以这并不是最佳答案。显然得重新找答案了。

2、修改源图像的像素颜色透明度

既然是要修改图片的透明度,那么我们是不是可以直接修改图片每个像素的透明度呢?

void ImageWidget::setImageAlpha(QImage& img, int val)
{
    for (int r = 0, wd = img.width(); r < wd; ++r)
    {
        for (int c = 0, ht = img.height(); c < ht; ++c)
        {
            QColor color = img.pixelColor(r, c);
            if (color == Qt::transparent)
            {
                continue;
            }
            color.setAlpha(val);
            img.setPixelColor(r, c, color);
        }
    }
}

像上面这样,每次在绘制的时候先修改目标图片的透明度,然后再将图片绘制到屏幕上。

if (oldOp.diaphaneity != newOp.diaphaneity)
{
    DrawTool::ImageShow img = m_img;
    QImage maskImg = m_maskOri;
    setImageAlpha(maskImg, newOp.diaphaneity);
    m_mask = maskImg.scaled(img.size * m_dScale, Qt::KeepAspectRatio, Qt::FastTransformation);
}

这种情况下,绘制过程中设置绘制模式为 QPainter::CompositionMode_DestinationIn 并填充矩形框的操作就没有什么实际的意义了。需要注释掉。

//painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
//painter.fillRect(imgBack.rect(), QColor(0, 0, 0, op.diaphaneity));

测试之后,发现这种想法能够满足我们的目标。并且绘制过程也很丝滑。效果如下:

在这里插入图片描述

但是在后续的测试中发现,通过上面这种粗暴的方式设置了源图的透明度之后,再重新从图中读取像素颜色,像素颜色会有一定的误差。并且和透明度的大小存在一定的关系,但不是线性的。

当透明度在 50% 左右的时候,我发现,颜色会有一种这样的关系:

newRgb = 255 -255 - rgb)*double)a / 255

这个公式对R、G、B都适用,计算出来的结果有误差(是因为有了浮点数),但不影响。但是如果当a越小或者越大的时候,这个误差会增加。因此这个公式肯定是错的。

所以通过这中直接设置源图像透明底的方法,如果设置之后不在乎他的颜色,只是为了显示效果,是完全可以的,但如果它的像素颜色对你有用,或者你要在某些时候恢复它不透明,会有一定的影响。

3、通过 QPainter::CompositionMode_DestinationIn 模式和多个QPainter对象实现

想到这个方法是由上面第一种方式反思得到的,既然可以通过第一种方法模拟得到一个图像的透明度,那么为什么不能通过两个QPainter对象来实现了,一个专门用来实现针对单张图像的透明度,另一个用来实现正常的绘制流程呢?

但是在考虑这种方法的时候,需要注意的一点是:

Qt 中 是不允许两个QPainter对象同时进行绘制的,因此要注意他们之间的绘制顺序关系。

下面这个方法用来绘制一张图像的透明度。

void ImageWidget::drawMaskAlpha(QImage& img)
{
    DrawTool::DrawToolData op = m_operate;
    QImage back(m_mask.size(), QImage::Format_ARGB32);
    back.fill(Qt::transparent);
    img = back;
    QPainter pter(&img);
    pter.setCompositionMode(QPainter::CompositionMode_Source);
    pter.drawImage(0, 0, m_mask);
    pter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
    pter.fillRect(back.rect(), QColor(0, 0, 0, op.diaphaneity));
    pter.end();
}
void ImageBaseWidget::paintEvent(QPaintEvent *event)
{
    QImage imgBack(size(), QImage::Format_ARGB32);
    imgBack.fill(Qt::black);

    DrawTool::ImageShow img = m_img;
    DrawTool::DrawToolData op = m_operate;

    QImage imgDraw(img.size, QImage::Format_ARGB32);
    imgDraw.fill(Qt::transparent);
    m_draw = imgDraw.scaled(img.size * m_dScale, Qt::KeepAspectRatio, Qt::FastTransformation);

    QImage mask;
    drawMaskAlpha(mask);

    QPainter painter;
    painter.begin(&imgBack);
    painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
    painter.drawImage(m_paintPt, m_show);
    painter.drawImage(m_paintPt, m_draw);
    painter.drawImage(m_paintPt, mask);
    
    painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
    painter.fillRect(imgBack.rect(), QColor(0, 0, 0, op.diaphaneity));
    painter.end();
    
    painter.begin(this);
    painter.setCompositionMode(QPainter::CompositionMode_Source);
    painter.drawImage(QPoint(0, 0), imgBack);
    painter.end();
}

上面代码中出现的 DrawTool::ImageShowDrawTool::DrawToolData,是为了方便保存一些图像绘制过程中的变量。可以直接理解为成员变量。也可以参考我的上一篇博客 Qt QImage scaled方法缩放中的问题, 里面有相应的解释。

经过测试,最后的这种方法,可以达到我们的目标,并且并不会修改源图,只是在视觉上给我们一种图像透明度的错觉。在实际应用过程中可能会比较实用。

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

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

相关文章

ACM MM23 Workshop|多媒体+无人机

摘要&#xff1a; 无人驾驶飞行器 (UAV)&#xff0c;也称为无人机&#xff0c;由于能够从空中捕获高质量的多媒体数据&#xff0c;近年来变得越来越流行。 随着航空摄影、电影摄影和测绘等多媒体应用的兴起&#xff0c;无人机已成为收集丰富多样的多媒体内容的强大工具。 本次…

elasticsearch结构化查询

在上一篇中我们介绍了DSL相关的知识&#xff0c;接下来我们将会学习elasticsearch的结构化查询&#xff0c;同时也实践一下上一篇的DSL的查询用法 什么是结构化搜索? 从《Elasticsearch权威指南》上摘取部分解释如下: 结构化搜索是指查询包含内部结构的数据。日期&#xff0…

当我们在谈论ChatGPT时,我们在谈论什么?

当我们在谈论ChatGPT时&#xff0c;我们在谈论什么&#xff1f; 文章目录 当我们在谈论ChatGPT时&#xff0c;我们在谈论什么&#xff1f;一、介绍GPT-4相比GPT-3.5有何不同呢1.交谈能力2.多语言翻译精确度3.视觉输入 二、应用领域1.小镇做题家 (学术研究)2.Cosplay&#xff0c…

优思学院|质量大师的那些名言(三)【质量是一种习惯】

格言是一种简洁明了、简练有力的表达方式&#xff0c;通常蕴含着深刻的哲理和智慧&#xff0c;能够为我们提供指导和启示。 在《质量大师的那些名言》系列中&#xff0c;优思学院将透过这些名言&#xff0c;用最简单、直接、深刻的方式教授质量和六西格玛管理。 概述 在现代商…

ChatGPT 目前到底能帮助我们程序员做什么?

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享博主 &#x1f40b; 希望大家多多支持一下, 我们一起进步&#xff01;&#x1f604; &#x1f3c5; 如果文章对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&#x1…

异常中断处理

异常或中断是用户程序中最基本的一种执行流程或形态。这部分主要对ARM架构下的异常中断做详细说明。 ARM一共有7种类型的异常&#xff0c;按优先级从高到低的排列如下&#xff1a; 复位异常&#xff08;Reset&#xff09;、数据异常&#xff08;Data Abort&#xff09;、快速…

工业和信息化部发布《关于电信设备进网许可制度若干改革举措的通告》

按照《国务院办公厅关于深化电子电器行业管理制度改革的意见》&#xff08;国办发〔2022〕31号&#xff09;要求&#xff0c;工业和信息化部发布《关于电信设备进网许可制度若干改革举措的通告》&#xff08;工信部信管函〔2023〕14号&#xff09;&#xff0c;集中公布动态调整…

2023,你了解Kafka吗?深入详解

- 消息队列的核心价值 - 解耦合。 异步处理 例如电商平台&#xff0c;秒杀活动。一般流程会分为&#xff1a;1: 风险控制、2&#xff1a;库存锁定、3&#xff1a;生成订单、4&#xff1a;短信通知、5&#xff1a;更新数据。 通过消息系统将秒杀活动业务拆分开&#x…

**MySQL关联查询七种方式详解与应用实例**,你的掌握了吗

当我们需要从多个表中查询数据时&#xff0c;就需要使用关联查询了。MySQL支持七种不同类型的关联查询&#xff1a;内连接、左连接、右连接、全外连接、交叉连接、自连接和自然连接。本文将讲解这七种关联查询的SQL语句、示例以及应用场景。 一、 前言 关联查询是数据库操作中…

Leetcode 37 解数独

Leetcode解数独 题目描述题解1(按Board行列回溯&#xff1a;较直接) 题目描述 编写一个程序&#xff0c;通过填充空格来解决数独问题。 数独的解法需 遵循如下规则&#xff1a; 数字 1-9 在每一行只能出现一次数字 1-9 在每一列只能出现一次数字 1-9 在每一个以粗实线分隔的…

postgresql|数据库|批量执行SQL脚本文件的shell脚本

前言&#xff1a; 对于数据库的维护而言&#xff0c;肯定是有SQL脚本的执行&#xff0c;例如&#xff0c;某个项目需要更新&#xff0c;那么&#xff0c;可能会有很多的SQL脚本需要执行&#xff0c;SQL脚本可能会包含有建表&#xff0c;插入数据&#xff0c;索引建立&#xff…

Vue项目的性能优化

前言 Vue 框架通过数据双向绑定和虚拟 DOM 技术&#xff0c;帮我们处理了前端开发中最脏最累的 DOM 操作部分&#xff0c; 我们不再需要去考虑如何操作 DOM 以及如何最高效地操作 DOM&#xff1b;但 Vue 项目中仍然存在项目首屏优化、Webpack 编译配置优化等问题&#xff0c;所…

Towards Principled Disentanglement for Domain Generalization

本文用大量的理论论述了基于解纠缠约束优化的域泛化问题。 这篇文章认为以往的文章在解决域泛化问题时所用的方法都是non-trivial的&#xff0c;也就是说没有作严格的证明&#xff0c;是不可解释的&#xff0c;而本文用到大量的定理和推论证明了方法的有效性。 动机 因为域泛…

客户管理系统的作用有哪些?

阅读本文您将了解&#xff1a;1.客户管理系统的作用&#xff1b;2.客户管理系统软件怎么用&#xff1b;3.客户管理的注意事项。 一、客户管理系统的作用 客户是企业的重要财富&#xff0c;因此客户管理是企业发展过程中至关重要的一部分&#xff0c;那么客户管理怎么做&#…

把字符串转换成整数

题目&#xff1a;把字符串转换成整数 思路&#xff1a; 如果对于一般规则的数字“字符串”转化为数字都很容易&#xff0c;比如&#xff1a; 对于“123456”可以利用如下代码进行转化&#xff1a; string str"123456"; int ans 0; for (int i0; i<str.size(); …

Elesticesearch

1. 概述 应用场景&#xff1a; 给你一个巨大的文档数据&#xff0c;文档中存储着许多非结构化的数据&#xff0c;如下&#xff1a; {“id” : “1”, “name” : “佛山张学友”, “age” : “15”}, {“name” : “广州周润发”, “height” : “182”}, …中间有10000万行……

ABAP 二分法查找与SORT排序

需求场景 需要对内表排序&#xff0c;按降序排列&#xff0c;获取第一行&#xff1b;二分法查找需要的数据 我按照降序排列后&#xff0c;获取到了第一行&#xff0c;但是通过二分法查找没有获取到 二分法查找 二分查找&#xff0c;对排序数组通过二分区间排除的方法进行快速…

最好用的六款虚拟机软件,赶紧收藏

在日常工作和学习中,我们常常需要在一台电脑上运行多个操作系统,以便进行软件测试、开发、学习以及实验等任务。虚拟机软件就是一种崭新的技术,它可以在一台电脑上运行多个操作系统,为用户提供了更高效、安全、稳定和智能化的工作和学习环境。今天我为大家介绍6款优秀的虚拟…

k8s安装监控工具metrics-server

我们需要监控cpu和内存的使用率.以便提供硬件资源的申请采购建议. 也方便我们知道运行负荷, 而不是糊里糊涂出了问题再去解决或者工具自动解决了而我们不知道, 话说回来集群的好处就是低成本的达到高性能, 性能不去监控就有点太不专业了. 但, k8s居然不自带监控工具 https://ku…

了解hiberfil.sys文件:计算机休眠模式的背后

简介: hiberfil.sys是Windows操作系统中的一个文件&#xff0c;它通常存储在计算机的根目录下&#xff0c;用于保存休眠模式下的内存映像。当您将计算机置于休眠模式时&#xff0c;Windows会将所有正在运行的程序和数据保存到hiberfil.sys文件中&#xff0c;然后关闭计算…