如何使用旋转的 QGraphicsRectItem 裁剪在场景上设置的 QPixmap?

How to crop QPixmap that is set on a Scene with a rotated QGraphicsRectItem?

我不知道如何裁剪在场景中设置的 QPixmap,同时旋转的 QGraphicsRectItem 也放置在同一场景中。

这是我的 QGraphicsScene 和 QPixmap 的代码。

class crop_pattern(QGraphicsView):
    img_is_cropped = QtCore.Signal(object)
    def __init__(self, path, scale):
        super().__init__()
        # Connect graphics scene with graphics view
        self.setFixedSize(500, 500)
        self.scene = QGraphicsScene(self)
        self.setScene(self.scene)
        self.roi_scale = scale
      
        # Display image
        self.set_image(path)

    def set_image(self, path):
        pixmap = QtGui.QPixmap(path)

        if pixmap:
            pixmap = pixmap.scaledToHeight(self.roi_scale * pixmap.height())

        self.scene.clear()
        self.scene.addPixmap(pixmap)
        
        self.setAlignment(QtCore.Qt.AlignCenter)

    def wheelEvent(self, event):
        zoomInFactor = 1.05
        zoomOutFactor = 1 / zoomInFactor

        oldPos = self.mapToScene(event.pos())

        if event.angleDelta().y() > 0:
            zoomFactor = zoomInFactor
        else:
            zoomFactor = zoomOutFactor
            
        self.scale(zoomFactor, zoomFactor)

        newPos = self.mapToScene(event.pos())

        delta = newPos - oldPos
        self.translate(delta.x(), delta.y())

(wheelEvent 函数归功于 QGraphicsView Zooming in and out under mouse position using mouse wheel

这里是用户点击某个按钮时生成的QGraphicsItem。

    QtCore.Slot(bool)
    def create_shape(self):
        sender = self.sender()
        if sender.text().lower() == "circle":
            self.shape = ellipse_shape(0, 0, 100, 100)

        elif sender.text().lower() == "rectangle":
            self.shape = rect_shape(0, 0, 100, 100)
            
        self.shape.setZValue(1)
        self.shape.setTransformOriginPoint(50, 50)

        self.crop_pattern.scene.addItem(self.shape) # added item to the same scene, which is crop_pattern.

这是问题建议的 GUI。 (QGraphicsRectItem 已调整大小)

如何裁剪矩形内的像素?谢谢!

一个可能的解决方案是创建一个隐藏的 QGraphicsView 并使用 render() 方法来保存图像部分。隐藏的QGraphicsView的objective不修改现有视图,因为图像除了不受缩放影响外还必须旋转。

from PyQt5 import QtCore, QtGui, QtWidgets


def crop_rect(rect_item, scene):
    is_visible = rect_item.isVisible()

    rect_item.hide()

    hide_view = QtWidgets.QGraphicsView(scene)
    hide_view.rotate(-rect_item.rotation())

    polygon = rect_item.mapToScene(rect_item.rect())
    pixmap = QtGui.QPixmap(rect_item.rect().size().toSize())
    pixmap.fill(QtCore.Qt.transparent)
    source_rect = hide_view.mapFromScene(polygon).boundingRect()

    painter = QtGui.QPainter(pixmap)
    hide_view.render(
        painter,
        target=QtCore.QRectF(pixmap.rect()),
        source=source_rect,
    )
    painter.end()

    rect_item.setVisible(is_visible)

    return pixmap


def main():
    app = QtWidgets.QApplication([])

    scene = QtWidgets.QGraphicsScene()
    view = QtWidgets.QGraphicsView(alignment=QtCore.Qt.AlignCenter)
    view.setScene(scene)
    # emulate wheel
    view.scale(0.8, 0.8)

    # create pixmap
    pixmap = QtGui.QPixmap(500, 500)
    pixmap.fill(QtGui.QColor("green"))
    painter = QtGui.QPainter(pixmap)
    painter.setBrush(QtGui.QColor("salmon"))
    painter.drawEllipse(pixmap.rect().adjusted(100, 90, -80, -100))
    painter.end()

    pixmap_item = scene.addPixmap(pixmap)

    rect = QtCore.QRectF(0, 0, 200, 300)
    rect_item = scene.addRect(rect)
    rect_item.setPen(QtGui.QPen(QtGui.QColor("red"), 4))
    rect_item.setPos(100, 100)
    rect_item.setTransformOriginPoint(50, 50)
    rect_item.setRotation(10)

    view.resize(640, 480)
    view.show()

    qpixmap = crop_rect(rect_item, scene)
    label = QtWidgets.QLabel()
    label.setPixmap(qpixmap)
    label.show()

    app.exec_()


if __name__ == "__main__":
    main()

输入:

输出: