[Python] PySide snipping tool coordinates mismatch due to monitor scaling and dual monitor...

Discussão em 'Python' iniciado por Stack, Abril 11, 2025.

  1. Stack

    Stack Membro Participativo

    I have a Python application that captures a region of the screen using PySide6 and PIL libraries. The application works well on 1980x1080 resolution monitor. However, when using it on my primary monitor with a resolution 2560x1600 and a scaling factor of 175%, there is a significant mismatch between the captured region and the actual screenshot.

    I suspect this discrepancy is due to the monitor scaling factor affecting coordinates calculations. How can I adjust the coordinates to account for the monitor scaling factor?

    Additionally, I would like to extend the screen capture functionally to work on dual monitors, capturing regions from both monitors simultaneously. What approach should I take to implement this feature?

    # source from https://github.com/harupy/snipping-tool
    import sys
    from PySide6 import QtCore, QtGui, QtWidgets
    import tkinter as tk
    from PIL import ImageGrab
    import numpy as np
    import cv2
    import pygetwindow as gw

    class MyWidget(QtWidgets.QWidget):
    def __init__(self):
    super().__init__()
    root = tk.Tk()
    screen_width = root.winfo_screenwidth()
    screen_height = root.winfo_screenheight()
    root.withdraw() # Hide the root window
    screen_geometry = gw.getWindowsWithTitle(gw.getActiveWindow().title)[0]
    virtual_screen_width = screen_geometry.width
    virtual_screen_height = screen_geometry.height
    self.setGeometry(0, 0, virtual_screen_width, virtual_screen_height)
    self.setWindowTitle(' ')
    self.begin = QtCore.QPoint()
    self.end = QtCore.QPoint()
    self.setWindowOpacity(0.3)
    self.num_snip = 0
    self.is_snipping = False
    QtWidgets.QApplication.setOverrideCursor(
    QtGui.QCursor(QtCore.Qt.CrossCursor)
    )
    self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
    print('Capture the screen...')
    print('Press q if you want to quit...')
    self.show()

    def paintEvent(self, event):
    if self.is_snipping:
    brush_color = (0, 0, 0, 0)
    lw = 0
    opacity = 0
    else:
    brush_color = (128, 128, 255, 128)
    lw = 3
    opacity = 0.3

    self.setWindowOpacity(opacity)
    qp = QtGui.QPainter(self)
    qp.setPen(QtGui.QPen(QtGui.QColor('black'), lw))
    qp.setBrush(QtGui.QColor(*brush_color))
    qp.drawRect(QtCore.QRectF(self.begin, self.end))

    def keyPressEvent(self, event):
    if event.key() == QtCore.Qt.Key_Q:
    print('Quit')
    self.close()
    event.accept()

    def mousePressEvent(self, event):
    self.begin = event.position()
    self.end = self.begin
    self.update()

    def mouseMoveEvent(self, event):
    self.end = event.position()
    self.update()

    def mouseReleaseEvent(self, event):
    self.num_snip += 1
    x1 = min(self.begin.x(), self.end.x())
    y1 = min(self.begin.y(), self.end.y())
    x2 = max(self.begin.x(), self.end.x())
    y2 = max(self.begin.y(), self.end.y())

    self.is_snipping = True
    self.repaint()
    QtWidgets.QApplication.processEvents()
    img = ImageGrab.grab(bbox=(x1, y1, x2, y2))
    self.is_snipping = False
    self.repaint()
    QtWidgets.QApplication.processEvents()
    img_name = 'snip{}.png'.format(self.num_snip)
    img.save(img_name)
    print(img_name, 'saved')
    img = cv2.cvtColor(np.array(img), cv2.COLOR_BGR2RGB)


    if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    window = MyWidget()
    window.show()
    app.aboutToQuit.connect(app.deleteLater)
    sys.exit(app.exec())



    I am currently exploring the screeninfo library to address issues related to screen resolution and DPI scaling..

    Continue reading...

Compartilhe esta Página