class Convertor: def __init__(self, path, stitches_only = False): self.jef = jef.Pattern(path) self.stitches_only = stitches_only self.rect = QRect() def bounding_rect(self): if not self.rect.isNull(): return self.rect x, y = [], [] for coordinates in self.jef.coordinates: i = map(lambda (op, i, j): i, coordinates) j = map(lambda (op, i, j): j, coordinates) x.append(min(i)) x.append(max(i)) y.append(min(j)) y.append(max(j)) return QRect(min(x), -max(y), max(x) - min(x), max(y) - min(y)) def show(self, painter): painter.save() painter.translate(-self.bounding_rect().topLeft()) i = 0 for i in range(self.jef.threads): colour = QColor(*self.jef.colour_for_thread(i)) coordinates = self.jef.coordinates[i] if not self.stitches_only: pen = QPen(QColor(200, 200, 200)) painter.setPen(pen) for op, x, y in coordinates: painter.drawEllipse(x - 2, -y - 2, 4, 4) pen = QPen(colour) painter.setPen(pen) mx, my = 0, 0 for op, x, y in coordinates: if op == "move": mx, my = x, y elif op == "stitch": painter.drawLine(mx, -my, x, -y) mx, my = x, y i += 1 painter.restore()
class ImageAreaSelector (QtGui.QWidget): '''This widget provides means to visually crop a portion of an image by selecting it''' # pylint: disable=W0612 NAME = 'ImageAreaSelector' DESCRIPTION = 'A widget used to select part of an image' AUTHOR = 'Gabriele "Whisky" Visconti' WEBSITE = '' # pylint: enable=W0612 selection_changed = QtCore.pyqtSignal() def __init__(self, pixmap, parent=None): '''Constructor''' QtGui.QWidget.__init__(self, parent) self._pixmap = pixmap self._selection_rect = QRect() self._image_origin = QPoint() self._resize_start = None self._drag_start = None self._handle_size = QSize(-10, -10) self._painter = QtGui.QPainter() self._hl_color1 = QtGui.QPalette().color(QtGui.QPalette.Highlight) self._hl_color2 = QtGui.QPalette().color(QtGui.QPalette.Highlight) self._hl_color2.setAlpha(150) self._zoom = 1.0 self.adjust_minum_size() self.setBackgroundRole(QtGui.QPalette.Dark) self.setMouseTracking(True) self.setCursor(Qt.CrossCursor) # -------------------- [BEGIN] QT_OVERRIDE def mousePressEvent (self, event): '''Overrides QWidget's mousePressEvent. Handles starting a new selection, starting a drag operation''' # pylint: disable=C0103 mouse_pos = event.pos() / self._zoom sel_rect = self._selection_rect if not event.button() == Qt.LeftButton: return if (not sel_rect.isNull()) and sel_rect.contains(mouse_pos, True): handle_rect = QRect(sel_rect.bottomRight(), self._handle_size) if handle_rect.contains(mouse_pos): self._resize_start = mouse_pos else: self._drag_start = mouse_pos else: self._resize_start = mouse_pos sel_rect.setTopLeft (mouse_pos) self._selection_rect.setSize(QSize(0, 0)) def mouseMoveEvent (self, event): '''Overrides QWidget's mouseMoveEvent. Handles resizing and dragging operations on selection''' # pylint: disable=C0103 sel_rect = self._selection_rect if self._resize_start: resize_end = event.pos() / self._zoom sel_rect.setBottomRight(sel_rect.bottomRight() + (resize_end - self._resize_start)) self._resize_start = resize_end self.make_selection_square() self.update() elif self._drag_start is not None: drag_end = event.pos() / self._zoom sel_rect.translate(drag_end - self._drag_start) self._drag_start = drag_end self.update() # cursor shape: mouse_pos = event.pos() / self._zoom if (not sel_rect.isNull()) and sel_rect.contains(mouse_pos, True): handle_rect = QRect(sel_rect.bottomRight(), self._handle_size) if handle_rect.contains(mouse_pos): self.setCursor(Qt.SizeFDiagCursor) else: self.setCursor(Qt.OpenHandCursor) else: self.setCursor(Qt.CrossCursor) def mouseReleaseEvent (self, event): '''Overrides QWidget's mouseReleaseEvent. Handles ending a resizing or draggin operation on the selection''' # pylint: disable=C0103 self._selection_rect = self._selection_rect.normalized() self._resize_start = None self._drag_start = None self.update() if not self._selection_rect.isNull(): self.selection_changed.emit() def paintEvent(self, event): '''Overrides QWidtget's paintEvent.''' # pylint: disable=C0103 QtGui.QWidget.paintEvent(self, event) self._painter.begin(self) pixmap_dest_rect = QRect(self._image_origin * self._zoom, self._pixmap.size()*self._zoom) self._painter.drawPixmap(pixmap_dest_rect, self._pixmap) if not self._selection_rect.isNull(): # preparing the darkened frame: sel_rect = self._selection_rect.normalized() frame = QtGui.QPixmap(event.rect().size()) frame.fill(QtGui.QColor(0, 0, 0, 127)) frame_painter = QtGui.QPainter(frame) # erase the selected area from the frame: frame_painter.setCompositionMode( QtGui.QPainter.CompositionMode_DestinationIn) sel_rect_scaled = QRect(sel_rect.topLeft() * self._zoom, sel_rect.size() * self._zoom) frame_painter.fillRect(sel_rect_scaled, QtGui.QColor(0, 0, 0, 0)) # draw selection border : frame_painter.setCompositionMode( QtGui.QPainter.CompositionMode_SourceOver) frame_painter.setPen(self._hl_color1) frame_painter.drawRect(sel_rect_scaled) # draw the resize grip (if possible) if sel_rect_scaled.width() > 20 and sel_rect_scaled.height() > 20: handle_rect = QRect(sel_rect_scaled.bottomRight(), self._handle_size) frame_painter.fillRect(handle_rect, self._hl_color2) frame_painter.drawRect(handle_rect) frame_painter.end() # painting the darkened frame: self._painter.drawPixmap(0, 0, frame) self._painter.end() def resizeEvent(self, event): '''Overrides QWidget's resizeEvent. Handles image centering.''' # pylint: disable=C0103 self.adjust_image_origin() # -------------------- [END] QT_OVERRIDE def adjust_image_origin(self): '''Recalculates the top left corner's image position, so the image is painted centered''' # pylint: disable=C0103 new_size = self.size() / self._zoom pix_size = self._pixmap.size() dx = (new_size.width() - pix_size.width() ) /2 dy = (new_size.height() - pix_size.height()) /2 new_image_origin = QPoint(dx, dy) self._selection_rect.translate(new_image_origin - self._image_origin) self._image_origin = new_image_origin log.info('image origin: %s' % new_image_origin) def select_unscaled(self): '''Selects, if possible, a 96 x 96 square centered around the original image. In this way the image won't be scaled but won't take up all the 96 x 96 area.''' # pylint: disable=C0103 pix_size = self._pixmap.size() if pix_size.width() <= 96 and pix_size.height() <= 96: viewport_size = self.size() x = (viewport_size.width () - 96) / 2 y = (viewport_size.height() - 96) / 2 self._selection_rect.setTopLeft(QPoint(x, y)) self._selection_rect.setSize(QSize(96, 96)) self.update() self.selection_changed.emit() def select_all(self): '''Selects the whole image. Currently broken for images taller than wide.''' # TODO: make me work! self._selection_rect.setTopLeft(self._image_origin) self._selection_rect.setSize(self._pixmap.size()) self.update() self.selection_changed.emit() def rotate_left(self): '''Rotates the image counterclockwise.''' self._pixmap = self._pixmap.transformed(QtGui.QTransform().rotate(-90)) self.adjust_minum_size() self.adjust_image_origin() self.update() self.selection_changed.emit() def rotate_right(self): '''Rotates the image clockwise''' self._pixmap = self._pixmap.transformed(QtGui.QTransform().rotate(90)) self.adjust_minum_size() self.adjust_image_origin() self.update() self.selection_changed.emit() def adjust_minum_size(self): '''Sets the new minimum size, calculated upon the image size and the _zoom factor.''' pixmap = self._pixmap if pixmap.width() < 96 or pixmap.height() < 96: min_size = QSize(96, 96) else: min_size = pixmap.size() self.setMinimumSize(min_size*self._zoom) def make_selection_square(self): '''Modify the selected area making it square''' wid = self._selection_rect.width () self._selection_rect.setSize(QSize(wid, wid)) def set_zoom(self, zoomlevel): '''Sets the specified zoomlevel''' self._zoom = zoomlevel self.adjust_minum_size() self.adjust_image_origin() self.update() self.selection_changed.emit() def fit_zoom(self): '''Chooses a zoomlevel that makes visible the entire image. Currently broken.''' widget_wid = self.size().width () widget_hei = self.size().height() pixmap_wid = self._pixmap.width () pixmap_hei = self._pixmap.height() self._zoom = (min(widget_wid, widget_hei) / min(pixmap_wid, pixmap_hei)) self.adjust_minum_size() self.adjust_image_origin() self.update() self.selection_changed.emit() def get_selected_pixmap(self): '''Returns the pixmap contained in the selection rect. Currently doesn't handle transparency correctly''' sel_rect_scaled = QRect(self._selection_rect.topLeft() * self._zoom, self._selection_rect.size() * self._zoom) return QtGui.QPixmap.grabWidget(self, sel_rect_scaled)
class XSnapshotWidget(QWidget): def __init__(self, parent=None): super(XSnapshotWidget, self).__init__(parent) # define custom properties self._region = QRect() self._filepath = '' # define custom properties palette = self.palette() palette.setColor(palette.Window, QColor('white')) self.setPalette(palette) self.setWindowOpacity(0.5) self.setWindowFlags(Qt.SplashScreen) self.setFocus() def accept(self): """ Prompts the user for the filepath to save and then saves the image. """ filetypes = 'PNG Files (*.png);;JPG Files (*.jpg);;All Files (*.*)' filename = QFileDialog.getSaveFileName(None, 'Save Snapshot', self.filepath(), filetypes) if type(filename) == tuple: filename = filename[0] filename = str(filename) if not filename: self.reject() else: self.setFilepath(filename) self.save() def filepath(self): """ Returns the filepath that is going to be asved for this snapshot widget. :return <str> """ return self._filepath def hideWindow(self): """ Sets the window to hide/show while taking the snapshot. :param window | <QMainWindow> || <QDialog> """ return self._hideWindow def keyPressEvent(self, event): """ Listens for the escape key to cancel out from this snapshot. :param event | <QKeyPressEvent> """ # reject on a cancel if event.key() == Qt.Key_Escape: self.reject() super(XSnapshotWidget, self).keyPressEvent(event) def mousePressEvent(self, event): """ Starts the selection process for this widget and snapshot area. :param event | <QMousePressEvent> """ self._region.setX(event.pos().x()) self._region.setY(event.pos().y()) super(XSnapshotWidget, self).mousePressEvent(event) def mouseMoveEvent(self, event): """ Drags the selection view for this widget. :param event | <QMouseMoveEvent> """ w = event.pos().x() - self._region.x() h = event.pos().y() - self._region.y() self._region.setWidth(w) self._region.setHeight(h) self.repaint() super(XSnapshotWidget, self).mouseMoveEvent(event) def mouseReleaseEvent(self, event): """ Finishes the selection event. :param event | <QMouseReleaseEvent> """ self.accept() super(XSnapshotWidget, self).mouseReleaseEvent(event) def paintEvent(self, event): """ Handles the drawing for this widget and its selection region. :param event | <QPaintEvent> """ pen = QPen(Qt.DashLine) pen.setColor(QColor('red')) painter = QPainter(self) painter.setPen(pen) clr = QColor('black') clr.setAlpha(100) painter.setBrush(clr) painter.drawRect(self._region) def reject(self): """ Rejects the snapshot and closes the widget. """ if self.hideWindow(): self.hideWindow().show() self.close() self.deleteLater() def region(self): """ Returns the selection region defined by the rectangle for snapshoting. :return <QRect> """ return self._region def save(self): """ Saves the snapshot based on the current region. """ # close down the snapshot widget if self.hideWindow(): self.hideWindow().hide() self.hide() QApplication.processEvents() time.sleep(1) # create the pixmap to save wid = QApplication.desktop().winId() if not self._region.isNull(): x = self._region.x() y = self._region.y() w = self._region.width() h = self._region.height() else: x = self.x() y = self.y() w = self.width() h = self.height() pixmap = QPixmap.grabWindow(wid, x, y, w, h) pixmap.save(self.filepath()) self.close() self.deleteLater() if self.hideWindow(): self.hideWindow().show() def show(self): """ Shows this widget and hides the specified window if necessary. """ super(XSnapshotWidget, self).show() if self.hideWindow(): self.hideWindow().hide() QApplication.processEvents() def setFilepath(self, filepath): """ Sets the filepath that will be saved for this snapshot. :param filepath | <str> """ self._filepath = filepath def setHideWindow(self, window): """ Sets the window that will be hidden while this snapshot is being taken. :param window | <QMainWindow> """ self._hideWindow = window def setRegion(self, rect): """ Sets the region rectangle to the inputed rect. :param rect | <QRect> """ if rect is not None: self._region = rect @staticmethod def capture(rect=None, filepath='', prompt=True, hideWindow=None): """ Prompts the user to capture the screen. :param rect | <QRect> filepath | <str> prompt | <bool> :return (<str> filepath, <bool> accepted) """ widget = XSnapshotWidget(QApplication.desktop()) widget.setRegion(rect) widget.setHideWindow(hideWindow) widget.setFilepath(filepath) widget.move(1, 1) widget.resize(QApplication.desktop().size()) if prompt or not filepath: widget.show() else: widget.save()
class ImageAreaSelector(QtGui.QWidget): '''This widget provides means to visually crop a portion of an image by selecting it''' # pylint: disable=W0612 NAME = 'ImageAreaSelector' DESCRIPTION = 'A widget used to select part of an image' AUTHOR = 'Gabriele "Whisky" Visconti' WEBSITE = '' # pylint: enable=W0612 selection_changed = QtCore.pyqtSignal() def __init__(self, pixmap, parent=None): '''Constructor''' QtGui.QWidget.__init__(self, parent) self._pixmap = pixmap self._selection_rect = QRect() self._image_origin = QPoint() self._resize_start = None self._drag_start = None self._handle_size = QSize(-10, -10) self._painter = QtGui.QPainter() self._hl_color1 = QtGui.QPalette().color(QtGui.QPalette.Highlight) self._hl_color2 = QtGui.QPalette().color(QtGui.QPalette.Highlight) self._hl_color2.setAlpha(150) self._zoom = 1.0 self.adjust_minum_size() self.setBackgroundRole(QtGui.QPalette.Dark) self.setMouseTracking(True) self.setCursor(Qt.CrossCursor) # -------------------- [BEGIN] QT_OVERRIDE def mousePressEvent(self, event): '''Overrides QWidget's mousePressEvent. Handles starting a new selection, starting a drag operation''' # pylint: disable=C0103 mouse_pos = event.pos() / self._zoom sel_rect = self._selection_rect if not event.button() == Qt.LeftButton: return if (not sel_rect.isNull()) and sel_rect.contains(mouse_pos, True): handle_rect = QRect(sel_rect.bottomRight(), self._handle_size) if handle_rect.contains(mouse_pos): self._resize_start = mouse_pos else: self._drag_start = mouse_pos else: self._resize_start = mouse_pos sel_rect.setTopLeft(mouse_pos) self._selection_rect.setSize(QSize(0, 0)) def mouseMoveEvent(self, event): '''Overrides QWidget's mouseMoveEvent. Handles resizing and dragging operations on selection''' # pylint: disable=C0103 sel_rect = self._selection_rect if self._resize_start: resize_end = event.pos() / self._zoom sel_rect.setBottomRight(sel_rect.bottomRight() + (resize_end - self._resize_start)) self._resize_start = resize_end self.make_selection_square() self.update() elif self._drag_start is not None: drag_end = event.pos() / self._zoom sel_rect.translate(drag_end - self._drag_start) self._drag_start = drag_end self.update() # cursor shape: mouse_pos = event.pos() / self._zoom if (not sel_rect.isNull()) and sel_rect.contains(mouse_pos, True): handle_rect = QRect(sel_rect.bottomRight(), self._handle_size) if handle_rect.contains(mouse_pos): self.setCursor(Qt.SizeFDiagCursor) else: self.setCursor(Qt.OpenHandCursor) else: self.setCursor(Qt.CrossCursor) def mouseReleaseEvent(self, event): '''Overrides QWidget's mouseReleaseEvent. Handles ending a resizing or draggin operation on the selection''' # pylint: disable=C0103 self._selection_rect = self._selection_rect.normalized() self._resize_start = None self._drag_start = None self.update() if not self._selection_rect.isNull(): self.selection_changed.emit() def paintEvent(self, event): '''Overrides QWidtget's paintEvent.''' # pylint: disable=C0103 QtGui.QWidget.paintEvent(self, event) self._painter.begin(self) pixmap_dest_rect = QRect(self._image_origin * self._zoom, self._pixmap.size() * self._zoom) self._painter.drawPixmap(pixmap_dest_rect, self._pixmap) if not self._selection_rect.isNull(): # preparing the darkened frame: sel_rect = self._selection_rect.normalized() frame = QtGui.QPixmap(event.rect().size()) frame.fill(QtGui.QColor(0, 0, 0, 127)) frame_painter = QtGui.QPainter(frame) # erase the selected area from the frame: frame_painter.setCompositionMode( QtGui.QPainter.CompositionMode_DestinationIn) sel_rect_scaled = QRect(sel_rect.topLeft() * self._zoom, sel_rect.size() * self._zoom) frame_painter.fillRect(sel_rect_scaled, QtGui.QColor(0, 0, 0, 0)) # draw selection border : frame_painter.setCompositionMode( QtGui.QPainter.CompositionMode_SourceOver) frame_painter.setPen(self._hl_color1) frame_painter.drawRect(sel_rect_scaled) # draw the resize grip (if possible) if sel_rect_scaled.width() > 20 and sel_rect_scaled.height() > 20: handle_rect = QRect(sel_rect_scaled.bottomRight(), self._handle_size) frame_painter.fillRect(handle_rect, self._hl_color2) frame_painter.drawRect(handle_rect) frame_painter.end() # painting the darkened frame: self._painter.drawPixmap(0, 0, frame) self._painter.end() def resizeEvent(self, event): '''Overrides QWidget's resizeEvent. Handles image centering.''' # pylint: disable=C0103 self.adjust_image_origin() # -------------------- [END] QT_OVERRIDE def adjust_image_origin(self): '''Recalculates the top left corner's image position, so the image is painted centered''' # pylint: disable=C0103 new_size = self.size() / self._zoom pix_size = self._pixmap.size() dx = (new_size.width() - pix_size.width()) / 2 dy = (new_size.height() - pix_size.height()) / 2 new_image_origin = QPoint(dx, dy) self._selection_rect.translate(new_image_origin - self._image_origin) self._image_origin = new_image_origin log.info('image origin: %s' % new_image_origin) def select_unscaled(self): '''Selects, if possible, a 96 x 96 square centered around the original image. In this way the image won't be scaled but won't take up all the 96 x 96 area.''' # pylint: disable=C0103 pix_size = self._pixmap.size() if pix_size.width() <= 96 and pix_size.height() <= 96: viewport_size = self.size() x = (viewport_size.width() - 96) / 2 y = (viewport_size.height() - 96) / 2 self._selection_rect.setTopLeft(QPoint(x, y)) self._selection_rect.setSize(QSize(96, 96)) self.update() self.selection_changed.emit() def select_all(self): '''Selects the whole image. Currently broken for images taller than wide.''' # TODO: make me work! self._selection_rect.setTopLeft(self._image_origin) self._selection_rect.setSize(self._pixmap.size()) self.update() self.selection_changed.emit() def rotate_left(self): '''Rotates the image counterclockwise.''' self._pixmap = self._pixmap.transformed(QtGui.QTransform().rotate(-90)) self.adjust_minum_size() self.adjust_image_origin() self.update() self.selection_changed.emit() def rotate_right(self): '''Rotates the image clockwise''' self._pixmap = self._pixmap.transformed(QtGui.QTransform().rotate(90)) self.adjust_minum_size() self.adjust_image_origin() self.update() self.selection_changed.emit() def adjust_minum_size(self): '''Sets the new minimum size, calculated upon the image size and the _zoom factor.''' pixmap = self._pixmap if pixmap.width() < 96 or pixmap.height() < 96: min_size = QSize(96, 96) else: min_size = pixmap.size() self.setMinimumSize(min_size * self._zoom) def make_selection_square(self): '''Modify the selected area making it square''' wid = self._selection_rect.width() self._selection_rect.setSize(QSize(wid, wid)) def set_zoom(self, zoomlevel): '''Sets the specified zoomlevel''' self._zoom = zoomlevel self.adjust_minum_size() self.adjust_image_origin() self.update() self.selection_changed.emit() def fit_zoom(self): '''Chooses a zoomlevel that makes visible the entire image. Currently broken.''' widget_wid = self.size().width() widget_hei = self.size().height() pixmap_wid = self._pixmap.width() pixmap_hei = self._pixmap.height() self._zoom = (min(widget_wid, widget_hei) / min(pixmap_wid, pixmap_hei)) self.adjust_minum_size() self.adjust_image_origin() self.update() self.selection_changed.emit() def get_selected_pixmap(self): '''Returns the pixmap contained in the selection rect. Currently doesn't handle transparency correctly''' sel_rect_scaled = QRect(self._selection_rect.topLeft() * self._zoom, self._selection_rect.size() * self._zoom) return QtGui.QPixmap.grabWidget(self, sel_rect_scaled)