【问题标题】:Print pdf document in PyQt5在 PyQt5 中打印 pdf 文档
【发布时间】:2020-06-10 14:29:50
【问题描述】:

我想将pdf 文档打印到打印机。到目前为止,我有这个代码。

def printDialog(self):
        filePath, filter = QFileDialog.getOpenFileName(self, 'Open file', '', 'Text (*.txt);;PDF (*.pdf)')
        if not filePath:
          return
        file_extension = os.path.splitext(filePath)[1]
        if file_extension == ".txt":
            doc = QtGui.QTextDocument()
            try:
                with open(filePath, 'r') as txtFile:
                    doc.setPlainText(txtFile.read())
                printer = QPrinter(QPrinter.HighResolution)
                if not QPrintDialog(printer, self).exec_():
                    return
                doc.print_(printer)
            except Exception as e:
                print('Error trying to print: {}'.format(e))
        elif file_extension == ".pdf":
            printer = QPrintDialog(QPrinter.HighResolution)
            printer.setOutputFormat(QPrinter.PdfFormat)
            printer.setOutputFileName(filePath)
            # TODO
        else:
            pass

我不知道如何继续TODO 部分。

【问题讨论】:

  • 您是否尝试过使用 QWebEnginePage,正如我已经告诉过您的那样两次
  • @musicamante 不,我现在不知道该怎么做。
  • @musicamante 我可以用它打印特定目录中的所有文档(选择多个文档)吗?并观察印刷进度?例如显示带有“printing doc1”、“printing doc2”等的消息框?
  • 在您上一个问题的答案中,我链接到 this 其他解释如何加载和打印 html 内容的答案。正如我告诉你的,只需使用setUrl()。多次打印的答案是肯定的,但只能在你了解如何打印 pdf 文件后,在另一个问题中解决。
  • @musicamante 一开始我尝试了 index.html,但我收到了错误 self._page.print(self._printer, self.print_completed) AttributeError: 'Window' object has no attribute 'print_completed' 。我正在发送带有代码的 pastebin,如果您可以查看它pastebin.com/x582VjRe

标签: python python-3.x windows printing pyqt5


【解决方案1】:

一种可能性是使用 pdf2image

一个 python (3.5+) 模块,包装 pdftoppm 和 pdftocairo 以将 PDF 转换为 PIL Image 对象

https://pypi.org/project/pdf2image/

在上面的链接下,您将找到 poppler 的安装说明,它是模块的依赖项。

步骤

  • PDF 文件已读取
  • 借助pdf2image转换成图片
  • 每个图像都是使用 QPaint 绘制的

代码的简单版本如下所示:

images = convert_from_path(filePath, dpi=300, output_folder=path)
painter = QPainter()
painter.begin(printer)
for i, image in enumerate(images):
    if i > 0:
        printer.newPage()
    rect = painter.viewport()
    qtImage = ImageQt(image)
    qtImageScaled = qtImage.scaled(rect.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
    painter.drawImage(rect, qtImageScaled)
painter.end()

convert_from_path 的第二个参数描述了以 dpi 为单位的输出分辨率。设备坐标系中的目标矩形可以通过调用 QPainter 实例上的 viewport 来确定。最后,可以使用双线性滤波器算法将图像平滑地缩放到目标矩形。

独立的示例程序

我稍微修改了您的代码并创建了一个完全独立的示例。

不处理诸如纸张大小、分辨率、内存要求优化和错误处理等主题。目的是举一个最小的例子。

import os
import sys

from PIL.ImageQt import ImageQt
from PyQt5 import QtWidgets
from PyQt5.QtCore import QSize, Qt
from PyQt5.QtGui import QPainter
from PyQt5.QtPrintSupport import QPrintDialog, QPrinter
from PyQt5.QtWidgets import QMainWindow, QFileDialog, QPushButton
import tempfile

from pdf2image import convert_from_path


class PrintDemo(QMainWindow):

    def __init__(self):
        QMainWindow.__init__(self)

        self.setMinimumSize(QSize(192, 128))
        self.setWindowTitle("Print Demo")

        printButton = QPushButton('Print', self)
        printButton.clicked.connect(self.onPrint)
        printButton.resize(128, 32)
        printButton.move(32, 48)

    def onPrint(self):
        self.printDialog()

    def printDialog(self):
        filePath, filter = QFileDialog.getOpenFileName(self, 'Open file', '', 'PDF (*.pdf)')
        if not filePath:
            return
        file_extension = os.path.splitext(filePath)[1]

        if file_extension == ".pdf":
            printer = QPrinter(QPrinter.HighResolution)
            dialog = QPrintDialog(printer, self)
            if dialog.exec_() == QPrintDialog.Accepted:
                with tempfile.TemporaryDirectory() as path:
                    images = convert_from_path(filePath, dpi=300, output_folder=path)
                    painter = QPainter()
                    painter.begin(printer)
                    for i, image in enumerate(images):
                        if i > 0:
                            printer.newPage()
                        rect = painter.viewport()
                        qtImage = ImageQt(image)
                        qtImageScaled = qtImage.scaled(rect.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
                        painter.drawImage(rect, qtImageScaled)
                    painter.end()
        else:
            pass


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    mainWin = PrintDemo()
    mainWin.show()
    sys.exit(app.exec_())

【讨论】:

  • 谢谢。它可以转换成更大的图像吗?如何保持大小,与输入 pdf 相同?
  • 我注意到我可以将第二个参数添加到 convert_from_bytes,dpi。但不知道保留pdf大小的正确值是什么。
  • 还有一个尺寸参数yet,但是不知道尺寸合适。
  • dpi 参数决定了 PDF 到图像转换的质量。为了填充整个页面,设备坐标系中的目标矩形可以通过调用painter上的viewport来确定。然后可以使用双线性滤波器算法将图像平滑地缩放到目标矩形。我已经相应地更新了答案和示例代码。
  • 在页面底部pypi.org/project/pdf2image 写着:一个相对较大的 PDF 文件会耗尽你所有的内存并导致进程中止(除非你使用输出文件夹)。 我已经更新了使用输出文件夹变体的答案。您还可以在此链接下找到更多性能提示。
猜你喜欢
  • 2016-10-09
  • 2015-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-12
  • 1970-01-01
  • 2021-01-05
  • 2019-08-15
相关资源
最近更新 更多