Reputation: 3642
I'd like to print pdf
document to a printer. So far, I have this code.
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
I don't know how to continue in the TODO
section.
Upvotes: 3
Views: 5518
Reputation: 27106
One possibility would be to use pdf2image which is
A python (3.5+) module that wraps pdftoppm and pdftocairo to convert PDF to a PIL Image object
see https://pypi.org/project/pdf2image/
Under the link above you will find installation instructions for poppler, which is a dependency of the module.
Steps
A simple version of the code would look like this:
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()
The second parameter of convert_from_path describes the output resolution in dpi. The target rectangle in the device coordinate system can be determined by calling viewport on the QPainter instance. Finally, the image can then be smoothly scaled to the target rectangle using a bilinear filter algorithm.
Self-contained Sample Program
I have slightly modified your code and created a completely self-contained example.
Topics such as paper sizes, resolutions, optimization regarding memory requirements and error handling etc. are not handled. The intention is rather to give a minimal example.
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_())
Upvotes: 2