如何在PyQt6中为图像创建蒙版并修改其颜色?
PyQt6实现图像蒙版与颜色修改的正确方案
问题背景
已有JavaScript实现的图像蒙版改色功能,现在需要在PyQt6中复刻相同效果。当前尝试createMaskFromColor仅得到黑白蒙版,无法实现目标效果。
原图

JavaScript实现效果

当前PyQt6代码问题
使用createMaskFromColor生成的蒙版是黑白的,无法叠加颜色实现JS中的效果。
解决方案:模拟Canvas的合成模式
PyQt6的QPainter支持类似Canvas的合成模式,可以通过以下步骤实现和JS一致的效果:
- 创建与图像尺寸一致的临时图像作为绘制画布
- 填充目标颜色到临时图像
- 使用
CompositionMode_DestinationAtop模式绘制原图,保留图像Alpha通道区域的颜色 - 使用
CompositionMode_Multiply模式再次绘制原图,增强细节 - 将最终合成的临时图像绘制到界面
修改后的完整代码
from sys import argv from sys import exit as ex from pathlib import Path from PyQt6.QtWidgets import QApplication, QWidget, QSizePolicy, QVBoxLayout from PyQt6.QtCore import Qt, QRectF, QTimer from PyQt6.QtGui import QPaintEvent, QPainter, QImage, QPen, QColor, QBrush class PaintWidget(QWidget): def __init__(self, parent=None) -> None: super().__init__() self.setSizePolicy( QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) ) # 加载并缩放图像(scaledToWidth返回新图像,需赋值) self.image_path = str(Path(Path(__file__).parent, "image.png")) self.image = QImage(self.image_path).scaledToWidth(150, Qt.TransformationMode.SmoothTransformation) self.target_color = QColor(255, 0, 0) # 目标红色,可修改为任意颜色 self.timer = QTimer(self) self.timer.timeout.connect(self.update) self.timer.start(17) def paintEvent(self, event: QPaintEvent | None) -> None: painter = QPainter(self) painter.setRenderHint(QPainter.RenderHint.Antialiasing) # 绘制背景 painter.setPen(QPen(QColor(169, 169, 169), 0, Qt.PenStyle.SolidLine)) painter.setBrush(QBrush(QColor(169, 169, 169), Qt.BrushStyle.SolidPattern)) painter.drawRect(self.rect()) # 创建临时图像作为合成画布 temp_image = QImage(self.image.size(), QImage.Format.Format_ARGB32) temp_image.fill(Qt.GlobalColor.transparent) temp_painter = QPainter(temp_image) temp_painter.setRenderHint(QPainter.RenderHint.Antialiasing) # 步骤1:填充目标颜色 temp_painter.fillRect(temp_image.rect(), self.target_color) # 步骤2:使用DestinationAtop模式绘制原图,保留图像区域的颜色 temp_painter.setCompositionMode(QPainter.CompositionMode.CompositionMode_DestinationAtop) temp_painter.drawImage(0, 0, self.image) # 步骤3:使用Multiply模式再次绘制原图,增强细节(与JS逻辑一致) temp_painter.setCompositionMode(QPainter.CompositionMode.CompositionMode_Multiply) temp_painter.drawImage(0, 0, self.image) temp_painter.end() # 将合成后的图像绘制到界面 rect = QRectF(0, 0, temp_image.width(), temp_image.height()) painter.drawImage(rect, temp_image) return super().paintEvent(event) class MainWindow(QWidget): def __init__(self) -> None: super().__init__() self.setup_ui() self.show() def setup_ui(self) -> None: self.showFullScreen() self.main_window_layout = QVBoxLayout() self.painter_widget = PaintWidget() self.main_window_layout.addWidget(self.painter_widget) self.setLayout(self.main_window_layout) if __name__ == "__main__": app = QApplication(argv) main_window = MainWindow() ex(app.exec())
关键说明
- 合成模式对应:
- JS中的
destination-atop对应PyQt的CompositionMode_DestinationAtop - JS中的
multiply对应PyQt的CompositionMode_Multiply
- JS中的
- 临时图像的作用:模拟Canvas的独立绘制环境,避免直接在界面画布操作导致的叠加问题
- 图像缩放:
scaledToWidth返回新图像,必须赋值给变量,否则原图像不会改变 - 渲染提示:开启
Antialiasing让图像边缘更平滑
内容的提问来源于stack exchange,提问作者negar amiri
相关产品推荐
相关产品推荐

