[Python] - import sys
- import os
- import time
- import fitz
- from print import Ui_PrintForm
- from itertools import count
- from pathlib import Path
- import configparser
- from PIL.ImageQt import ImageQt
- from PIL import Image
- from PySide6.QtGui import QPainter, QPageSize, QPageLayout, QColor
- from PySide6.QtPrintSupport import QPrinter, QPrintDialog, QPrinterInfo
- from PySide6.QtCore import QRect, QObject, QThread, Signal, QEvent, Qt
- from PySide6.QtWidgets import QApplication, QWidget, QListWidgetItem, QFileDialog, QStyleFactory
- class printPdfWorker(QObject):
- finished = Signal()
- progress = Signal(str, str)
- def __init__(self, pdf=None, parent=None):
- super().__init__()
- self.win = parent
- self.paths = pdf
- self.cup = self.win.cup
- self.paper = self.win.paper
- self.printname = self.win.printName
- self.dpi = int(str(self.win.dpi)[:3])
- self.orientation = self.win.dirtion()
- ali = self.win.ali
- if '水平居中' in ali:
- self.inter = 2
- else: # inserted
- if '靠右居中' in ali:
- self.inter = 1
- self.double = self.win.double
- self._printer = QPrinter(QPrinter.PrinterMode.HighResolution)
- self._printer.setPrinterName(self.printname)
- if 'A4' in self.paper:
- self._printer.setPageSize(QPageSize(QPageSize.A4))
- self.height_dpx, self.width_dpx = self.a4_size(self.dpi, 210, 297)
- else: # inserted
- if 'A5' in self.paper:
- self._printer.setPageSize(QPageSize(QPageSize.A5))
- self.height_dpx, self.width_dpx = self.a4_size(self.dpi, 148, 210)
- self._printer.setPrintRange(QPrinter.PrintRange.AllPages)
- if self.win.checkbox.isChecked():
- self._printer.setColorMode(QPrinter.ColorMode.GrayScale)
- else: # inserted
- self._printer.setColorMode(QPrinter.ColorMode.Color)
- try:
- self._printer.setDuplex(self.double)
- except Exception as e:
- pass # postinserted
- else: # inserted
- if self.orientation:
- self._printer.setPageOrientation(self.orientation)
- self._printer.setCopyCount(self.cup)
- print(e)
- def setprinton(self):
- if 'A4' in self.paper:
- self._printer.setPageSize(QPageSize(QPageSize.A4))
- self.height_dpx, self.width_dpx = self.a4_size(self.dpi, 210, 297)
- else: # inserted
- if 'A5' in self.paper:
- self._printer.setPageSize(QPageSize(QPageSize.A5))
- self.height_dpx, self.width_dpx = self.a4_size(self.dpi, 148, 210)
- self._printer.setPrintRange(QPrinter.PrintRange.AllPages)
- if self.win.checkbox.isChecked():
- self._printer.setColorMode(QPrinter.ColorMode.GrayScale)
- else: # inserted
- self._printer.setColorMode(QPrinter.ColorMode.Color)
- try:
- self._printer.setDuplex(self.double)
- except Exception as e:
- pass # postinserted
- else: # inserted
- if self.orientation:
- self._printer.setPageOrientation(self.orientation)
- self._printer.setCopyCount(self.cup)
- print(e)
- else: # inserted
- pass
- def rundialog(self):
- self.dialog = QPrintDialog(self._printer)
- self.dialog.setOptions(QPrintDialog.PrintToFile | QPrintDialog.PrintSelection)
- if self.dialog.exec():
- self.runprint()
- else: # inserted
- self.finished.emit()
- def runprint(self):
- """长时间运行的打印任务。""" # inserted
- try:
- self.setprinton()
- if self.paper!= 'A4两版':
- if self.win.mergebox.isChecked():
- painter = QPainter(self._printer)
- rect = painter.viewport()
- images = self.add_image(self.paths)
- for pil_image, pageNumber in zip(images, count(1)):
- if pageNumber > 1:
- self._printer.newPage()
- self.print_image(pil_image, rect, painter)
- painter.end()
- else: # inserted
- for index, path in enumerate(self.paths):
- painter = QPainter(self._printer)
- rect = painter.viewport()
- images = []
- path = Path(path)
- suffix = path.suffix.lower()
- if suffix == '.pdf':
- images = self.open_pdf(path, images)
- for pil_image, pageNumber in zip(images, count(1)):
- if pageNumber > 1:
- self._printer.newPage()
- self.print_image(pil_image, rect, painter)
- else: # inserted
- with Image.open(path) as image:
- pass # postinserted
- except Exception as e:
- pil_image = image.copy()
- self.print_image(pil_image, rect, painter)
- painter.end()
- else: # inserted
- if self.win.mergebox.isChecked():
- images = self.add_image(self.paths)
- self.A4_sep(images)
- else: # inserted
- batch_size = 10
- for i in range(0, len(self.paths), batch_size):
- batch_paths = self.paths[i:i + batch_size]
- images = self.add_image(batch_paths)
- self.A4_sep(images)
- self.progress.emit('文件已发送至打印机', 'green')
- else: # inserted
- self.finished.emit()
- print(f'打印出错{e}0')
- def open_pdf(self, path, images):
- with fitz.open(path) as pdf:
- num_pages = len(pdf)
- printRange = range(num_pages)
- page_indices = [i for i in printRange]
- for index in page_indices:
- pixmap = pdf[index].get_pixmap(dpi=self.dpi)
- pil_image = Image.frombytes('RGB', [pixmap.width, pixmap.height], pixmap.samples)
- images.append(pil_image)
- return images
- def add_image(self, paths=None):
- images = []
- file_paths = paths
- file_paths = [path for path in file_paths if path.endswith('.pdf')] + [path for path in file_paths if path.endswith(('.jpg', '.jpeg', '.png'))]
- for index, path in enumerate(file_paths):
- path = Path(path)
- suffix = path.suffix.lower()
- if suffix == '.pdf':
- images = self.open_pdf(path, images)
- else: # inserted
- with Image.open(path) as image:
- images.append(image.copy())
- return images
- def A4_sep(self, images):
- if len(images) % 2!= 0:
- images.append(None)
- painter = QPainter(self._printer)
- for index, pageNumber in zip(range(0, len(images), 2), count(1)):
- image1 = images[index]
- image2 = images[index + 1]
- if pageNumber > 1:
- self._printer.newPage()
- self.join_pic(image1, image2, painter)
- painter.end()
- def print_image(self, pil_image, rect, painter):
- pilWidth, pilHeight = pil_image.size
- imageRatio = pilHeight / pilWidth
- viewportRatio = rect.height() / rect.width()
- A4Ratio = self.height_dpx / self.width_dpx
- if self.win.up == '自动旋转':
- if viewportRatio < 1 and imageRatio > 1 or (viewportRatio > 1 and imageRatio < 1):
- pil_image = pil_image.transpose(Image.ROTATE_90)
- pilWidth, pilHeight = pil_image.size
- imageRatio = pilHeight / pilWidth
- if A4Ratio < imageRatio:
- x = int(pilHeight / viewportRatio - pilWidth)
- xOffset = int(x / 2)
- yOffset = 0
- else: # inserted
- xOffset = 0
- y = int(rect.height() - rect.width() / pilWidth * pilHeight)
- yOffset = int(y / self.inter)
- else: # inserted
- xOffset, yOffset, x, y = (0, 0, 0, 0)
- if viewportRatio > imageRatio:
- y = int(rect.width() / (pilWidth / pilHeight))
- printArea = QRect(xOffset, yOffset, rect.width(), y)
- else: # inserted
- x = int(pilWidth / pilHeight * rect.height())
- printArea = QRect(xOffset, yOffset, x, rect.height())
- image = ImageQt(pil_image)
- painter.drawImage(printArea, image)
- return painter
- def join_pic(self, image1, image2, painter):
- if image2 == None:
- image2 = Image.new('RGB', image1.size, 'white')
- for image in (image1, image2):
- pilWidth, pilHeight = image.size
- imageRatio = pilHeight / pilWidth
- if imageRatio > 1:
- if image == image1:
- image1 = image.transpose(Image.ROTATE_90)
- if image == image2:
- image2 = image.transpose(Image.ROTATE_90)
- def resize_image(image):
- height = int(self.height_dpx / 2)
- ratio = height / image.size[1]
- max_width = int(image.size[0] * ratio)
- max_height = int(height)
- if max_width > self.width_dpx:
- max_width = self.width_dpx
- ratio = self.width_dpx / image.size[0]
- max_height = int(image.size[1] * ratio)
- new_width = max_width
- new_height = max_height
- resized_image = image.resize((new_width, new_height))
- return resized_image
- image1 = resize_image(image1)
- image2 = resize_image(image2)
- half_hight = int(self.height_dpx / 2)
- merged_image = Image.new('RGB', (self.width_dpx, self.height_dpx), 'white')
- if image1.size[0] < self.width_dpx:
- x1 = int((self.width_dpx - image1.size[0]) / self.inter)
- else: # inserted
- x1 = 0
- if image1.size[1] < half_hight:
- y1 = int((half_hight - image1.size[1]) / 2)
- else: # inserted
- y1 = 0
- if image2.size[0] < self.width_dpx:
- x2 = int((self.width_dpx - image2.size[0]) / self.inter)
- else: # inserted
- x2 = 0
- if image2.size[1] < half_hight:
- y2 = int((half_hight - image2.size[1]) / 2)
- else: # inserted
- y2 = 0
- merged_image.paste(image1, (x1, y1))
- merged_image.paste(image2, (x2, half_hight + y2))
- rect = painter.viewport()
- self.print_image(merged_image, rect, painter)
- def a4_size(self, dpi, width, height):
- a4_width = width / 25.4
- a4_height = height / 25.4
- height_dpx = int(a4_height * dpi)
- width_dpx = int(a4_width * dpi)
- return (height_dpx, width_dpx)
- class Window(QWidget):
- def __init__(self):
- super(Window, self).__init__()
- self.ui = Ui_PrintForm()
- self.ui_win = self.windowFlags()
- self.ui.setupUi(self)
- self.longRunningBtn = self.ui.pushButton
- self.longRunningBtn.clicked.connect(self.runPrintTask)
- self.addfile = self.ui.pushButton_2
- self.addfile.clicked.connect(self.getFile)
- self.clearfile = self.ui.pushButton_3
- self.clearfile.clicked.connect(self.clearFile)
- self.sysPrint = self.ui.toolButton
- self.sysPrint.clicked.connect(self.rundio)
- self.spinbox = self.ui.doubleSpinBox
- self.paper_box = self.ui.comboBox
- self.dpi_box = self.ui.comboBox_2
- self.double_box = self.ui.comboBox_3
- self.alignment = self.ui.comboBox_4
- self.direction = self.ui.comboBox_6
- self.paper_box.currentIndexChanged.connect(self.setdirection)
- self.bar = self.ui.label_8
- self.listwidget = self.ui.listWidget
- self.checkbox = self.ui.checkBox
- self.mergebox = self.ui.checkBox_2
- self.printbox = self.ui.comboBox_5
- self.load_printers()
- self.small_win = self.ui.dockWidget
- self.small_win.hide()
- self.textbox = self.ui.textEdit
- self.textbox.textChanged.connect(self.changedText)
- self.load_config()
- self.setdirection()
- self.file_path = []
- self.listwidget.viewport().installEventFilter(self)
- def eventFilter(self, source, event):
- if event.type() == QEvent.MouseButtonDblClick and source is self.listwidget.viewport():
- self.small_win.show()
- return True
- return super().eventFilter(source, event)
- def setdirection(self):
- if self.paper_box.currentText()!= 'A4':
- self.direction.setCurrentIndex(0)
- self.direction.setEnabled(False)
- else: # inserted
- self.direction.setEnabled(True)
- def changedText(self):
- self.clearFile()
- text = self.textbox.toPlainText()
- lines = text.splitlines()
- for line in lines:
- if line.strip():
- self.showListwidget(line)
- def load_config(self):
- config = configparser.ConfigParser()
- config.read('printConfig.ini')
- self.spinbox.setValue(int(config.get('Print', 'Series', fallback=1)))
- self.paper_box.setCurrentIndex(int(config.get('Print', 'Paper', fallback=0)))
- self.dpi_box.setCurrentIndex(int(config.get('Print', 'Dpi', fallback=1)))
- self.double_box.setCurrentIndex(int(config.get('Print', 'Double', fallback=0)))
- self.double_box.setCurrentIndex(int(config.get('Print', 'Center', fallback=0)))
- self.printbox.setCurrentText(config.get('Print', 'PrintName', fallback=''))
- self.direction.setCurrentIndex(int(config.get('Print', 'PageDirection', fallback=0)))
- self.checkbox.setCheckState(Qt.CheckState.Checked if config.getboolean('Print', 'Color', fallback=False) else Qt.CheckState.Unchecked)
- self.mergebox.setCheckState(Qt.CheckState.Checked if config.getboolean('Print', 'Mergebox', fallback=False) else Qt.CheckState.Unchecked)
- def doublePrint(self):
- double = self.double_box.currentIndex()
- if double == 0:
- return QPrinter.DuplexMode.DuplexNone
- if double == 1:
- return QPrinter.DuplexLongSide
- if double == 2:
- return QPrinter.DuplexShortSide
- if double == 3:
- return QPrinter.DuplexAuto
- def dirtion(self):
- self.up = self.direction.currentText()
- if self.up == '纵向':
- return QPageLayout.Portrait
- if self.up == '横向':
- return QPageLayout.Landscape
- def clearFile(self):
- self.file_path = []
- self.listwidget.clear()
- self.runBar('准备就绪......', 'black')
- def getFile(self):
- response = QFileDialog.getOpenFileNames(parent=self, caption='选择文件', filter='文件类型 (*.pdf *.jpg *.png *.jpeg *.bmp);;Images (*.png *.jpg *.jpeg *.bmp);;PDF Files (*.pdf)')
- if response:
- file_paths = response[0]
- for path in file_paths:
- self.showListwidget(path)
- def showListwidget(self, path):
- self.file_path.append(path)
- item_widget = QListWidgetItem(path)
- self.listwidget.addItem(item_widget)
- self.bar.setText(f'已添加文件:{len(self.file_path)}个')
- return self.file_path
- def lianjie(self, paths):
- self.clearFile()
- valid_extensions = {'.jpg', '.png', '.jpeg', 'bmp', '.pdf'}
- for path in paths:
- _, extensions = os.path.splitext(path)
- if extensions.lower() in valid_extensions:
- self.showListwidget(path)
- def load_printers(self):
- printers = QPrinterInfo.availablePrinters()
- printer_names = [printer.printerName() for printer in printers]
- self.printbox.addItems(printer_names)
- def printdata(self):
- self.cup = self.spinbox.value()
- self.paper = self.paper_box.currentText()
- self.dpi = self.dpi_box.currentText()
- self.ali = self.alignment.currentText()
- self.double = self.doublePrint()
- self.printName = self.printbox.currentText()
- self.runBar('正在发送页面到打印机\n请勿关闭程序...', 'red')
- def rundio(self):
- pdf_file = self.file_path
- if not pdf_file:
- self.runBar('没有待打印的文件', 'blue')
- return
- self.printdata()
- self.thread = QThread()
- self.worker = printPdfWorker(pdf_file, self)
- self.worker.moveToThread(self.thread)
- self.thread.started.connect(self.worker.rundialog)
- self.worker.finished.connect(self.thread.quit)
- self.worker.finished.connect(self.worker.deleteLater)
- self.worker.progress.connect(self.runBar)
- self.thread.start()
- def runPrintTask(self):
- pdf_file = self.file_path
- if not pdf_file:
- self.runBar('没有待打印的文件', 'blue')
- return
- self.printdata()
- self.thread = QThread()
- self.worker = printPdfWorker(pdf_file, self)
- self.worker.moveToThread(self.thread)
- self.thread.started.connect(self.worker.runprint)
- self.worker.finished.connect(self.thread.quit)
- self.worker.finished.connect(self.worker.deleteLater)
- self.worker.progress.connect(self.runBar)
- self.thread.start()
- def runBar(self, text, color='black'):
- palette = self.bar.palette()
- palette.setColor(self.bar.foregroundRole(), QColor(color))
- self.bar.setPalette(palette)
- self.bar.setText(text)
- def dragEnterEvent(self, event):
- if event.mimeData().hasUrls():
- event.accept()
- else: # inserted
- event.ignore()
- def dropEvent(self, event):
- valid_extensions = {'.jpg', '.png', '.jpeg', 'bmp', '.pdf'}
- dropped_files = []
- for url in event.mimeData().urls():
- file_path = url.toLocalFile()
- if os.path.isdir(file_path):
- for root, dirs, files in os.walk(file_path):
- for file in files:
- full_file_path = os.path.join(root, file)
- _, extension = os.path.splitext(full_file_path)
- if extension.lower() in valid_extensions:
- dropped_files.append(full_file_path)
- else: # inserted
- _, extension = os.path.splitext(file_path)
- if extension.lower() in valid_extensions:
- dropped_files.append(file_path)
- for file_path in dropped_files:
- self.showListwidget(file_path)
- def closeEvent(self, event):
- self.save_combobox()
- event.accept()
- def save_combobox(self):
- config = configparser.ConfigParser()
- config.read('printConfig.ini')
- if 'Print' not in config:
- config.add_section('Print')
- cup = self.spinbox.value()
- paper = self.paper_box.currentIndex()
- dpi = self.dpi_box.currentIndex()
- double = self.double_box.currentIndex()
- center = self.alignment.currentIndex()
- printName = self.printbox.currentText()
- direction = self.direction.currentIndex()
- mergebox = int(self.mergebox.checkState() == Qt.CheckState.Checked)
- config['Print'] = {'Series': int(cup), 'Paper': str(paper), 'Dpi': str(dpi), 'Double': str(double), 'Center': str(center), 'Color': str(int(self.checkbox.checkState() == Qt.CheckState.Checked)), 'PrintName': str(printName), 'PageDirection': str(direction), 'Mergebox': str(mergebox)}
- with open('printConfig.ini', 'w') as configfile:
- config.write(configfile)
- if __name__ == '__main__':
- app = QApplication(sys.argv)
- app.setStyle(QStyleFactory.create('Fusion'))
- win = Window()
- win.show()
- sys.exit(app.exec())
复制代码 |