class Label(QLabel): selection_changed = pyqtSignal(QRect, name="selectionChanged") def __init__(self): QLabel.__init__(self) self.rb = QRubberBand(QRubberBand.Rectangle, self) self.setMouseTracking(True) def mousePressEvent(self, event: QMouseEvent): self.origin = event.pos() self.rb.setGeometry(QRect(self.origin, QSize())) self.rb.show() QLabel.mousePressEvent(self, event) def mouseMoveEvent(self, event: QMouseEvent): if self.rb.isVisible(): self.rb.setGeometry( QRect(self.origin, event.pos()).normalized()) QWidget.mouseMoveEvent(self, event) def mouseReleaseEvent(self, event): if self.rb.isVisible(): self.rb.hide() self.selection_changed.emit(self.rb.geometry()) QLabel.mouseReleaseEvent(self, event)
class MiniMapGraphicsView(QGraphicsView): def __init__(self, parent): super().__init__(parent) self._drag_start_pos = None self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.setFixedSize(200, 200) self.viewport().setFixedSize(self.contentsRect().size()) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setInteractive(False) self.setFocusProxy(parent) self.band = QRubberBand(QRubberBand.Rectangle, self) self.band.hide() def centerOn(self, pos): if self.band.isVisible(): self.parent().centerOn(self.mapToScene(pos)) rect = self.band.geometry() rect.moveCenter(pos) self.band.setGeometry(rect) def mousePressEvent(self, event): if self.band.isVisible() and event.button() == Qt.LeftButton: rect = self.band.geometry() if event.pos() in rect: self._drag_start_pos = event.pos() else: self.centerOn(event.pos()) def mouseMoveEvent(self, event): if self.band.isVisible() and event.buttons() == Qt.MouseButtons( Qt.LeftButton) and self._drag_start_pos is not None: self.centerOn(event.pos()) def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton and self.band.isVisible(): self.viewport().unsetCursor() self._drag_start_pos = None def adjustRubberband(self): scene = self.scene() if scene is None: return rect = self.parent().mapToScene(self.parent().rect()).boundingRect() if not rect.contains(scene.sceneRect()): rect = self.mapFromScene(rect).boundingRect() self.band.setGeometry(rect) self.band.show() else: self.band.hide() def zoomToFit(self): self.fitInView(self.scene().sceneRect().adjusted(-20, -20, 20, 20), Qt.KeepAspectRatio)
class SelectWidget(QWidget, Ui_Form2): select = [0,0,0,0] def __init__(self, parent=None): super(SelectWidget, self).__init__(parent) self.setWindowOpacity(0.5) self.setupUi(self) desktop = QtWidgets.QDesktopWidget() self.resize(desktop.availableGeometry().width(), desktop.availableGeometry().height()) self.rubberband = QRubberBand( QRubberBand.Rectangle, self) self.setMouseTracking(True) def mousePressEvent(self, event): self.select[0] = event.screenPos().x() self.select[1] = event.screenPos().y() self.origin = event.pos() self.rubberband.setGeometry( QtCore.QRect(self.origin, QtCore.QSize())) self.rubberband.show() QWidget.mousePressEvent(self, event) def mouseMoveEvent(self, event): if self.rubberband.isVisible(): self.rubberband.setGeometry( QtCore.QRect(self.origin, event.pos()).normalized()) QWidget.mouseMoveEvent(self, event) def mouseReleaseEvent(self, event): self.select[2] = event.screenPos().x() self.select[3] = event.screenPos().y() if self.rubberband.isVisible(): self.rubberband.hide() rect = self.rubberband.geometry() # ポインタ座標を左上→右下に揃える if self.select[0] > self.select[2]: tmp = self.select[0] self.select[0] = self.select[2] self.select[2] = tmp if self.select[1] > self.select[3]: tmp = self.select[1] self.select[1] = self.select[3] self.select[3] = tmp # 選択した面積がゼロの場合は何もしないで関数を終わる if self.select[0]==self.select[2] or self.select[1]==self.select[3]: QWidget.mouseReleaseEvent(self, event) self.close() return # ポインタ座標をメインウインドウに設定する area = '' for point in self.select: area = area + str(int(point)) + ',' main_window.lineEdit.setText(area[0:-1]) self.close() QWidget.mouseReleaseEvent(self, event)
class VideoArea(QLabel): def __init__(self, parent=None, main=None): QLabel.__init__(self, parent) self.selection = QRubberBand(QRubberBand.Rectangle, self) self.main = main def mousePressEvent(self, event): if event.button() == Qt.LeftButton: position = QPoint(event.pos()) if self.selection.isVisible(): if (self.upper_left - position).manhattanLength() < 20: self.mode = "UL" elif (self.lower_right - position).manhattanLength() < 20: self.mode = "LR" else: self.selection.hide() else: self.upper_left = position self.lower_right = position self.mode = "LR" self.selection.show() def mouseMoveEvent(self, event): if self.selection.isVisible(): if self.mode == "LR": self.lower_right = QPoint(event.pos()) elif self.mode == "UL": self.upper_left = QPoint(event.pos()) self.selection.setGeometry( QRect(self.upper_left, self.lower_right).normalized()) def mouseReleaseEvent(self, event): self.main.controller.set_coordinates( *self.selection.geometry().getCoords()) self.selection.hide()
class DragWidget(QWidget): spacerX = 16 spacerY = 16 clipicon = None new_window_signal = pyqtSignal(str) query = pyqtSignal() src_dragwidget = None src_selected = [] def __init__(self, path, parent=None): super(DragWidget, self).__init__(parent) self.setMinimumSize(400, 200) self.setAcceptDrops(True) self.parent = parent # self.parent.menu.connect(self.delete_icon) self.modifier = False self.rubberband = QRubberBand(QRubberBand.Rectangle, self) self.path = path self.icons = [] self.icon_offsetx = 0 self.icon_offsety = 0 # self.clipicon = None # self.moving_icons = [] self.read_drawer() self.clean_up() # print(type(IconWidget.icon)) # print(self.findChildren(ClickableIcon)) def read_drawer(self): # self.icons.clear() for item in os.scandir(self.path): if item.is_dir(): icon_widget = IconWidget(parent=self, name=item.name, path=self.path, dir=True) else: icon_widget = IconWidget(parent=self, name=item.name, path=self.path, dir=False) icon_widget.new_window.connect(self.new_window_signal.emit) icon_widget.clipboard.connect(self.on_clipboard) self.icons.append(icon_widget) self.icons[-1].setAttribute(Qt.WA_DeleteOnClose) # self.update() def updateScrollArea(self): """ set the dimension of the widget """ iconx = [] icony = [] if len(self.icons) > 0: for item in self.icons: iconx.append(item.x()) icony.append(item.y()) self.setMinimumWidth(max(iconx)+75) self.setMinimumHeight(max(icony)+75) def dragEnterEvent(self, event): event.accept() def dragMoveEvent(self, event): event.accept() def get_dnd_list(self, event): icon_list = [] icon_offsetx = None icon_offsety = None if len(DragWidget.src_selected) > 0: for item in DragWidget.src_selected: icon_list.append(item) else: icon_list.append(event.source()) return icon_list def create_icon(self, name, drawer): if drawer: icon_widget = IconWidget(self, name=name, path=self.path, dir=True) else: icon_widget = IconWidget(self, name=name, path=self.path, dir=False) icon_widget.new_window.connect(self.new_window_signal.emit) self.icons.append(icon_widget) def place_icon(self, x, y): self.icons[-1].move(x, y) self.icons[-1].show() def dropEvent(self, event): event.accept() icon_list = self.get_dnd_list(event) icon_offsetx = event.pos().x() icon_offsety = event.pos().y() for item in icon_list: name = item.name drawer = item.drawer src_path = item.path + "/" + name dst_path = self.path + "/" if event.mimeData().hasFormat("application/x-icon"): self.create_icon(name, drawer) self.move_data(src_path, dst_path) self.place_icon(icon_offsetx, icon_offsety) icon_offsetx += 100 if icon_offsetx > self.window().width(): icon_offsetx = event.pos().x() icon_offsety += 75 icon_offsetx = None icon_offsety = None self.updateScrollArea() def clear_dnd(self): DragWidget.src_dragwidget = None DragWidget.src_selected.clear() def get_modifier(self): return self.parent.modifier def mousePressEvent(self, event): if event.buttons() == Qt.LeftButton: for item in self.icons: item.icon.deselect_icon() self.clear_dnd() self.origin = event.pos() self.rubberband.setGeometry(QRect(self.origin, QSize())) self.rubberband.show() def mouseMoveEvent(self, event): if self.rubberband.isVisible(): self.rubberband.setGeometry( QRect(self.origin, event.pos()).normalized()) # QWidget.mouseMoveEvent(self, event) def mouseReleaseEvent(self, event): self.clear_dnd() if self.rubberband.isVisible(): self.rubberband.hide() rect = self.rubberband.geometry() for child in self.findChildren(IconWidget): if rect.intersects(child.geometry()): child.icon.select_icon() DragWidget.src_selected.append(child) if DragWidget.src_dragwidget is not self: DragWidget.src_dragwidget = self def mouseDoubleClickEvent(self, event): print(BLU, "Double Click", END) self.query.emit() def create_file(self): new_file = self.path + "/" + "newfile.txt" open(new_file, 'w').close() icon_widget = IconWidget(self, name="newfile.txt", path=self.path, dir=False) icon_widget.new_window.connect(self.new_window_signal.emit) icon_widget.show() self.icons.append(icon_widget) def create_drawer(self): print("creating new drawer") new_drawer = self.path + "/" + "NewDrawer" os.makedirs(new_drawer) icon_widget = IconWidget(self, name="NewDrawer", path=self.path, dir=True) icon_widget.new_window.connect(self.new_window_signal.emit) icon_widget.show() self.icons.append(icon_widget) def rename_file(self): print("renaming file") def clean_up(self): for item in self.icons: item.move(DragWidget.spacerX, DragWidget.spacerY) # initial icon placement DragWidget.spacerX += 100 if DragWidget.spacerX + 100 > self.window().width(): DragWidget.spacerY += 75 DragWidget.spacerX = 16 # reset placement values DragWidget.spacerX = 16 DragWidget.spacerY = 16 self.updateScrollArea() def move_data(self, source, dest): srce_path = source.rsplit('/', 1)[0] dest_path = dest.rsplit('/', 1)[0] if srce_path != dest_path: try: shutil.move(source, dest) except Exception as err: print(err) def copy_icon(self, source, dest): pass def delete_icon(self): dest = os.path.expanduser("~") + "/.Trash/" error_string = "" for item in self.icons: if item.icon.selected: source = item.path + "/" + item.name if source is not "": try: shutil.move(source, dest) except Exception as err: error_string += str(err) + "\n" + "\n" else: self.icons.remove(item) item.deleteLater() if error_string is not "": QMessageBox.information(self, 'Info', error_string, QMessageBox.Ok) def paste_icon(self): print("---") print("srce=", self.clipicon.path + "/" + self.clipicon.name) # print("res=", self.clipicon.path + "/" + self.clipicon.name) print("dest=", self.path + "/") # if os.path.isdir(os.path.join(self.clipicon.path, self.clipicon.name)): SRCE = self.clipicon.path + "/" + self.clipicon.name DEST = self.path+"/" + self.clipicon.name shutil.copytree(SRCE, DEST) def on_clipboard(self, icon): print("realpath", self.path) print("clip_icon_name=", icon.name) DragWidget.clipicon = icon
class ImageViewer(QLabel): def __init__(self): super(ImageViewer, self).__init__() self.crop = Signal() #pixmap = QPixmap(640, 640) pixmap = QPixmap() self.setPixmap(pixmap) self.first_x, self.first_y = None, None self.last_x, self.last_y = None, None self.pen_color = QColor('#000000') self.scaleFactor = 0.0 self.setBackgroundRole(QPalette.Base) #self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) #self.setScaledContents(True) #self.setGeometry(QRect(110, 550, 640, 640)) self.setText("Feature") self.setAlignment(Qt.AlignTop | Qt.AlignLeft) #self.setAlignment(Qt.AlignCenter) self.setWordWrap(False) #self.setFixedSize(640,640) self.createActions() self.show() #self.showMaximized() def setImage(self, q_img): self.setPixmap(q_img) self.scaleFactor = 1.0 #self.fitToWindowAct.setEnabled(True) self.updateActions() if not self.fitToWindowAct.isChecked(): self.adjustSize() def open(self): fileName, _ = QFileDialog.getOpenFileName(self, "Open File", QDir.currentPath()) if fileName: image = QImage(fileName) if image.isNull(): QMessageBox.information(self, "Image Viewer", "Cannot load %s." % fileName) return self.setPixmap(QPixmap.fromImage(image)) self.scaleFactor = 1.0 self.fitToWindowAct.setEnabled(True) self.updateActions() if not self.fitToWindowAct.isChecked(): self.adjustSize() def zoomIn(self): self.scaleImage(1.25) def zoomOut(self): self.scaleImage(0.8) def normalSize(self): self.adjustSize() self.scaleFactor = 1.0 def fitToWindow(self): fitToWindow = self.fitToWindowAct.isChecked() self.scrollArea.setWidgetResizable(fitToWindow) if not fitToWindow: self.normalSize() self.updateActions() def createActions(self): self.openAct = QAction("&Open...", self, shortcut="Ctrl+O", triggered=self.open) self.zoomInAct = QAction("Zoom &In (25%)", self, shortcut="Ctrl++", enabled=False, triggered=self.zoomIn) self.zoomOutAct = QAction("Zoom &Out (25%)", self, shortcut="Ctrl+-", enabled=False, triggered=self.zoomOut) self.normalSizeAct = QAction("&Normal Size", self, shortcut="Ctrl+S", enabled=False, triggered=self.normalSize) self.fitToWindowAct = QAction("&Fit to Window", self, enabled=False, checkable=True, shortcut="Ctrl+F", triggered=self.fitToWindow) def updateActions(self): self.zoomInAct.setEnabled(not self.fitToWindowAct.isChecked()) self.zoomOutAct.setEnabled(not self.fitToWindowAct.isChecked()) self.normalSizeAct.setEnabled(not self.fitToWindowAct.isChecked()) def scaleImage(self, factor): self.scaleFactor *= factor self.resize(self.scaleFactor * self.pixmap().size()) self.zoomInAct.setEnabled(self.scaleFactor < 3.0) self.zoomOutAct.setEnabled(self.scaleFactor > 0.333) def mousePressEvent(self, eventQMouseEvent): self.originQPoint = self.mapFrom(self, eventQMouseEvent.pos()) self.first_x = int(eventQMouseEvent.x()) self.first_y = int(eventQMouseEvent.y()) self.currentQRubberBand = QRubberBand(QRubberBand.Rectangle, self) self.currentQRubberBand.setGeometry(QRect(self.originQPoint, QSize())) self.currentQRubberBand.show() def mouseMoveEvent(self, eventQMouseEvent): self.x = int(eventQMouseEvent.x()) self.y = int(eventQMouseEvent.y()) text1 = str(self.x) text2 = str(self.y) p = self.mapToGlobal(eventQMouseEvent.pos()) #QToolTip.showText(eventQMouseEvent.pos() , "X: "+text1+" "+"Y: "+text2,self) QToolTip.showText(p, "X: " + text1 + " " + "Y: " + text2, self) # print ('mouse QToolTip 1') 전체장에서의 위젯 시작점의 좌표가 오리진 포인트가 되어야 함. ''' if self.currentQRubberBand.isVisible(): self.currentQRubberBand.setGeometry(QRect(self.originQPoint, eventQMouseEvent.pos()).normalized() & self.pixmap().rect()) ''' pos = self.mapFromGlobal(self.mapToGlobal(eventQMouseEvent.pos())) #QToolTip.showText(eventQMouseEvent.pos(), "X: {} Y: {}".format(p.x(), p.y()), self) if self.currentQRubberBand.isVisible() and self.pixmap() is not None: self.currentQRubberBand.setGeometry( QRect(self.originQPoint, pos).normalized() & self.rect()) def mouseReleaseEvent(self, eventQMouseEvent): self.last_x = int(eventQMouseEvent.x()) self.last_y = int(eventQMouseEvent.y()) ''' self.currentQRubberBand.hide() currentQRect = self.currentQRubberBand.geometry() self.currentQRubberBand.deleteLater() if self.pixmap() is not None: tr = QTransform() if self.fitToWindowAct.isChecked(): tr.scale(self.pixmap().width() / self.scrollArea.width(), self.pixmap().height() / self.scrollArea.height()) else: tr.scale(1 / self.scaleFactor, 1 / self.scaleFactor) r = tr.mapRect(currentQRect) cropQPixmap = self.pixmap().copy(r) cropQPixmap.save('output.png') ''' self.currentQRubberBand.hide() currentQRect = self.currentQRubberBand.geometry() self.currentQRubberBand.deleteLater() cropQPixmap = self.pixmap().copy(currentQRect) #size = cropQPixmap.size() # 직접변환 해서 저장하는 코드... 나중에 #s = cropQPixmap.bits().asstring(size.width() * size.height() * image.depth() // 8) # format 0xffRRGGBB #arr = np.fromstring(s, dtype=np.uint8).reshape((size.height(), size.width(), cropQPixmap.depth() // 8)) #new_image = Image.fromarray(array) cropQPixmap.save('output.png') img = cv2.imread("output.png", cv2.IMREAD_COLOR) h, w = self.cut_imgSize() self.crop.cut_signal.emit(img, h, w) def cut_imgSize(self): h = abs(self.last_y - self.first_y) w = abs(self.last_x - self.first_x) return h, w
class FsApp(QMainWindow): def __init__(self, app): super(FsApp, self).__init__() self.app = app self.selRect = None self.screenPix = None # Set up the user interface from Designer. self.ui = Ui_MainWindow() self.ui.setupUi(self) #self.setWindowOpacity(0.5) #self.setAttribute(QtCore.Qt.WA_TranslucentBackground, True) self.captureScreen() self.showMaximized() self.showFullScreen() #capture screen and display rec = QApplication.desktop().screenGeometry() height = rec.height() width = rec.width() self.ui.labPix.resize(width, height) self.ui.labPix.setScaledContents(True) self.ui.labPix.setPixmap(self.screenPix) #start rubberband self.rubberband = QRubberBand(QRubberBand.Rectangle, self) bla = QtGui.QPalette() bla.setBrush(QtGui.QPalette.Highlight, QtGui.QBrush(QtCore.Qt.red)) self.rubberband.setPalette(bla) self.rubberband.setWindowOpacity(1.0) def captureScreen(self): screens = self.app.screens() self.screenPix = screens[0].grabWindow(0) def mousePressEvent(self, event): self.origin = event.pos() self.rubberband.setGeometry(QtCore.QRect(self.origin, QtCore.QSize())) self.rubberband.show() QWidget.mousePressEvent(self, event) def mouseMoveEvent(self, event): if self.rubberband.isVisible(): self.rubberband.setGeometry(QtCore.QRect(self.origin, event.pos()).normalized()) QWidget.mouseMoveEvent(self, event) def mouseReleaseEvent(self, event): if self.rubberband.isVisible(): self.selRect = self.rubberband.geometry() self.rubberband.hide() codePix = self.screenPix.copy( self.selRect.x(), self.selRect.y(), self.selRect.width(), self.selRect.height()) QApplication.clipboard().setPixmap(codePix) self.exit() QWidget.mouseReleaseEvent(self, event) def exit(self): sys.exit(0)
class DragWidget(QWidget): spacerX = 16 spacerY = 16 clipicon = None new_window_signal = pyqtSignal(str) query = pyqtSignal() src_dragwidget = None src_selected = [] def __init__(self, path, parent=None): super(DragWidget, self).__init__(parent) self.setMinimumSize(400, 200) self.setAcceptDrops(True) self.parent = parent # self.parent.menu.connect(self.delete_icon) self.modifier = False self.rubberband = QRubberBand(QRubberBand.Rectangle, self) self.path = path self.icons = [] self.icon_offsetx = 0 self.icon_offsety = 0 # self.clipicon = None # self.moving_icons = [] self.read_drawer() self.clean_up() # print(type(IconWidget.icon)) # print(self.findChildren(ClickableIcon)) def read_drawer(self): # self.icons.clear() for item in os.scandir(self.path): if item.is_dir(): icon_widget = IconWidget(parent=self, name=item.name, path=self.path, dir=True) else: icon_widget = IconWidget(parent=self, name=item.name, path=self.path, dir=False) icon_widget.new_window.connect(self.new_window_signal.emit) icon_widget.clipboard.connect(self.on_clipboard) self.icons.append(icon_widget) self.icons[-1].setAttribute(Qt.WA_DeleteOnClose) # self.update() def updateScrollArea(self): """ set the dimension of the widget """ iconx = [] icony = [] if len(self.icons) > 0: for item in self.icons: iconx.append(item.x()) icony.append(item.y()) self.setMinimumWidth(max(iconx) + 75) self.setMinimumHeight(max(icony) + 75) def dragEnterEvent(self, event): event.accept() def dragMoveEvent(self, event): event.accept() def get_dnd_list(self, event): icon_list = [] icon_offsetx = None icon_offsety = None if len(DragWidget.src_selected) > 0: for item in DragWidget.src_selected: icon_list.append(item) else: icon_list.append(event.source()) return icon_list def create_icon(self, name, drawer): if drawer: icon_widget = IconWidget(self, name=name, path=self.path, dir=True) else: icon_widget = IconWidget(self, name=name, path=self.path, dir=False) icon_widget.new_window.connect(self.new_window_signal.emit) self.icons.append(icon_widget) def place_icon(self, x, y): self.icons[-1].move(x, y) self.icons[-1].show() def dropEvent(self, event): event.accept() icon_list = self.get_dnd_list(event) icon_offsetx = event.pos().x() icon_offsety = event.pos().y() for item in icon_list: name = item.name drawer = item.drawer src_path = item.path + "/" + name dst_path = self.path + "/" if event.mimeData().hasFormat("application/x-icon"): self.create_icon(name, drawer) self.move_data(src_path, dst_path) self.place_icon(icon_offsetx, icon_offsety) icon_offsetx += 100 if icon_offsetx > self.window().width(): icon_offsetx = event.pos().x() icon_offsety += 75 icon_offsetx = None icon_offsety = None self.updateScrollArea() def clear_dnd(self): DragWidget.src_dragwidget = None DragWidget.src_selected.clear() def get_modifier(self): return self.parent.modifier def mousePressEvent(self, event): if event.buttons() == Qt.LeftButton: for item in self.icons: item.icon.deselect_icon() self.clear_dnd() self.origin = event.pos() self.rubberband.setGeometry(QRect(self.origin, QSize())) self.rubberband.show() def mouseMoveEvent(self, event): if self.rubberband.isVisible(): self.rubberband.setGeometry( QRect(self.origin, event.pos()).normalized()) # QWidget.mouseMoveEvent(self, event) def mouseReleaseEvent(self, event): self.clear_dnd() if self.rubberband.isVisible(): self.rubberband.hide() rect = self.rubberband.geometry() for child in self.findChildren(IconWidget): if rect.intersects(child.geometry()): child.icon.select_icon() DragWidget.src_selected.append(child) if DragWidget.src_dragwidget is not self: DragWidget.src_dragwidget = self def mouseDoubleClickEvent(self, event): print(BLU, "Double Click", END) self.query.emit() def create_file(self): new_file = self.path + "/" + "newfile.txt" open(new_file, 'w').close() icon_widget = IconWidget(self, name="newfile.txt", path=self.path, dir=False) icon_widget.new_window.connect(self.new_window_signal.emit) icon_widget.show() self.icons.append(icon_widget) def create_drawer(self): print("creating new drawer") new_drawer = self.path + "/" + "NewDrawer" os.makedirs(new_drawer) icon_widget = IconWidget(self, name="NewDrawer", path=self.path, dir=True) icon_widget.new_window.connect(self.new_window_signal.emit) icon_widget.show() self.icons.append(icon_widget) def rename_file(self): print("renaming file") def clean_up(self): for item in self.icons: item.move(DragWidget.spacerX, DragWidget.spacerY) # initial icon placement DragWidget.spacerX += 100 if DragWidget.spacerX + 100 > self.window().width(): DragWidget.spacerY += 75 DragWidget.spacerX = 16 # reset placement values DragWidget.spacerX = 16 DragWidget.spacerY = 16 self.updateScrollArea() def move_data(self, source, dest): srce_path = source.rsplit('/', 1)[0] dest_path = dest.rsplit('/', 1)[0] if srce_path != dest_path: try: shutil.move(source, dest) except Exception as err: print(err) def copy_icon(self, source, dest): pass def delete_icon(self): dest = os.path.expanduser("~") + "/.Trash/" error_string = "" for item in self.icons: if item.icon.selected: source = item.path + "/" + item.name if source is not "": try: shutil.move(source, dest) except Exception as err: error_string += str(err) + "\n" + "\n" else: self.icons.remove(item) item.deleteLater() if error_string is not "": QMessageBox.information(self, 'Info', error_string, QMessageBox.Ok) def paste_icon(self): print("---") print("srce=", self.clipicon.path + "/" + self.clipicon.name) # print("res=", self.clipicon.path + "/" + self.clipicon.name) print("dest=", self.path + "/") # if os.path.isdir(os.path.join(self.clipicon.path, self.clipicon.name)): SRCE = self.clipicon.path + "/" + self.clipicon.name DEST = self.path + "/" + self.clipicon.name shutil.copytree(SRCE, DEST) def on_clipboard(self, icon): print("realpath", self.path) print("clip_icon_name=", icon.name) DragWidget.clipicon = icon
class QTrappingPattern(pg.ScatterPlotItem): """Interface between QJansenScreen GUI and CGH pipeline. Implements logic for manipulating traps. """ trapAdded = pyqtSignal(QTrap) sigCompute = pyqtSignal(object) def __init__(self, parent=None, *args, **kwargs): super(QTrappingPattern, self).__init__(*args, **kwargs) self.setParent(parent) # this is not set by ScatterPlotItem self.setPxMode(False) # scale plot symbols with window # Rubberband selection self.selection = QRubberBand(QRubberBand.Rectangle, self.parent()) self.origin = QPoint() # traps, selected trap and active group self.traps = QTrapGroup(self) self.trap = None self.group = None self._prev = None self.selected = [] self._appearanceOutdated = False self._hologramOutdated = False @property def prev(self): return self._prev @prev.setter def prev(self, prev): if self._prev is not None: self._prev.state = states.normal self._prev = prev if self.prev is not None: prev.state = states.special @pyqtSlot() def toggleAppearance(self): logger.debug('toggleAppearance') self._appearanceOutdated = True @pyqtSlot() def toggleHologram(self): logger.debug('toggleHologram') self._hologramOutdated = True @pyqtSlot(object) def refresh(self, frame): self.refreshAppearance() self.refreshHologram() @pyqtSlot() def refreshAppearance(self): """Provide a list of spots to screen for plotting. This will be called by children when their properties change. Changes can be triggered by mouse events, by interaction with property widgets, or by direct programmatic control of traps or groups. """ if self._appearanceOutdated: traps = self.traps.flatten() spots = [trap.spot for trap in traps] self.setData(spots=spots) self._appearanceOutdated = False logger.debug('refreshAppearance') @pyqtSlot() def refreshHologram(self): if self._hologramOutdated: traps = self.traps.flatten() self.sigCompute.emit(traps) self._hologramOutdated = False logger.debug('refreshHologram') def selectedPoint(self, position): points = self.pointsAt(position) index = self.points().tolist().index(points[0]) if points else None return index # Selecting traps and groups of traps def clickedTrap(self, pos): """Return the trap at the specified position """ coords = self.mapFromScene(pos) index = self.selectedPoint(coords) found = index is not None return self.traps.flatten()[index] if found else None def groupOf(self, obj): """Return the highest-level group containing the specified object. """ if obj is None: return None while obj.parent() is not self.traps: obj = obj.parent() return obj def clickedGroup(self, pos): """Return the highest-level group containing the trap at the specified position. """ self.trap = self.clickedTrap(pos) return self.groupOf(self.trap) def selectedTraps(self, region): """Return a list of traps whose groups fall entirely within the selection region. """ self.selected = [] rect = self.mapFromScene(QRectF(region)).boundingRect() for child in self.traps.children(): if child.isWithin(rect): self.selected.append(child) child.state = states.grouping else: child.state = states.normal self.refreshAppearance() # Creating and deleting traps def addTrap(self, trap): trap.setParent(self) self.traps.add(trap) trap.appearanceChanged.connect(self.toggleAppearance) trap.hologramChanged.connect(self.toggleHologram) trap.destroyed.connect(self.toggleAppearance) trap.destroyed.connect(self.toggleHologram) trap.cgh = self.parent().cgh.device self.trapAdded.emit(trap) def createTrap(self, r, state=None): trap = QTrap(r=r, state=state) self.addTrap(trap) return trap def createTraps(self, coordinates, state=None): coords = list(coordinates) if not coords: return group = QTrapGroup() self.traps.add(group) for r in coords: trap = self.createTrap(r, state=state) group.add(trap) return group def clearTrap(self, trap): """Remove specified trap from trapping pattern""" self.traps.remove(trap, delete=True) def clearTraps(self, traps=None): """Remove all traps from trapping pattern. """ traps = traps or self.traps.flatten() for trap in traps: self.clearTrap(trap) # Creating, breaking and moving groups of traps def createGroup(self): """Combine selected objects into new group""" group = QTrapGroup() for trap in self.selected: if trap.parent() is not self: trap.parent().remove(trap) group.add(trap) self.traps.add(group) self.selected = [] return group def breakGroup(self): """Break group into children and place children in the top level. """ if isinstance(self.group, QTrapGroup): for child in self.group.children(): child.state = states.grouping self.group.remove(child) self.traps.add(child) self.group = None def moveGroup(self, pos): """Move the selected group so that the selected trap is at the specified position. """ coords = self.mapFromScene(pos) dr = QVector3D(coords - self.trap.coords()) self.group.moveBy(dr) # Dispatch low-level events to actions def leftPress(self, pos, modifiers): """Selection and grouping. """ self.group = self.clickedGroup(pos) # update selection rectangle if self.group is None: self.origin = QPoint(pos) rect = QRect(self.origin, QSize()) self.selection.setGeometry(rect) self.selection.show() # break selected group elif modifiers == Qt.ControlModifier: self.breakGroup() # select group else: self.group.state = states.selected self.refreshAppearance() def rightPress(self, pos, modifiers): """Creation and destruction. """ # Shift-Right Click: Add trap if modifiers == Qt.ShiftModifier: r = self.mapFromScene(pos) self.createTrap(r, state=states.selected) # Ctrl-Right Click: Delete trap elif modifiers == Qt.ControlModifier: self.traps.remove(self.clickedGroup(pos), delete=True) # Handlers for signals emitted by QJansenScreen @pyqtSlot(QMouseEvent) def mousePress(self, event): """Event handler for mousePress events. """ button = event.button() pos = event.pos() modifiers = event.modifiers() self.prev = None if button == Qt.LeftButton: self.leftPress(pos, modifiers) elif button == Qt.RightButton: self.rightPress(pos, modifiers) @pyqtSlot(QMouseEvent) def mouseMove(self, event): """Event handler for mouseMove events. """ pos = event.pos() # Move traps if self.group is not None: self.moveGroup(pos) # Update selection box elif self.selection.isVisible(): region = QRect(self.origin, QPoint(pos)).normalized() self.selection.setGeometry(region) self.selectedTraps(region) @pyqtSlot(QMouseEvent) def mouseRelease(self, event): """Event handler for mouseRelease events. """ if self.selected: self.createGroup() for child in self.traps.children(): child.state = states.normal self.prev = self.group self.group = None self.selection.hide() self.refreshAppearance() @pyqtSlot(QWheelEvent) def mouseWheel(self, event): """Event handler for mouse wheel events. """ pos = event.pos() group = self.clickedGroup(pos) if group is not None: group.state = states.selected dz = event.angleDelta().y() / 120. group.moveBy(QVector3D(0, 0, dz)) # group.state = states.normal self.group = None
class ViewerWidget(QAbstractScrollArea): """ The main ViewerWidget class. Should be embeddable in other applications. See the open() function for loading images. """ # signals geolinkMove = pyqtSignal(GeolinkInfo, name='geolinkMove') geolinkQueryPoint = pyqtSignal(GeolinkInfo, name='geolinkQueryPoint') # can't use ViewerWidget - use base class instead layerAdded = pyqtSignal(QAbstractScrollArea, name='layerAdded') showStatusMessage = pyqtSignal('QString', name='showStatusMessage') activeToolChanged = pyqtSignal(ActiveToolChangedInfo, name='activeToolChanged') polygonCollected = pyqtSignal(PolygonToolInfo, name='polygonCollected') polylineCollected = pyqtSignal(PolylineToolInfo, name='polylineCollected') vectorLocationSelected = pyqtSignal(list, viewerlayers.ViewerVectorLayer, name='vectorLocationSelected') locationSelected = pyqtSignal(QueryInfo, name='locationSelected') def __init__(self, parent): QAbstractScrollArea.__init__(self, parent) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) # tracking works awfully badly under X # turn off until we work out a workaround self.verticalScrollBar().setTracking(False) self.horizontalScrollBar().setTracking(False) self.layers = viewerlayers.LayerManager() self.paintPoint = QPoint() # normally 0,0 unless we are panning # when moving the scroll bars # events get fired that we wish to ignore self.suppressscrollevent = False # set the background color to black so window # is black when nothing loaded and when panning # new areas are initially black. self.setBackgroundColor(Qt.black) # to do with tools self.rubberBand = None self.panCursor = None self.panGrabCursor = None self.zoomInCursor = None self.zoomOutCursor = None self.queryCursor = None self.vectorQueryCursor = None self.polygonCursor = None self.activeTool = VIEWER_TOOL_NONE self.panOrigin = None self.toolPoints = None # for line and polygon tools - list of points self.toolPointsFinished = True # True if we finished collecting # with line and poly tools self.toolPen = QPen() # for drawing the toolPoints self.toolPen.setWidth(1) self.toolPen.setColor(Qt.yellow) self.toolPen.setDashPattern([5, 5, 5, 5]) # Define the scroll wheel behaviour self.mouseWheelZoom = True # do we follow extent when geolinking? self.geolinkFollowExtent = True # to we query all layers or only displayed? self.queryOnlyDisplayed = False def updateScrollBars(self): """ Update the scroll bars to accurately show where we are relative to the full extent """ fullextent = self.layers.getFullExtent() setbars = False self.suppressscrollevent = True if fullextent is not None: (fullleft, fulltop, fullright, fullbottom) = fullextent layer = self.layers.getTopLayer() if layer is not None: (left, top, right, bottom) = layer.coordmgr.getWorldExtent() (wldX, wldY) = layer.coordmgr.getWorldCenter() verticalBar = self.verticalScrollBar() horizontalBar = self.horizontalScrollBar() # always set range to 0 - 1000 and calculate # everything as fraction of that verticalBar.setRange(0, 1000) horizontalBar.setRange(0, 1000) # to pagestep which is also the slider size fullxsize = float(fullright - fullleft) if fullxsize == 0: fullxsize = 100 hpagestep = (float(right - left) / fullxsize) * 1000 horizontalBar.setPageStep(int(hpagestep)) fullysize = float(fulltop - fullbottom) if fullysize == 0: fullysize = 100 vpagestep = (float(top - bottom) / fullysize) * 1000 verticalBar.setPageStep(int(vpagestep)) # position of the slider relative to the center of the image hpos = (float(wldX - fullleft) / fullxsize) * 1000 horizontalBar.setSliderPosition(int(hpos)) vpos = (float(fulltop - wldY) / fullysize) * 1000 verticalBar.setSliderPosition(int(vpos)) setbars = True if not setbars: # something went wrong - disable self.horizontalScrollBar().setRange(0, 0) self.verticalScrollBar().setRange(0, 0) self.suppressscrollevent = False def addRasterLayer(self, gdalDataset, stretch, lut=None, ignoreProjectionMismatch=False, quiet=False): """ Add the given dataset to the stack of images being displayed as a raster layer """ size = self.viewport().size() self.layers.addRasterLayer(gdalDataset, size.width(), size.height(), stretch, lut, ignoreProjectionMismatch, quiet) # get rid off tool points self.toolPoints = None self.toolPointsFinished = True self.viewport().update() self.updateScrollBars() self.layerAdded.emit(self) def addVectorLayer(self, ogrDataSource, ogrLayer, color=None, resultSet=False, origSQL=None, quiet=False): """ Add the vector given by the ogrDataSource and its dependent ogrLayer to the stack of images. """ size = self.viewport().size() if color is None: color = viewerlayers.DEFAULT_VECTOR_COLOR self.layers.addVectorLayer(ogrDataSource, ogrLayer, size.width(), size.height(), color, resultSet, origSQL, quiet) self.viewport().update() self.updateScrollBars() self.layerAdded.emit(self) def addVectorFeatureLayer(self, ogrDataSource, ogrLayer, ogrFeature, color=None, quiet=None): """ Just a single feature vector """ size = self.viewport().size() if color is None: color = viewerlayers.DEFAULT_VECTOR_COLOR self.layers.addVectorFeatureLayer(ogrDataSource, ogrLayer, ogrFeature, size.width(), size.height(), color, quiet) self.viewport().update() self.updateScrollBars() self.layerAdded.emit(self) def addLayersFromJSONFile(self, fileobj, nlayers): """ Get the layer manager to read all the layer descriptions from fileobj and load these layers into this widget. """ size = self.viewport().size() self.layers.fromFile(fileobj, nlayers, size.width(), size.height()) self.viewport().update() self.updateScrollBars() self.layerAdded.emit(self) def removeLayer(self): """ Removes the top later """ self.layers.removeTopLayer() # get rid off tool points self.toolPoints = None self.toolPointsFinished = True self.viewport().update() self.updateScrollBars() # query point functions def setQueryPoint(self, senderid, easting, northing, color, size=None, cursor=None): """ Sets/Updates query point keyed on the id() of the sender """ self.layers.queryPointLayer.setQueryPoint(senderid, easting, northing, color, size, cursor) self.layers.queryPointLayer.getImage() self.viewport().update() def removeQueryPoint(self, senderid): """ Removes a query point. keyed on the id() of the sender """ self.layers.queryPointLayer.removeQueryPoint(senderid) self.layers.queryPointLayer.getImage() self.viewport().update() def highlightValues(self, color, selectionArray=None): """ Applies a QColor to the LUT where selectionArray == True to the top layer and redraws. Pass None to reset """ layer = self.layers.getTopRasterLayer() if layer is not None: if len(layer.stretch.bands) != 1: msg = 'can only highlight values on single band images' raise viewererrors.InvalidDataset(msg) layer.highlightRows(color, selectionArray) # force repaint self.viewport().update() def setColorTableLookup(self, lookupArray=None, colName=None, surrogateLUT=None, surrogateName=None): """ Uses the supplied lookupArray to look up image data before indexing into color table in the top layer and redraws. Pass None to reset. """ layer = self.layers.getTopRasterLayer() if layer is not None: if len(layer.stretch.bands) != 1: msg = 'can only highlight values on single band images' raise viewererrors.InvalidDataset(msg) layer.setColorTableLookup(lookupArray, colName, surrogateLUT, surrogateName) # force repaint self.viewport().update() def zoomNativeResolution(self): """ Sets the zoom to native resolution wherever the current viewport is centered """ self.layers.zoomNativeResolution() # force repaint self.viewport().update() self.updateScrollBars() # geolink self.emitGeolinkMoved() def zoomFullExtent(self): """ Resets the zoom to full extent - should be the same as when file was opened. """ self.layers.zoomFullExtent() # force repaint self.viewport().update() self.updateScrollBars() # geolink self.emitGeolinkMoved() def setActiveTool(self, tool, senderid): """ Set active tool (one of VIEWER_TOOL_*). pass VIEWER_TOOL_NONE to disable pass the id() of the calling object. This is passed around in the activeToolChanged signal so GUI elements can recognise who asked for the change """ # if the tool was line or polygon # now is the time to remove the outline from the widget if (self.activeTool == VIEWER_TOOL_POLYGON or self.activeTool == VIEWER_TOOL_POLYLINE): self.toolPoints = None self.toolPointsFinished = True # force repaint self.viewport().update() self.activeTool = tool if tool == VIEWER_TOOL_ZOOMIN: if self.zoomInCursor is None: # create if needed. self.zoomInCursor = QCursor( QPixmap([ "16 16 3 1", ". c None", "a c #000000", "# c #ffffff", ".....#####......", "...##aaaaa##....", "..#.a.....a.#...", ".#.a...a...a.#..", ".#a....a....a#..", "#a.....a.....a#.", "#a.....a.....a#.", "#a.aaaa#aaaa.a#.", "#a.....a.....a#.", "#a.....a.....a#.", ".#a....a....a#..", ".#.a...a...aaa#.", "..#.a.....a#aaa#", "...##aaaaa###aa#", ".....#####...###", "..............#." ])) self.viewport().setCursor(self.zoomInCursor) elif tool == VIEWER_TOOL_ZOOMOUT: if self.zoomOutCursor is None: # create if needed self.zoomOutCursor = QCursor( QPixmap([ "16 16 4 1", "b c None", ". c None", "a c #000000", "# c #ffffff", ".....#####......", "...##aaaaa##....", "..#.a.....a.#...", ".#.a.......a.#..", ".#a.........a#..", "#a...........a#.", "#a...........a#.", "#a.aaaa#aaaa.a#.", "#a...........a#.", "#a...........a#.", ".#a.........a#..", ".#.a.......aaa#.", "..#.a.....a#aaa#", "...##aaaaa###aa#", ".....#####...###", "..............#." ])) self.viewport().setCursor(self.zoomOutCursor) elif tool == VIEWER_TOOL_PAN: if self.panCursor is None: # both these used for pan operations self.panCursor = QCursor(Qt.OpenHandCursor) self.panGrabCursor = QCursor(Qt.ClosedHandCursor) self.viewport().setCursor(self.panCursor) elif tool == VIEWER_TOOL_QUERY: if self.queryCursor is None: self.queryCursor = QCursor(Qt.CrossCursor) self.viewport().setCursor(self.queryCursor) elif tool == VIEWER_TOOL_VECTORQUERY: if self.vectorQueryCursor is None: self.vectorQueryCursor = QCursor( QPixmap([ "16 16 3 1", "# c None", "a c #000000", ". c #ffffff", "######aaaa######", "######a..a######", "######a..a######", "######a..a######", "######a..a######", "######aaaa######", "aaaaa######aaaaa", "a...a######a...a", "a...a######a...a", "aaaaa######aaaaa", "######aaaa######", "######a..a###a.a", "######a..a###aaa", "######a..a###a.a", "######a..a###a.a", "######aaaa###aaa" ])) self.viewport().setCursor(self.vectorQueryCursor) elif tool == VIEWER_TOOL_POLYGON or tool == VIEWER_TOOL_POLYLINE: if self.polygonCursor is None: self.polygonCursor = QCursor( QPixmap([ "16 16 3 1", " c None", ". c #000000", "+ c #FFFFFF", " ", " +.+ ", " ++.++ ", " +.....+ ", " +. .+ ", " +. . .+ ", " +. . .+ ", " ++. . .++", " ... ...+... ...", " ++. . .++", " +. . .+ ", " +. . .+ ", " ++. .+ ", " ++.....+ ", " ++.++ ", " +.+ " ])) self.viewport().setCursor(self.polygonCursor) msg = ('Left click adds a point, middle to remove last,' + ' right click to end') self.showStatusMessage.emit(msg) elif tool == VIEWER_TOOL_NONE: # change back self.viewport().setCursor(Qt.ArrowCursor) obj = ActiveToolChangedInfo(self.activeTool, senderid) self.activeToolChanged.emit(obj) def setNewStretch(self, newstretch, layer, local=False): """ Change the stretch being applied to the current data """ layer.setNewStretch(newstretch, local) self.viewport().update() def timeseriesBackward(self): """ Assume images are a stacked timeseries oldest to newest. Turn on the previous one to the current topmost displayed """ self.layers.timeseriesBackward() self.viewport().update() def timeseriesForward(self): """ Assume images are a stacked timeseries oldest to newest. Turn off the current topmost displayed """ self.layers.timeseriesForward() self.viewport().update() def setMouseScrollWheelAction(self, scrollZoom): "Set the action for a mouse wheen event (scroll/zoom)" self.mouseWheelZoom = scrollZoom def setBackgroundColor(self, color): "Sets the background color for the widget" widget = self.viewport() palette = widget.palette() palette.setColor(widget.backgroundRole(), color) widget.setPalette(palette) def setGeolinkFollowExtentAction(self, followExtent): "Set whether we are following geolink extent of just center" self.geolinkFollowExtent = followExtent def setQueryOnlyDisplayed(self, queryOnlyDisplayed): """ set whether we are only querying displayed layers (True) or all (False) """ self.queryOnlyDisplayed = queryOnlyDisplayed def flicker(self): """ Call to change the flicker state (ie draw the top raster image or not). """ state = False layer = self.layers.getTopLayer() if layer is not None: state = not layer.displayed self.layers.setDisplayedState(layer, state) self.viewport().update() return state def scrollContentsBy(self, dx, dy): """ Handle the user moving the scroll bars """ if not self.suppressscrollevent: layer = self.layers.getTopLayer() if layer is not None: (left, top, right, bottom) = layer.coordmgr.getWorldExtent() hpagestep = float(self.horizontalScrollBar().pageStep()) xamount = -(float(dx) / hpagestep) * (right - left) vpagestep = float(self.verticalScrollBar().pageStep()) yamount = (float(dy) / vpagestep) * (top - bottom) wldX, wldY = layer.coordmgr.getWorldCenter() layer.coordmgr.setWorldCenter(wldX + xamount, wldY + yamount) # not sure why we need this but get black strips # around otherwise layer.coordmgr.recalcBottomRight() self.layers.makeLayersConsistent(layer) self.layers.updateImages() self.viewport().update() self.updateScrollBars() # geolink self.emitGeolinkMoved() def wheelEvent(self, event): """ User has used mouse wheel to zoom in/out or pan depending on defined preference """ layer = self.layers.getTopRasterLayer() if layer is not None: delta = event.angleDelta().y() # Shift scrolling will move you forward and backwards through the time series if QApplication.keyboardModifiers() == Qt.ShiftModifier: if delta > 0: self.timeseriesBackward() elif delta < 0: self.timeseriesForward() elif self.mouseWheelZoom: (wldX, wldY) = layer.coordmgr.getWorldCenter() impixperwinpix = layer.coordmgr.imgPixPerWinPix if delta > 0: impixperwinpix *= 1.0 - VIEWER_ZOOM_WHEEL_FRACTION elif delta < 0: impixperwinpix *= 1.0 + VIEWER_ZOOM_WHEEL_FRACTION layer.coordmgr.setZoomFactor(impixperwinpix) layer.coordmgr.setWorldCenter(wldX, wldY) # not sure why we need this but get black strips # around otherwise layer.coordmgr.recalcBottomRight() self.layers.makeLayersConsistent(layer) self.layers.updateImages() self.updateScrollBars() self.viewport().update() else: dx = event.angleDelta().x() dy = delta self.scrollContentsBy(dx, dy) # geolink self.emitGeolinkMoved() def resizeEvent(self, event): """ Window has been resized - get new data """ size = event.size() self.layers.setDisplaySize(size.width(), size.height()) self.updateScrollBars() def paintEvent(self, event): """ Viewport needs to be redrawn. Assume that each layer's image is current (as created by getImage()) we can just draw it with QPainter """ paint = QPainter(self.viewport()) for layer in self.layers.layers: if layer.displayed: paint.drawImage(self.paintPoint, layer.image) # draw any query points on top of image paint.drawImage(self.paintPoint, self.layers.queryPointLayer.image) # now any tool points if self.toolPoints is not None: path = QPainterPath() firstpt = self.toolPoints[0] path.moveTo(firstpt.x(), firstpt.y()) for pt in self.toolPoints[1:]: path.lineTo(pt.x(), pt.y()) paint.setPen(self.toolPen) paint.drawPath(path) paint.end() def mousePressEvent(self, event): """ Mouse has been clicked down if we are in zoom/pan mode we need to start doing stuff here """ QAbstractScrollArea.mousePressEvent(self, event) pos = event.pos() if (self.activeTool == VIEWER_TOOL_ZOOMIN or self.activeTool == VIEWER_TOOL_ZOOMOUT): if self.rubberBand is None: self.rubberBand = QRubberBand(QRubberBand.Rectangle, self) self.rubberBand.setGeometry(QRect(pos, QSize())) self.rubberBand.show() self.rubberBand.origin = pos elif self.activeTool == VIEWER_TOOL_PAN: # remember pos self.panOrigin = pos # change cursor self.viewport().setCursor(self.panGrabCursor) elif self.activeTool == VIEWER_TOOL_QUERY: modifiers = event.modifiers() (dspX, dspY) = (pos.x(), pos.y()) self.newQueryPoint(dspX=dspX, dspY=dspY, modifiers=modifiers) elif self.activeTool == VIEWER_TOOL_VECTORQUERY: modifiers = event.modifiers() (dspX, dspY) = (pos.x(), pos.y()) self.newVectorQueryPoint(dspX, dspY, modifiers=modifiers) elif self.activeTool == VIEWER_TOOL_POLYGON: button = event.button() if button == Qt.LeftButton: # adding points if self.toolPoints is None or self.toolPointsFinished: # first point - starts and ends at same pos self.toolPoints = [pos, pos] self.toolPointsFinished = False else: # last point same as first - insert before last self.toolPoints.insert(-1, pos) elif button == Qt.MiddleButton and self.toolPoints is not None: # delete last point if len(self.toolPoints) > 2: del self.toolPoints[-2] elif button == Qt.RightButton and self.toolPoints is not None: # finished # create object for signal layer = self.layers.getTopRasterLayer() modifiers = event.modifiers() obj = PolygonToolInfo(self.toolPoints, layer, modifiers) self.polygonCollected.emit(obj) self.toolPointsFinished = True # done, but still display # redraw so paint() gets called self.viewport().update() elif self.activeTool == VIEWER_TOOL_POLYLINE: button = event.button() if button == Qt.LeftButton: # adding points if self.toolPoints is None or self.toolPointsFinished: # first point self.toolPoints = [pos] self.toolPointsFinished = False else: # add to list self.toolPoints.append(pos) elif button == Qt.MiddleButton and self.toolPoints is not None: # delete last point if len(self.toolPoints) > 1: self.toolPoints.pop() elif button == Qt.RightButton and self.toolPoints is not None: # finished # create object for signal if self.queryOnlyDisplayed: layer = self.layers.getTopDisplayedRasterLayer() else: layer = self.layers.getTopRasterLayer() modifiers = event.modifiers() obj = PolylineToolInfo(self.toolPoints, layer, modifiers) self.polylineCollected.emit(obj) self.toolPointsFinished = True # done, but still display # redraw so paint() gets called self.viewport().update() def mouseReleaseEvent(self, event): """ Mouse has been released, if we are in zoom/pan mode we do stuff here. """ QAbstractScrollArea.mouseReleaseEvent(self, event) if self.rubberBand is not None and self.rubberBand.isVisible(): # get the information about the rect they have drawn # note this is on self, rather than viewport() selection = self.rubberBand.geometry() geom = self.viewport().geometry() selectionsize = float(selection.width() * selection.height()) geomsize = float(geom.width() * geom.height()) self.rubberBand.hide() layer = self.layers.getTopRasterLayer() if layer is not None: if selectionsize < MIN_SELECTION_SIZE_PX: # this is practically a '0' size selection on a 4K screen and # an improbably small selection on an HD screen so assume user # has just clicked the image and set fraction to 0.5 fraction = 0.5 else: fraction = numpy.sqrt(selectionsize / geomsize) if self.activeTool == VIEWER_TOOL_ZOOMIN: if selectionsize < MIN_SELECTION_SIZE_PX: # user 'just clicked' (see if statement above). # NOTE: this fixes issues with 0 or negative dimensions # inside else: below that used ot hard-crash tuiview wldX, wldY = layer.coordmgr.display2world( selection.left(), selection.top()) layer.coordmgr.setZoomFactor( layer.coordmgr.imgPixPerWinPix * fraction) layer.coordmgr.setWorldCenter(wldX, wldY) # not sure why we need this but get black strips # around otherwise layer.coordmgr.recalcBottomRight() else: # I don't think anything needs to be added here dspTop = selection.top() dspLeft = selection.left() dspBottom = selection.bottom() dspRight = selection.right() (rastLeft, rastTop) = layer.coordmgr.display2pixel( dspLeft, dspTop) (rastRight, rastBottom) = layer.coordmgr.display2pixel( dspRight, dspBottom) #print layer.coordmgr layer.coordmgr.setTopLeftPixel(rastLeft, rastTop) layer.coordmgr.calcZoomFactor(rastRight, rastBottom) # not sure why we need this but get black strips # around otherwise layer.coordmgr.recalcBottomRight() #print layer.coordmgr elif self.activeTool == VIEWER_TOOL_ZOOMOUT: # the smaller the area the larger the zoom center = selection.center() wldX, wldY = layer.coordmgr.display2world( center.x(), center.y()) layer.coordmgr.setZoomFactor( layer.coordmgr.imgPixPerWinPix / fraction) layer.coordmgr.setWorldCenter(wldX, wldY) # not sure why we need this but get black strips # around otherwise layer.coordmgr.recalcBottomRight() # redraw self.layers.makeLayersConsistent(layer) self.layers.updateImages() self.viewport().update() self.updateScrollBars() # geolink self.emitGeolinkMoved() elif self.activeTool == VIEWER_TOOL_PAN: # change cursor back self.viewport().setCursor(self.panCursor) layer = self.layers.getTopRasterLayer() if layer is not None: # stop panning and move viewport dspXmove = -self.paintPoint.x() dspYmove = -self.paintPoint.y() (pixNewX, pixNewY) = layer.coordmgr.display2pixel(dspXmove, dspYmove) #print 'panning' #print layer.coordmgr layer.coordmgr.setTopLeftPixel(pixNewX, pixNewY) layer.coordmgr.recalcBottomRight() #print layer.coordmgr # reset self.paintPoint.setX(0) self.paintPoint.setY(0) # redraw self.layers.makeLayersConsistent(layer) self.layers.updateImages() self.viewport().update() self.updateScrollBars() # geolink self.emitGeolinkMoved() def mouseMoveEvent(self, event): """ Mouse has been moved while dragging. If in zoom/pan mode we need to do something here. """ QAbstractScrollArea.mouseMoveEvent(self, event) if self.rubberBand is not None and self.rubberBand.isVisible(): # must be doing zoom in/out. extend rect rect = QRect(self.rubberBand.origin, event.pos()).normalized() self.rubberBand.setGeometry(rect) elif self.activeTool == VIEWER_TOOL_PAN: # panning. Work out the offset from where we # starting panning and draw the current image # at an offset pos = event.pos() xamount = pos.x() - self.panOrigin.x() yamount = pos.y() - self.panOrigin.y() self.paintPoint.setX(xamount) self.paintPoint.setY(yamount) # force repaint - self.paintPoint used by paintEvent() self.viewport().update() self.updateScrollBars() # query point routines def newQueryPoint(self, easting=None, northing=None, dspY=None, dspX=None, column=None, row=None, modifiers=None): """ This viewer has recorded a new query point. Or user has entered new coords in querywindow. Calls updateQueryPoint and emits the geolinkQueryPoint signal pass either [easting and northing] or [dspX,dspY] or [column, row] """ if self.queryOnlyDisplayed: layer = self.layers.getTopDisplayedRasterLayer() else: layer = self.layers.getTopRasterLayer() if layer is None: return if ((easting is None or northing is None) and (dspX is None or dspY is None) and (column is None or row is None)): msg = ("must provide one of [easting,northing] or [dspX,dspY] " + "or [column, row]") raise ValueError(msg) if dspX is not None and dspY is not None: (column, row) = layer.coordmgr.display2pixel(dspX, dspY) (easting, northing) = layer.coordmgr.pixel2world(column, row) elif easting is not None and northing is not None: (column, row) = layer.coordmgr.world2pixel(easting, northing) elif column is not None and row is not None: (easting, northing) = layer.coordmgr.pixel2world(column, row) # update the point self.updateQueryPoint(easting, northing, column, row, modifiers) # emit the geolinked query point signal obj = GeolinkInfo(id(self), easting, northing) self.geolinkQueryPoint.emit(obj) def newVectorQueryPoint(self, dspX, dspY, modifiers=None): """ New vector query point. Does the spatial query and emits the vectorLocationSelected signal with the results """ if self.queryOnlyDisplayed: layer = self.layers.getTopDisplayedVectorLayer() else: layer = self.layers.getTopVectorLayer() if layer is None: return (easting, northing) = layer.coordmgr.display2world(dspX, dspY) tolerance = layer.coordmgr.metersperpix * 3 # maybe should be a pref? # show hourglass while query running oldCursor = self.cursor() self.setCursor(Qt.WaitCursor) results = layer.getAttributesAtPoint(easting, northing, tolerance) self.setCursor(oldCursor) self.vectorLocationSelected.emit(results, layer) def updateQueryPoint(self, easting, northing, column, row, modifiers): """ Map has been clicked, get the value and emit a locationSelected signal. Called by newQueryPoint or when a geolinkQueryPoint signal has been received. """ # read the data out of the dataset if self.queryOnlyDisplayed: layer = self.layers.getTopDisplayedRasterLayer() else: layer = self.layers.getTopRasterLayer() if (layer is not None and column >= 0 and column < layer.gdalDataset.RasterXSize and row >= 0 and row < layer.gdalDataset.RasterYSize): data = layer.gdalDataset.ReadAsArray(int(column), int(row), 1, 1) if data is not None: # we just want the single 'drill down' of data as a 1d array data = data[..., 0, 0] # if single band GDAL gives us a single value - # convert back to array # to make life easier if data.size == 1: data = numpy.array([data]) qi = QueryInfo(easting, northing, column, row, data, layer, modifiers) # emit the signal - handled by the QueryDockWidget self.locationSelected.emit(qi) def doGeolinkQueryPoint(self, easting, northing): """ Call this when the widget query point has been moved in another viewer and should be updated in this one if the query tool is active. """ if self.activeTool == VIEWER_TOOL_QUERY: if self.queryOnlyDisplayed: layer = self.layers.getTopDisplayedRasterLayer() else: layer = self.layers.getTopRasterLayer() if layer is not None: (col, row) = layer.coordmgr.world2pixel(easting, northing) self.updateQueryPoint(easting, northing, col, row, None) # geolinking routines def doGeolinkMove(self, easting, northing, metresperwinpix): """ Call this when widget needs to be moved because of geolinking event. """ layer = self.layers.getTopRasterLayer() if layer is not None: if self.geolinkFollowExtent and metresperwinpix != 0: imgpixperwinpix = metresperwinpix / layer.coordmgr.geotransform[ 1] layer.coordmgr.setZoomFactor(imgpixperwinpix) layer.coordmgr.setWorldCenter(easting, northing) self.layers.makeLayersConsistent(layer) self.layers.updateImages() self.updateScrollBars() self.viewport().update() def getGeolinkInfo(self): """ Called by emitGeolinkMoved and anything else that needs the current GeolinkInfo """ info = None # get the coords of the current centre layer = self.layers.getTopRasterLayer() if layer is not None: easting, northing = layer.coordmgr.getWorldCenter() metresperwinpix = (layer.coordmgr.imgPixPerWinPix * layer.coordmgr.geotransform[1]) info = GeolinkInfo(id(self), easting, northing, metresperwinpix) return info def emitGeolinkMoved(self): """ Call this on each zoom/pan to emit the appropriate signal. """ info = self.getGeolinkInfo() if info is not None: # emit the signal self.geolinkMove.emit(info)
class RubberbandEnhancedLabel(QLabel): def __init__(self, parent=None): self._parent_class = _parent_class QLabel.__init__(self, parent) self.selection = QRubberBand(QRubberBand.Rectangle, self) def mousePressEvent(self, event): ''' Mouse is pressed. If selection is visible either set dragging mode (if close to border) or hide selection. If selection is not visible make it visible and start at this point. ''' # if event.button() == Qt.LeftButton: position = QPoint(event.pos()) if self.selection.isVisible(): # visible selection if (self.upper_left - position).manhattanLength() < 20: # close to upper left corner, drag it self.mode = "drag_upper_left" elif (self.lower_right - position).manhattanLength() < 20: # close to lower right corner, drag it self.mode = "drag_lower_right" else: # clicked somewhere else, hide selection self.selection.hide() else: # no visible selection, start new selection self.upper_left = position self.lower_right = position self.mode = "drag_lower_right" self.selection.show() def mouseMoveEvent(self, event): ''' Mouse moved. If selection is visible, drag it according to drag mode. ''' if self.selection.isVisible(): # visible selection if self.mode == "drag_lower_right": self.lower_right = QPoint(event.pos()) elif self.mode == "drag_upper_left": self.upper_left = QPoint(event.pos()) # update geometry self.selection.setGeometry(QRect(self.upper_left, self.lower_right).normalized()) def mouseReleaseEvent(self, event): if self.selection.isVisible(): currentQRect = self.selection.geometry() cropQPixmap = self.pixmap().copy(currentQRect) cropQPixmap.save('output.png') image = QImage("output.png") if image.isNull(): QMessageBox.information(self.centralwidget, "Image Viewer", "Cannot load %s." % self.fileName) return pm = QPixmap.fromImage(image) h = pm.height() w = pm.width() if (h > w): self._parent_class.originalImageLabel.setPixmap(pm.scaledToHeight(400)) else: self._parent_class.originalImageLabel.setPixmap(pm.scaledToWidth(400)) self.selection.hide()
class GUI(QMainWindow): ''' Main GUI class ''' def __init__(self): ''' Initializes most basic object and sets default values for parameters ''' super().__init__() self.initUI() #path to pdf self.path = None #masks for flat elimination algorithm self.conditionLower = np.array([255, 255, 255]) self.conditionUpper = np.array([100, 100, 100]) #batch size self.batchSize = 5 #pages to work on -> unfinished so set to always work on full file self.pages = [0] #color to use when replacing pixels self.color = np.array([255, 255, 255]) #default output name self.outName = "temporary" #not existing bounding box self.boundingBox = [0] self.DEBUG = True def initUI(self): ''' UI initialization ''' #set size and center self.setFixedSize(370, 350) self.center() #create all butons for menu and assign them functions self.btn1 = QPushButton('Load PDF', self) self.btn1.clicked.connect(self.getFilePath) self.btn1.setToolTip('Choose pdf file to work with') self.btn1.resize(100, 50) self.btn1.move(25, 25) self.btn2 = QPushButton('Set Config', self) self.btn2.clicked.connect(self.initConfigForm) self.btn2.setToolTip('Configure settings') self.btn2.resize(100, 50) self.btn2.move(25, 80) self.btn3 = QPushButton('Create\nBounding Box', self) self.btn3.clicked.connect(self.createBoundingBox) self.btn3.setToolTip('Create box limiting area of change') self.btn3.resize(100, 50) self.btn3.move(135, 25) self.btn4 = QPushButton('Generate Average', self) self.btn4.clicked.connect(self.getAverageEstimateWrapper) self.btn4.setToolTip('Estimate watermark by averaging over pages') self.btn4.resize(100, 50) self.btn4.move(135, 80) self.btn5 = QPushButton('Flat Elimination', self) self.btn5.clicked.connect(self.convertFlatWrapper) self.btn5.setToolTip('Replace all RGB values between set values and replace them with color') self.btn5.resize(100, 50) self.btn5.move(245, 25) self.btn6 = QPushButton('Average\nElimination', self) self.btn6.clicked.connect(self.convertAverageWrapper) self.btn6.setToolTip('Replace all RGB values that are similar enough to averaged sample') self.btn6.resize(100, 50) self.btn6.move(245, 80) #hide certain buttons untill a pdf is choosen self.btn3.hide() self.btn4.hide() self.btn5.hide() self.btn6.hide() #set name, logo, etc. for progress bar self.bar = QWidget() self.bar.setWindowIcon(QIcon('graphics//logo.png')) self.bar.setWindowTitle('Progress bar') self.progress = QProgressBar(self.bar) self.bar.move(QDesktopWidget().availableGeometry().center() - QPoint(150, 15)) self.progress.setGeometry(0, 0, 300, 30) #slector for bounding box self.selector = QWidget() self.pic = QLabel(self.selector) #assign events to the correct window self.selector.mousePressEvent = lambda event : self.MPE(event) self.selector.mouseMoveEvent = lambda event : self.MME(event) self.selector.mouseReleaseEvent = lambda event : self.MRE(event) #set title and logo self.selector.setWindowTitle('Select Bounding Box') self.selector.setWindowIcon(QIcon('graphics//logo.png')) #create rubber band for selector self.selection = QRubberBand(QRubberBand.Rectangle, self.pic) #set project logo in the menu logo = QLabel(self) logo.resize(200, 200) logo.setPixmap(QPixmap("graphics//logo.png")) logo.move(85, 130) #set title and logo for main windows and finish initialization self.setWindowIcon(QIcon('graphics//logo.png')) self.setWindowTitle('PDF Purifico') self.show() return def pageForm(self): ''' Unfinished form for retrieving arbitrary start and finish pages ''' #setup widget self.pageForm = QWidget() self.pageForm.resize(600, 100) #set label label = QLabel(self.pageForm) label.setText("Set first and last page") label.move(15, 15) #set input fields self.firstP = QLineEdit(self.pageForm) self.firstP.move(180, 15) self.lastP = QLineEdit(self.pageForm) self.lastP.move(330, 15) #create send button self.formPageButton = QPushButton('Set pages', self.pageForm) self.formPageButton.clicked.connect(self.setPages) self.formPageButton.move(480, 15) self.pageForm.show() return def setPages(self): ''' validate input and save it ''' firstP = int(self.firstP.text()) lastP = int(self.lastP.text()) #validate if (firstP > 0) and (lastP > 0) and (lastP >= firstP): self.pages = [firstP, lastP] self.waitForPages = False #hide form once done self.pageForm.hide() return def initConfigForm(self): ''' Create form forconfiguration changes ''' #create base widget self.form = QWidget() self.form.resize(500, 350) #Creates labels and input fields for all the data label = QLabel(self.form) label.setText("R value from RGB (min - max)") label.move(15, 15) label = QLabel(self.form) label.setText("G value from RGB (min - max)") label.move(15, 45) label = QLabel(self.form) label.setText("B value from RGB (min - max)") label.move(15, 75) self.minR = QLineEdit(self.form) self.minR.move(180, 15) self.maxR = QLineEdit(self.form) self.maxR.move(330, 15) self.minG = QLineEdit(self.form) self.minG.move(180, 45) self.maxG = QLineEdit(self.form) self.maxG.move(330, 45) self.minB = QLineEdit(self.form) self.minB.move(180, 75) self.maxB = QLineEdit(self.form) self.maxB.move(330, 75) label = QLabel(self.form) label.setText("R value from RGB to set") label.move(15, 105) label = QLabel(self.form) label.setText("G value from RGB to set") label.move(15, 135) label = QLabel(self.form) label.setText("B value from RGB to set") label.move(15, 165) self.colorR = QLineEdit(self.form) self.colorR.move(180, 105) self.colorG = QLineEdit(self.form) self.colorG.move(180, 135) self.colorB = QLineEdit(self.form) self.colorB.move(180, 165) label = QLabel(self.form) label.setText("Size of batches to read to RAM") label.move(15, 195) self.batchS = QLineEdit(self.form) self.batchS.move(180, 195) label = QLabel(self.form) label.setText("Name for new file") label.move(15, 225) self.name = QLineEdit(self.form) self.name.move(180, 225) #button to send self.formButton = QPushButton('Save Config', self.form) self.formButton.clicked.connect(self.setConfig) self.formButton.move(330, 135) self.formButton.resize(135, 50) #set name and logo self.form.setWindowTitle("Config") self.form.setWindowIcon(QIcon('graphics//logo.png')) self.form.show() return def setConfig(self): ''' validate and set data from config form ''' try: #retrieve all the data and cast to correct type minR = int(self.minR.text()) minG = int(self.minG.text()) minB = int(self.minB.text()) maxR = int(self.maxR.text()) maxG = int(self.maxG.text()) maxB = int(self.maxB.text()) colorR = int(self.colorR.text()) colorG = int(self.colorG.text()) colorB = int(self.colorB.text()) batchS = int(self.batchS.text()) self.outName = self.name.text() #validate and save if (0 <= minR <= 255) and (0 <= minG <= 255) and (0 <= minB <= 255): self.conditionUpper = np.array([minR, minG, minB]) if (0 <= maxR <= 255) and (0 <= maxG <= 255) and (0 <= maxB <= 255): self.conditionUpper = np.array([maxR, maxG, maxB]) if (0 <= colorR <= 255) and (0 <= colorG <= 255) and (0 <= colorB <= 255): self.conditionUpper = np.array([colorR, colorG, colorB]) if (batchS > 0): self.batchSize = batchS self.form.hide() except: #in case of error QMessageBox.question(self, 'Error', "Something broke", QMessageBox.Yes) self.form.hide() return def onCountChanged(self, value): ''' For updating progress bar ''' self.progress.setValue(value) return def getFilePath(self): ''' Get path to pdf file ''' w = QWidget() filename = QFileDialog.getOpenFileName(w, 'Select PDF file') self.path = filename[0] #since we got a pdf now we can enable the other buttons self.btn3.show() self.btn4.show() self.btn5.show() self.btn6.show() return def convertFlatWrapper(self): ''' Wrapper for convertFlat function ''' #set pages correctly if (len(self.pages) == 2): pagesToClean = self.pages[1] - self.pages[0] + 1 pageOffset = self.pages[0] - 1 elif (len(self.pages) == 1): pagesToClean = self.pages[0] pageOffset = 0 else: QMessageBox.about(self,"Error", "Pages set incorrectly") return #prepare update bar send data to thread and start it self.bar.show() self.calc = External() self.calc.setFunction(convertFlat, (self.path, self.conditionLower, self.conditionUpper, self.batchSize, self.outName, pagesToClean, pageOffset, self.color, self.boundingBox)) self.calc.countChanged.connect(self.onCountChanged) self.calc.start() return def getAverageEstimateWrapper(self): ''' Wrapper for getAverageEstimate ''' #set pages correctly if (len(self.pages) == 2): pagesToClean = self.pages[1] - self.pages[0] + 1 pageOffset = self.pages[0] - 1 elif (len(self.pages) == 1): pagesToClean = self.pages[0] pageOffset = 0 else: QMessageBox.about(self,"Error", "Pages set incorrectly") return #prepare update bar send data to thread and start it self.bar.show() self.calc = External() self.calc.setFunction(getAverageEstimate, (self.path, self.batchSize, self.outName, pagesToClean, pageOffset)) self.calc.countChanged.connect(self.onCountChanged) self.calc.start() return def convertAverageWrapper(self): ''' Wrapper for converAverage ''' if (len(self.pages) == 2): pagesToClean = self.pages[1] - self.pages[0] + 1 pageOffset = self.pages[0] - 1 elif (len(self.pages) == 1): pagesToClean = self.pages[0] pageOffset = 0 else: QMessageBox.about(self,"Error", "Pages set incorrectly") #slect averaged file touse as filter for pdf w = QWidget() filename = QFileDialog.getOpenFileName(w, 'Select averaged file to filter pdf') #prepare update bar send data to thread and start it self.bar.show() self.calc = External() self.calc.setFunction(convertAverage, (self.path, filename[0], self.batchSize, self.outName, pagesToClean, pageOffset, self.color, self.boundingBox)) self.calc.countChanged.connect(self.onCountChanged) self.calc.start() return def center(self): ''' method for centering ''' qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) return def closeEvent(self, event): ''' Confirmation when closing software ''' reply = QMessageBox.question(self, 'Message', "Are you sure?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: event.accept() else: event.ignore() return def MPE(self, event): ''' Mouse is pressed. If selection is visible either set dragging mode (if close to border) or hide selection. If selection is not visible make it visible and start at this point. ''' if event.button() == Qt.LeftButton: position = QPoint(event.pos()) if (self.DEBUG): print("Start coords:", position.x(), position.y()) #set coords for later self.start_x = position.x() self.start_y = position.y() if self.selection.isVisible(): # visible selection if (self.upper_left - position).manhattanLength() < 20: # close to upper left corner, drag it self.mode = "drag_upper_left" elif (self.lower_right - position).manhattanLength() < 20: # close to lower right corner, drag it self.mode = "drag_lower_right" else: # clicked somewhere else, hide selection self.selection.hide() else: # no visible selection, start new selection self.upper_left = position self.lower_right = position self.mode = "drag_lower_right" self.selection.show() return def MME(self, event): ''' Mouse moved. If selection is visible, drag it according to drag mode. ''' if self.selection.isVisible(): # visible selection if self.mode is "drag_lower_right": self.lower_right = QPoint(event.pos()) elif self.mode is "drag_upper_left": self.upper_left = QPoint(event.pos()) # update geometry self.selection.setGeometry(QRect(self.upper_left, self.lower_right).normalized()) return def MRE(self, event): ''' Mouse is released. Hide selector, selection and save propertly transformed coords ''' if event.button() == Qt.LeftButton: position = QPoint(event.pos()) if (self.DEBUG): print("Stop coords:", position.x(), position.y()) #save final position self.stop_x = position.x() self.stop_y = position.y() if self.selection.isVisible(): self.selection.hide() self.selector.hide() im = convert_from_path(self.path, fmt='jpeg', first_page=1, last_page=1)[0] width, height = im.size if (self.DEBUG): orig = np.array(im) color = np.array([100, 100, 200]) pts = np.zeros((2,2)) #set coordinates for bounding box pts[0][0] = int(self.start_x / self.scaled_im_width * width) pts[0][1] = int(self.start_y / self.scaled_im_height * height) pts[1][0] = int(self.stop_x / self.scaled_im_width * width) pts[1][1] = int(self.stop_y / self.scaled_im_height * height) self.boundingBox = pts if(self.DEBUG): drawLines(orig, pts.astype(int), color, 3) im = Image.fromarray(orig) im.save('temp\\sample.jpeg') im.show() return def createBoundingBox(self): ''' Creates bounding box to be used in one of the enxt algorithms ''' im = convert_from_path(self.path, fmt='jpeg', first_page=1, last_page=1)[0] im.save("temp\\temp.jpg") #get original sizes width, height = im.size im.close() geo = QDesktopWidget().availableGeometry() #transform for convinience if (geo.height() < height): width *= (geo.height()/height) * 0.9 height = geo.height() * 0.9 #save for reversing later self.scaled_im_width = int(width) self.scaled_im_height = int(height) self.pic.setGeometry(0 , 0, width, height) self.selector.setFixedSize(width, height) #load picture self.pic.setPixmap(QPixmap("temp\\temp.jpg").scaledToHeight(height)) qr = self.selector.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.selector.move(qr.topLeft()) self.selector.show() return