распечатать файл с определенным расширением - PullRequest
0 голосов
/ 22 февраля 2020

Я хочу напечатать файл, выбранный с помощью средства выбора файлов (или каким-либо другим способом) с определенным расширением, чтобы PyQt или принтер автоматически распознал формат (например, pdf, ms word, excel, txt, html, jpg et c.)

До сих пор я нашел здесь , как распечатать содержимое TextEdit, но я хотел бы для печати файлов в различных форматах.

Возможно ли это с помощью PyQt5 или мне нужно искать в другом месте?

1 Ответ

1 голос
/ 26 февраля 2020

Для печати простого текстового документа не требуется средство просмотра , поскольку функция print_() фактически вызывает функцию print_() внутреннего QDocument:

filePath, filter = QFileDialog.getOpenFileName(self, 'Open file', '', 'Text (*.txt)')
if not filePath:
    return
doc = QtGui.QTextDocument()
try:
    with open(filePath, 'r') as txtFile:
        doc.setPlainText(txtFile.read())
    printer = QtPrintSupport.QPrinter(QtPrintSupport.QPrinter.HighResolution)
    if not QtPrintSupport.QPrintDialog(printer, self).exec_():
        return
    doc.print_(printer)
except Exception as e:
    print('Error trying to print: {}'.format(e))

Возможно, вы захотите добавить некоторые функциональные возможности для установки размера страницы, полей документа, размеров шрифта и т. Д. c, перед фактической печатью (просто прочитайте документы QTextDocument), я оставлю это вам.


Печать из файлов html практически аналогична, но вам нужно будет использовать класс QWebEnginePage из QtWebEngineWidgets. Смотрите этот ответ .
Делайте не используйте QTextDocument.setHtml(), так как Qt имеет ограниченную поддержку html тегов.

То же самое верно для файлов PDF Кроме того, разница заключается в том, что файл должен быть загружен через setUrl(), а параметр QWebEngineSettings.PluginsEnabled должен быть включен через page.settings().setAttribute(setting, bool) в случае это не так.
Прочитайте документацию о Просмотр файлов PDF .


Печать изображений можно выполнить двумя способами.

Первый и более простой способ создать временный файл html, который встраивает изображение и загружает его на страницу веб-двигателя, как описано выше (вы можете добавить элементы управления для масштабирования / масштабирования).

В качестве альтернативы, вы можете напрямую печатать с использованием QPainter, но вы должны соотноситься с разрешением принтера и размером изображения, поэтому, возможно, вы захотите иметь диалоговое окно предварительного просмотра перед фактической печатью изображения, в противном случае оно может быть слишком маленьким (или слишком большим).

Хотя сложнее, чем равнина <html><img src=""></html>, это позволяет лучший контроль над расположением и размером изображения [s].

class ImagePrintPreview(QtWidgets.QDialog):
    def __init__(self, parent, printer, pixmap):
        super().__init__(parent)

        self.printer = printer
        self.pixmap = pixmap

        layout = QtWidgets.QGridLayout(self)

        self.viewer = QtWidgets.QLabel()
        layout.addWidget(self.viewer, 0, 0, 1, 2)

        self.resoCombo = QtWidgets.QComboBox()
        layout.addWidget(self.resoCombo, 1, 0)

        self.zoom = QtWidgets.QSpinBox(minimum=50, maximum=200, suffix='%')
        self.zoom.setValue(100)
        self.zoom.setAccelerated(True)
        layout.addWidget(self.zoom, 1, 1)
        self.zoom.valueChanged.connect(self.updatePreview)

        self.buttonBox = QtWidgets.QDialogButtonBox(
            QtWidgets.QDialogButtonBox.Ok|QtWidgets.QDialogButtonBox.Cancel)
        layout.addWidget(self.buttonBox)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

        default = printer.resolution()
        self.resoCombo.addItem(str(default), default)
        for dpi in (150, 300, 600, 1200):
            if dpi == default:
                continue
            self.resoCombo.addItem(str(dpi), dpi)
        self.resoCombo.currentIndexChanged.connect(self.updatePreview)

        self.updatePreview()

    def updatePreview(self):
        # create a preview to show how the image will be printed
        self.printer.setResolution(self.resoCombo.currentData())
        paperRect = self.printer.paperRect(self.printer.DevicePixel)
        printRect = self.printer.pageRect(self.printer.DevicePixel)

        # a temporary pixmap that will use the printer's page size
        # note that page/paper are QRectF, they have a QSizeF which has to
        # be converted to a QSize
        pm = QtGui.QPixmap(paperRect.size().toSize())
        # new pixmap have allocated memory for their contents, which usually
        # result in some random pixels, just fill it with white
        pm.fill(QtCore.Qt.white)
        # start a qpainter on the pixmap
        qp = QtGui.QPainter(pm)
        # scale the pixmap to the wanted zoom value
        zoom = self.zoom.value() * .01
        scaled = self.pixmap.scaledToWidth(int(self.pixmap.width() * zoom), QtCore.Qt.SmoothTransformation)
        # paint the pixmap aligned to the printing margins
        qp.drawPixmap(printRect.topLeft(), scaled)

        # other possible alternatives:

        # Center the image:
        #   qp.translate(printRect.center())
        #   delta = QtCore.QPointF(scaled.rect().center())
        #   qp.drawPixmap(-delta, scaled)

        # To also rotate 90° clockwise, add this to the above:
        #   qp.rotate(90)
        # *after* qp.translate() and before qp.drawPixmap()


        # when painting to a non QWidget device, you always have to end the
        # painter before being able to use it
        qp.end()
        # scale the temporary pixmap to a fixed width
        self.viewer.setPixmap(pm.scaledToWidth(300, QtCore.Qt.SmoothTransformation))

    def exec_(self):
        if super().exec_():
            self.printer.setResolution(self.resoCombo.currentData())
            # do the same as above, but paint directly on the printer device
            printRect = self.printer.pageRect(self.printer.DevicePixel)
            qp = QtGui.QPainter(self.printer)
            zoom = self.zoom.value() * .01
            scaled = self.pixmap.scaledToWidth(int(self.pixmap.width() * zoom), QtCore.Qt.SmoothTransformation)
            qp.drawPixmap(printRect.topLeft(), scaled)
            # as above, that's important!
            qp.end()


class ImagePrinter(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        layout = QtWidgets.QVBoxLayout(self)
        selBtn = QtWidgets.QPushButton('Open image')
        layout.addWidget(selBtn)
        selBtn.clicked.connect(self.selectFile)

    def selectFile(self):
        filePath, filter = QtWidgets.QFileDialog.getOpenFileName(self, 'Open file', '/tmp', 'Images (*.jpg *.png)')
        if not filePath:
            return
        pixmap = QtGui.QPixmap(filePath)
        if pixmap.isNull():
            return

        printer = QtPrintSupport.QPrinter(QtPrintSupport.QPrinter.HighResolution)
        if QtPrintSupport.QPrintDialog(printer, self).exec_():
            ImagePrintPreview(self, printer, pixmap).exec_()

Обратите внимание, что я не смог проверить это в windows, поэтому может потребоваться изменить параметры, связанные с разрешением ( возможно с использованием printer.supportedResolutions()).


Как уже объяснялось в комментариях, для печати в других (и, возможно, проприетарных) форматах требуются внешние модули.

...