[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())