Почему при вставке изображения кисть рисуется в другом месте?

При вставке изображения кисть рисуется в другом месте от курсора. Как сделать так, чтобы этого не происходило?

import sys

from PyQt5.QtGui import QPainter, QPen, QImage
from PyQt5.QtWidgets import QMainWindow, QApplication, QFileDialog, QAction
from PyQt5.QtCore import Qt


class Window(QMainWindow):
    def __init__(self):
        super().__init__()

        self.image = QImage(self.size(), QImage.Format_RGB32)
        self.image.fill(Qt.white)

        self.brushColor = Qt.black
        self.brushSize = 8

        self.setGeometry(200, 300, 650, 500)

        mainMenu = self.menuBar()
        colormenu = mainMenu.addMenu("Сюда")

        saveAction = QAction("Вставить фото", self)
        colormenu.addAction(saveAction)
        saveAction.triggered.connect(self.save)

    def save(self):
        filename = QFileDialog.getOpenFileName(self, "", "",
                                               "PNG(*.png);;JPEG(*.jpg *.jpeg);;All Files(*.*)")[0]
        if filename == '':
            return
        self.image.load(filename)

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.drawImage(self.rect(), self.image, self.image.rect())
        painter.setPen(QPen(self.brushColor, self.brushSize, Qt.SolidLine))

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.coords = event.pos()

    def mouseMoveEvent(self, event):
        if event.buttons() and Qt.LeftButton:
            painter = QPainter(self.image)
            painter.setPen(QPen(self.brushColor, self.brushSize, Qt.SolidLine))
            painter.drawLine(self.coords, event.pos())
            self.coords = event.pos()
            self.update()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    wnd = Window()
    wnd.show()
    sys.exit(app.exec())

Ответы (2 шт):

Автор решения: gil9red

Поигрался с вашим кодом и понял почему при рисовании на картинке происходит сдвиг курсора -- причина в разном размере картинки и окна. Рисуете вы ведь на картинке, а после саму картинку рисуете на окне, поэтому появляются такие отличия.

Можно сделать еще одну картинку, она будет прозрачная, на ней будет рисунок и ее нужно будет поверх всего рисовать. Единственное, что при изменении размера окна нужно будет ей тоже менять размер

Пример:

import sys

from PyQt5.QtGui import QPainter, QPen, QImage
from PyQt5.QtWidgets import QMainWindow, QApplication, QFileDialog, QAction
from PyQt5.QtCore import Qt


class Window(QMainWindow):
    def __init__(self):
        super().__init__()

        self.image_foreground = QImage(self.size(), QImage.Format_ARGB32)
        self.image_foreground.fill(Qt.transparent)

        self.image_background = QImage(self.size(), QImage.Format_RGB32)
        self.image_background.fill(Qt.white)

        self.brushColor = Qt.black
        self.brushSize = 8

        self.setGeometry(200, 300, 650, 500)

        mainMenu = self.menuBar()
        colormenu = mainMenu.addMenu("Сюда")

        saveAction = QAction("Вставить фото", self)
        colormenu.addAction(saveAction)
        saveAction.triggered.connect(self.save)

    def save(self):
        filename = QFileDialog.getOpenFileName(self, "", "", "PNG(*.png);;JPEG(*.jpg *.jpeg);;All Files(*.*)")[0]
        if not filename:
            return
        self.image_background.load(filename)

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.drawImage(self.rect(), self.image_background, self.image_background.rect())
        painter.drawImage(self.rect(), self.image_foreground, self.image_foreground.rect())
        painter.setPen(QPen(self.brushColor, self.brushSize, Qt.SolidLine))

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.coords = event.pos()

    def mouseMoveEvent(self, event):
        if event.buttons() == Qt.LeftButton:
            painter = QPainter(self.image_foreground)
            painter.setPen(QPen(self.brushColor, self.brushSize, Qt.SolidLine))
            painter.drawLine(self.coords, event.pos())
            self.coords = event.pos()
            self.update()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    wnd = Window()
    wnd.show()
    sys.exit(app.exec())

PS.

Если не нужно, чтобы картинка растягивалась под размер окна, то в drawImage первым параметром передавать размер картинки, а не окна:

painter.drawImage(self.image_foreground.rect(), self.image_foreground)
→ Ссылка
Автор решения: S. Nick

Немного другой подход. Для разнообразия.

import sys
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtGui import QPixmap, QPainter, QPen


class Menu(QMainWindow):
    def __init__(self):
        super().__init__()
        self.drawing = False
        self.lastPoint = QPoint()
        self.image = QPixmap("im.png")
        self.resize(self.image.width(), self.image.height())
        self.show()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.drawPixmap(self.rect(), self.image)

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.drawing = True
            self.lastPoint = event.pos()

    def mouseMoveEvent(self, event):
        if event.buttons() and Qt.LeftButton and self.drawing:
            painter = QPainter(self.image)
            painter.setPen(QPen(Qt.red, 3, Qt.SolidLine))
            painter.drawLine(self.lastPoint, event.pos())
            self.lastPoint = event.pos()
            self.update()

    def mouseReleaseEvent(self, event):
        if event.button == Qt.LeftButton:
            self.drawing = False


if __name__ == '__main__':
    app = QApplication(sys.argv)
    mainMenu = Menu()
    sys.exit(app.exec_())

введите сюда описание изображения

→ Ссылка