def show_synced(self) -> None: p1 = QPixmap(self.icon().pixmap(self.icon().actualSize( QSize(1024, 1024)))) p2 = QPixmap(resource_path('icons/KeepSync.png')) mode = QPainter.CompositionMode_SourceOver s = p1.size().expandedTo(p2.size()) result = QPixmap(s) result.fill(Qt.transparent) painter = QPainter(result) painter.setRenderHint(QPainter.Antialiasing) painter.drawPixmap(QPoint(), p1) painter.setCompositionMode(mode) painter.drawPixmap(result.rect(), p2, p2.rect()) painter.end() self.setIcon(QIcon(result))
def update_pixmap(self, new: QPixmap, scaled: bool = True) -> None: """ Updates the currently displayed image. :param new: The new `QPixmap` to be displayed. :param scaled: If False, don't scale the image to fit the viewport. """ self.pixmap_is_scaled = scaled self.media.clear() self.pixmap = self.media.addPixmap(new) self.pixmap.setTransformOriginPoint( self.pixmap.boundingRect().width() / 2, self.pixmap.boundingRect().height() / 2) if scaled and (new.size().width() > self.view.width() or new.size().height() > self.view.height()): self.view.fitInView(self.pixmap, Qt.KeepAspectRatio) self.media.setSceneRect(self.pixmap.boundingRect())
def browser(self): """Slot function to initialize image thumbnails for the 'browse mode.'""" while self.h_box2.itemAt(0): self.h_box2.takeAt(0).widget().deleteLater() index = (self.index + (len(self.files) - 2)) % len(self.files) for i, file in enumerate(self.files): file = self.dir_now + '/' + self.files[index] label = ClickableLabel(self, file) self.h_box2.addWidget(label) pix = QPixmap(file) if (pix.size().width() > self.browse_bar.width() / 5 or pix.size().height() > 100): pix = pix.scaled(self.browse_bar.width() / 5, 100, Qt.KeepAspectRatio) label.setPixmap(pix) index = (index + 1) % len(self.files) if i == 4: break
class QtImg(QtWidgets.QWidget, Ui_Img): def __init__(self): super(self.__class__, self).__init__() Ui_Img.__init__(self) self.setupUi(self) self.bookId = "" self.epsId = 0 self.curIndex = 0 self.setWindowTitle("IMG") self.setWindowModality(QtCore.Qt.ApplicationModal) self.resize(800, 900) self.checkBox.setChecked(True) self.index = 0 self.comboBox.setCurrentIndex(self.index) validator = QIntValidator(0, 9999999) self.heighEdit.setValidator(validator) self.widthEdit.setValidator(validator) exp = QDoubleValidator(0.1, 64, 1) exp.setNotation(exp.StandardNotation) self.scaleEdit.setValidator(exp) # self.setWindowFlags(Qt.FramelessWindowHint) self.graphicsView.setFrameStyle(QFrame.NoFrame) self.graphicsView.setObjectName("graphicsView") self.graphicsView.setBackgroundBrush(QColor(Qt.white)) self.graphicsView.setCursor(Qt.OpenHandCursor) self.graphicsView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.graphicsView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.graphicsView.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform) self.graphicsView.setCacheMode(self.graphicsView.CacheBackground) self.graphicsView.setViewportUpdateMode(self.graphicsView.SmartViewportUpdate) self.graphicsItem = QGraphicsPixmapItem() self.graphicsItem.setFlags(QGraphicsPixmapItem.ItemIsFocusable | QGraphicsPixmapItem.ItemIsMovable) self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.CopyPicture) self.graphicsScene = QGraphicsScene(self) # 场景 self.graphicsView.setScene(self.graphicsScene) self.graphicsScene.addItem(self.graphicsItem) self.graphicsView.setMinimumSize(10, 10) self.pixMap = QPixmap("Loading") self.graphicsItem.setPixmap(self.pixMap) # self.radioButton.setChecked(True) self.isStripModel = False # self.radioButton.installEventFilter(self) # self.radioButton_2.installEventFilter(self) self.graphicsView.installEventFilter(self) self.graphicsView.setWindowFlag(Qt.FramelessWindowHint) # tta有BUG,暂时屏蔽 TODO # self.ttaModel.setEnabled(False) self.data = b"" self.waifu2xData = b"" self._delta = 0.1 self.scaleCnt = 0 self.backStatus = "" self.format = "" def ShowImg(self, data): if data: self.data = data self.waifu2xData = b"" QtTask().CancelConver("QtImg") self._ShowImg(data) elif self.data: self._ShowImg(self.data) else: pass def _ShowImg(self, data): self.scaleCnt = 0 self.pixMap = QPixmap() self.pixMap.loadFromData(data) self.show() self.graphicsItem.setPixmap(self.pixMap) self.graphicsView.setSceneRect(QRectF(QPointF(0, 0), QPointF(self.pixMap.width(), self.pixMap.height()))) size = ToolUtil.GetDownloadSize(len(data)) self.sizeLabel.setText(size) weight, height = ToolUtil.GetPictureSize(data) self.resolutionLabel.setText(str(weight) + "x" + str(height)) self.ScalePicture() def ScalePicture(self): rect = QRectF(self.graphicsItem.pos(), QSizeF( self.pixMap.size())) unity = self.graphicsView.transform().mapRect(QRectF(0, 0, 1, 1)) width = unity.width() height = unity.height() if width <= 0 or height <= 0: return self.graphicsView.scale(1 / width, 1 / height) viewRect = self.graphicsView.viewport().rect() sceneRect = self.graphicsView.transform().mapRect(rect) if sceneRect.width() <= 0 or sceneRect.height() <= 0: return x_ratio = viewRect.width() / sceneRect.width() y_ratio = viewRect.height() / sceneRect.height() x_ratio = y_ratio = min(x_ratio, y_ratio) self.graphicsView.scale(x_ratio, y_ratio) # if self.readImg.isStripModel: # height2 = self.pixMap.size().height() / 2 # height3 = self.graphicsView.size().height()/2 # height3 = height3/x_ratio # p = self.graphicsItem.pos() # self.graphicsItem.setPos(p.x(), p.y()+height2-height3) self.graphicsView.centerOn(rect.center()) for _ in range(abs(self.scaleCnt)): if self.scaleCnt > 0: self.graphicsView.scale(1.1, 1.1) else: self.graphicsView.scale(1/1.1, 1/1.1) def resizeEvent(self, event) -> None: super(self.__class__, self).resizeEvent(event) self.ScalePicture() def eventFilter(self, obj, ev): if ev.type() == QEvent.KeyPress: return True else: return super(self.__class__, self).eventFilter(obj, ev) def wheelEvent(self, event): if event.angleDelta().y() > 0: self.zoomIn() else: self.zoomOut() def zoomIn(self): """放大""" self.zoom(1.1) def zoomOut(self): """缩小""" self.zoom(1/1.1) def zoom(self, factor): """缩放 :param factor: 缩放的比例因子 """ _factor = self.graphicsView.transform().scale( factor, factor).mapRect(QRectF(0, 0, 1, 1)).width() if _factor < 0.07 or _factor > 100: # 防止过大过小 return if factor >= 1: self.scaleCnt += 1 else: self.scaleCnt -= 1 self.graphicsView.scale(factor, factor) def CopyPicture(self): clipboard = QApplication.clipboard() clipboard.setPixmap(self.pixMap) QtBubbleLabel.ShowMsgEx(self, "Copy Success") return def ReduceScalePic(self): self.zoom(1/1.1) return def AddScalePic(self): self.zoom(1.1) return def OpenPicture(self): try: filename = QFileDialog.getOpenFileName(self, "Open Image", ".", "Image Files(*.jpg *.png)") if filename and len(filename) >= 1: name = filename[0] if os.path.isfile(name): f = open(name, "rb") data = f.read() f.close() self.ShowImg(data) except Exception as ex: Log.Error(ex) return def StartWaifu2xPng(self): if self.StartWaifu2x("png"): self.format = "png" self.changeJpg.setEnabled(False) self.changePng.setEnabled(False) return def StartWaifu2xJPG(self): if self.StartWaifu2x("jpg"): self.format = "jpg" self.changeJpg.setEnabled(False) self.changePng.setEnabled(False) return def StartWaifu2x(self, format): if not self.data: return False if not config.CanWaifu2x: return False from waifu2x_vulkan import waifu2x_vulkan self.SetStatus(False) self.index = self.comboBox.currentIndex() index = self.comboBox.currentIndex() noise = int(self.noiseCombox.currentText()) if index == 0: modelName = "CUNET" elif index == 1: modelName = "PHOTO" elif index == 2: modelName = "ANIME_STYLE_ART_RGB" else: return False if noise == -1: noiseName = "NO_NOISE" else: noiseName = "NOISE"+str(noise) if modelName == "CUNET" and self.scaleRadio.isChecked() and round(float(self.scaleEdit.text()), 1) <= 1: modelInsence = "MODEL_{}_NO_SCALE_{}".format(modelName, noiseName) else: modelInsence = "MODEL_{}_{}".format(modelName, noiseName) if self.ttaModel.isChecked(): modelInsence += "_TTA" model = { "model": getattr(waifu2x_vulkan, modelInsence), } if self.scaleRadio.isChecked(): model['scale'] = round(float(self.scaleEdit.text()), 1) else: model['width'] = int(self.widthEdit.text()) model['high'] = int(self.heighEdit.text()) model['format'] = format self.backStatus = self.GetStatus() QtTask().AddConvertTask(self.data, model, self.AddConvertBack, cleanFlag="QtImg") self.changeLabel.setText(self.tr("正在转换")) return True def AddConvertBack(self, data, waifuId, backParam, tick): if data: self.waifu2xData = data if self.checkBox.isChecked(): self._ShowImg(data) self.changeLabel.setText(self.tr("已转换")) self.tickLabel.setText(str(round(tick, 3)) + "s") else: self.changeLabel.setText(self.tr("失败")) self.SetStatus(True) return def CheckHideButton(self): if self.format == "": self.changePng.setEnabled(True) self.changeJpg.setEnabled(True) elif self.format == "png": self.changePng.setEnabled(False) self.changeJpg.setEnabled(True) else: self.changePng.setEnabled(True) self.changeJpg.setEnabled(False) def SavePicture(self): data = self.waifu2xData if self.waifu2xData else self.data if not data: return try: today = time.strftime("%Y%m%d%H%M%S", time.localtime(time.time())) picFormat = self.format if self.format else "jpg" filepath = QFileDialog.getSaveFileName(self, "Save", "{}.{}".format(today, picFormat)) if filepath and len(filepath) >= 1 and filepath[0]: name = filepath[0] f = open(name, "wb") f.write(data) f.close() except Exception as es: Log.Error(es) return def SwithPicture(self): if self.checkBox.isChecked() and self.waifu2xData: self._ShowImg(self.waifu2xData) else: self._ShowImg(self.data) return def ChangeModel(self, index): # self.index = self.comboBox.currentIndex() self.CheckScaleRadio() return def GetStatus(self): data = str(self.noiseCombox.currentText()) + \ str(self.buttonGroup_2.checkedId()) + \ str(self.scaleEdit.text()) + \ str(self.heighEdit.text()) + \ str(int(self.ttaModel.isChecked())) + \ str(self.widthEdit.text()) + \ str(self.comboBox.currentIndex()) return data def SetStatus(self, status): self.scaleRadio.setEnabled(status) self.heighRadio.setEnabled(status) self.scaleEdit.setEnabled(status) self.widthEdit.setEnabled(status) self.heighEdit.setEnabled(status) self.noiseCombox.setEnabled(status) self.comboBox.setEnabled(status) # self.radioButton_4.setEnabled(status) # self.radioButton_5.setEnabled(status) # self.radioButton_6.setEnabled(status) # self.radioButton_7.setEnabled(status) # self.radioButton_8.setEnabled(status) # self.ttaModel.setEnabled(status) self.CheckScaleRadio() def SetEnable(self): self.SetStatus(True) def SetDisEnable(self): self.SetStatus(False) def CheckScaleRadio(self): if self.scaleRadio.isChecked() and self.scaleRadio.isEnabled(): self.scaleEdit.setEnabled(True) self.widthEdit.setEnabled(False) self.heighEdit.setEnabled(False) elif self.heighRadio.isChecked() and self.heighRadio.isEnabled(): self.scaleEdit.setEnabled(False) self.widthEdit.setEnabled(True) self.heighEdit.setEnabled(True) data = self.GetStatus() if self.backStatus != data: self.changePng.setEnabled(True) self.changeJpg.setEnabled(True) else: self.CheckHideButton()
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.art_scene = QGraphicsScene(self) self.art_scene.addText('Open an image file.') self.ui.art_view.setScene(self.art_scene) self.symbols_scene = QGraphicsScene(self) self.ui.symbols_view.setScene(self.symbols_scene) self.ui.action_exit.triggered.connect(self.close) self.ui.action_open_art.triggered.connect(self.open_image) self.ui.action_open_words.triggered.connect(self.open_words) self.ui.action_save.triggered.connect(self.save_pdf) self.ui.action_save_png.triggered.connect(self.save_png) self.ui.action_shuffle.triggered.connect(self.shuffle) self.ui.action_sort.triggered.connect(self.sort) self.ui.rows.valueChanged.connect(self.on_options_changed) self.ui.columns.valueChanged.connect(self.on_options_changed) self.ui.word_clues_radio.toggled.connect(self.on_options_changed) self.ui.symbol_clues_radio.toggled.connect(self.on_options_changed) self.word_layout = QGridLayout(self.ui.word_content) self.ui.word_scroll.setWidgetResizable(True) self.word_labels: typing.Dict[str, QLabel] = {} self.word_shuffler = WordShuffler([]) self.clues = None self.pixmap = self.scaled_pixmap = self.mini_pixmap = None self.sliced_pixmap_item: typing.Optional[QGraphicsPixmapItem] = None self.sliced_image: typing.Optional[QImage] = None self.selection_grid: typing.Optional[SelectionGrid] = None self.cells = [] self.art_shuffler: typing.Optional[ArtShuffler] = None self.symbols_source_pixmap_item: typing.Optional[ QGraphicsPixmapItem] = None self.symbols_pixmap_item: typing.Optional[QGraphicsPixmapItem] = None self.symbols_image: typing.Optional[QImage] = None self.symbols_shuffler: typing.Optional[ArtShuffler] = None self.selected_row: typing.Optional[int] = None self.selected_column: typing.Optional[int] = None self.settings = QSettings() self.image_path: typing.Optional[str] = self.settings.value( 'image_path') self.words_path: typing.Optional[str] = self.settings.value( 'words_path') self.dirty_letters = set() self.timer = QTimer() self.timer.setInterval(500) self.timer.setSingleShot(True) # noinspection PyUnresolvedReferences self.timer.timeout.connect(self.on_dirty) self.row_count = self.column_count = 0 self.clue_type = ClueType.words self.ui.rows.setValue(self.settings.value('row_count', 6, int)) self.ui.columns.setValue(self.settings.value('column_count', 4, int)) clue_type_name = self.settings.value('clue_type', ClueType.words.name) try: clue_type = ClueType[clue_type_name] except KeyError: clue_type = ClueType.words if clue_type == ClueType.words: self.ui.word_clues_radio.setChecked(True) else: self.ui.symbol_clues_radio.setChecked(True) self.row_clues: typing.List[QPixmap] = [] self.column_clues: typing.List[QPixmap] = [] self.on_options_changed() def on_dirty(self): for letter in self.dirty_letters: self.word_labels[letter].setText( self.word_shuffler.make_display(letter)) self.settings.setValue(f'word_{letter}', self.word_shuffler[letter]) if self.dirty_letters: self.clues = self.word_shuffler.make_clues() self.art_shuffler.clues = dict(self.clues) self.dirty_letters.clear() self.on_selection_moved() if self.pixmap is not None: x, y, width, height = self.get_selected_fraction() self.settings.setValue('x', x) self.settings.setValue('y', y) self.settings.setValue('width', width) self.settings.setValue('height', height) new_rows = self.ui.rows.value() new_columns = self.ui.columns.value() if self.ui.word_clues_radio.isChecked(): new_clue_type = ClueType.words else: new_clue_type = ClueType.symbols if (new_rows, new_columns, new_clue_type) == (self.row_count, self.column_count, self.clue_type): return self.settings.setValue('row_count', new_rows) self.settings.setValue('column_count', new_columns) self.settings.setValue('clue_type', new_clue_type.name) self.row_count, self.column_count = new_rows, new_columns self.clue_type = new_clue_type word_count = (self.row_count * self.column_count) while self.word_layout.count(): layout_item = self.word_layout.takeAt(0) layout_item.widget().deleteLater() self.word_labels.clear() self.row_clues.clear() self.column_clues.clear() if self.image_path is not None: self.load_image(self.image_path) if self.words_path is not None: self.load_words(self.words_path) letters = [chr(65 + i) for i in range(word_count)] if self.word_shuffler.needs_blank: letters.insert(0, '') word_fields = {} for i, letter in enumerate(letters): word_field = QLineEdit() self.word_layout.addWidget(word_field, i, 0) # noinspection PyUnresolvedReferences word_field.textEdited.connect(partial(self.on_word_edited, letter)) word_label = QLabel() self.word_layout.addWidget(word_label, i, 1) self.word_labels[letter] = word_label word_fields[letter] = word_field for i, letter in enumerate(letters): word = self.settings.value(f'word_{letter}', '') self.word_shuffler[letter] = word self.dirty_letters.add(letter) word_fields[letter].setText(word) def on_options_changed(self, *_): self.timer.start() def shuffle(self): self.clues = self.word_shuffler.make_clues() if self.art_shuffler is not None: self.art_shuffler.shuffle() self.on_selection_moved() def sort(self): if self.art_shuffler is not None: self.art_shuffler.sort() self.on_selection_moved() def open_words(self): word_filter = 'Text files (*.txt)' if self.words_path is None: words_folder = None else: words_folder = str(Path(self.words_path).parent) file_name, _ = QFileDialog.getOpenFileName(self, "Open a words file.", dir=words_folder, filter=word_filter) if not file_name: return self.settings.setValue('words_path', file_name) self.load_words(file_name) def load_words(self, words_path): with open(words_path) as f: choice = 0 if choice == 0: self.word_shuffler = WordShuffler(f) else: self.word_shuffler = WordStripper(f) def open_image(self): formats = QImageReader.supportedImageFormats() patterns = (f'*.{fmt.data().decode()}' for fmt in formats) image_filter = f'Images ({" ".join(patterns)})' if self.image_path is None: image_folder = None else: image_folder = str(Path(self.image_path).parent) file_name, _ = QFileDialog.getOpenFileName(self, "Open an image file.", dir=image_folder, filter=image_filter) if not file_name: return self.settings.setValue('image_path', file_name) self.load_image(file_name) def load_image(self, image_path): self.pixmap = QPixmap(image_path) if self.pixmap.isNull(): self.pixmap = None self.image_path = image_path self.scale_image() def scale_image(self): if self.pixmap is None: return if self.selection_grid is None: x = self.settings.value('x', 0.0, float) y = self.settings.value('y', 0.0, float) width = self.settings.value('width', 1.0, float) height = self.settings.value('height', 1.0, float) else: x, y, width, height = self.get_selected_fraction() self.art_scene.clear() self.cells.clear() view_size = self.ui.art_view.maximumViewportSize() if view_size.width() == 0: return self.art_scene.setSceneRect(0, 0, view_size.width(), view_size.height()) display_size = QSize(view_size.width() * 0.99 / 2, view_size.height() * 0.99) self.scaled_pixmap = self.pixmap.scaled( display_size, aspectMode=Qt.AspectRatioMode.KeepAspectRatio) self.art_scene.addPixmap(self.scaled_pixmap) scaled_size = self.scaled_pixmap.size() self.selection_grid = SelectionGrid(scaled_size.width() * x, scaled_size.height() * y, scaled_size.width() * width, scaled_size.height() * height, row_count=self.row_count, column_count=self.column_count) self.selection_grid.on_moved = self.on_selection_moved self.art_scene.addItem(self.selection_grid) self.sliced_image = QImage(display_size, QImage.Format.Format_ARGB32_Premultiplied) self.check_clues() self.art_shuffler = ArtShuffler(self.selection_grid.row_count, self.selection_grid.column_count, self.sliced_image, QRect(0, 0, display_size.width(), display_size.height()), clues=self.clues, row_clues=self.row_clues, column_clues=self.column_clues) self.sliced_pixmap_item = self.art_scene.addPixmap( QPixmap.fromImage(self.sliced_image)) self.sliced_pixmap_item.setPos(display_size.width(), 0) self.symbols_scene.clear() self.symbols_source_pixmap_item = self.symbols_scene.addPixmap( self.scaled_pixmap) self.symbols_image = QImage(display_size, QImage.Format.Format_ARGB32_Premultiplied) if self.symbols_shuffler is not None: selected_row = self.symbols_shuffler.selected_row selected_column = self.symbols_shuffler.selected_column else: selected_row = 0 selected_column = None self.symbols_shuffler = ArtShuffler(self.selection_grid.row_count, self.selection_grid.column_count, self.symbols_image, QRect(0, 0, display_size.width(), display_size.height()), row_clues=self.row_clues, column_clues=self.column_clues) self.symbols_shuffler.selected_row = selected_row self.symbols_shuffler.selected_column = selected_column self.symbols_pixmap_item = ClickablePixmapItem( QPixmap.fromImage(self.symbols_image)) self.symbols_pixmap_item.on_click = self.on_symbols_clicked self.symbols_scene.addItem(self.symbols_pixmap_item) self.symbols_pixmap_item.setPos(display_size.width(), 0) self.on_selection_moved() def on_symbols_clicked(self, event: QGraphicsSceneMouseEvent): self.symbols_scene.clearSelection() self.symbols_shuffler.select_clue(event.pos().toPoint()) self.on_selection_moved() def on_word_edited(self, letter, word): self.word_shuffler[letter] = word self.dirty_letters.add(letter) self.timer.start() def get_selected_fraction(self): selection_rect = self.selection_grid.rect() selection_pos = self.selection_grid.pos() size = self.scaled_pixmap.size() x = (selection_pos.x() + selection_rect.x()) / size.width() width = selection_rect.width() / size.width() y = (selection_pos.y() + selection_rect.y()) / size.height() height = selection_rect.height() / size.height() return x, y, width, height def on_selection_moved(self): selected_pixmap = self.get_selected_pixmap() self.art_shuffler.draw(selected_pixmap) self.sliced_pixmap_item.setPixmap(QPixmap.fromImage(self.sliced_image)) selected_pixmap = self.get_selected_pixmap() cell_width = (selected_pixmap.width() / self.selection_grid.column_count) cell_height = (selected_pixmap.height() / self.selection_grid.row_count) self.row_clues.clear() self.column_clues.clear() for i in range(self.selection_grid.row_count): clue_image = selected_pixmap.copy(0, i * cell_height, cell_width, cell_height) self.row_clues.append(clue_image) for j in range(self.selection_grid.column_count): clue_image = selected_pixmap.copy(j * cell_width, 0, cell_width, cell_height) self.column_clues.append(clue_image) self.symbols_shuffler.row_clues = self.row_clues self.symbols_shuffler.column_clues = self.column_clues self.symbols_shuffler.draw_grid(selected_pixmap) self.symbols_pixmap_item.setPixmap( QPixmap.fromImage(self.symbols_image)) self.timer.start() def get_selected_pixmap(self) -> QPixmap: x, y, width, height = self.get_selected_fraction() original_size = self.pixmap.size() selected_pixmap = self.pixmap.copy(x * original_size.width(), y * original_size.height(), width * original_size.width(), height * original_size.height()) return selected_pixmap def resizeEvent(self, event: QResizeEvent): super().resizeEvent(event) self.scale_image() def save_pdf(self): pdf_folder = self.settings.value('pdf_folder') file_name, _ = QFileDialog.getSaveFileName(self, "Save a PDF file.", dir=pdf_folder, filter='Documents (*.pdf)') if not file_name: return self.settings.setValue('pdf_folder', os.path.dirname(file_name)) writer = QPdfWriter(file_name) writer.setPageSize(QPageSize(QPageSize.Letter)) writer.setTitle('Sliced Art Puzzle') writer.setCreator('Don Kirkby') self.paint_puzzle(writer) def save_png(self): pdf_folder = self.settings.value('pdf_folder') file_name, _ = QFileDialog.getSaveFileName(self, "Save an image file.", dir=pdf_folder, filter='Images (*.png)') if not file_name: return writer = QPixmap(1000, 2000) self.paint_puzzle(writer) writer.save(file_name) self.settings.setValue('pdf_folder', os.path.dirname(file_name)) def paint_puzzle(self, writer: QPaintDevice): self.check_clues() painter = QPainter(writer) try: print_shuffler = ArtShuffler(self.art_shuffler.rows, self.art_shuffler.cols, writer, QRect(0, 0, writer.width(), round(writer.height() / 2)), clues=self.clues, row_clues=self.row_clues, column_clues=self.column_clues) print_shuffler.cells = self.art_shuffler.cells[:] print_shuffler.is_shuffled = self.art_shuffler.is_shuffled selected_pixmap = self.get_selected_pixmap() print_shuffler.draw(selected_pixmap, painter) print_shuffler.rect.moveTop(writer.height() / 2) print_shuffler.draw_grid(selected_pixmap, painter) finally: painter.end() def check_clues(self): if self.clue_type == ClueType.words: if self.clues is None: self.clues = self.word_shuffler.make_clues() self.row_clues.clear() self.column_clues.clear() else: self.clues = None