Saelyth
Saelyth

Reputation: 1734

PDF output not working with Pyqt5 and Python 3.5

I've tested at least 20 different workarounds for this.

I want to print a widget.

My widget is an Invoice and it have inside a lot of other widgets like QLineEdits, QLabels with text, QLabels that act as images, QDropDown menus, etc. This is a Screenshot (all data inside like the N.I.F are temporary placeholders for a real business):

My invoice

So it should be easy, right? It does not seem so.

  1. First I tried to sent it to Printers, and that alone was a very hard job dealing with lot of different printing specific options. After all my research I found QPrintDialog deals with most of the stuff
  2. After testing that for a while I noticed it grabs the widget quite fine, but it prints it to a very tiny section, so after much research I found a way to scale that, this is what I ended up with.

Code:

def print_as_pdf(widgettoprint):
    # Printer
    printer = QPrinter()
    setupdialog = QPrintDialog(printer, widgettoprint)
    if setupdialog.exec() == QPrintDialog.Accepted:
        # Renderer
        painter = QPainter(printer)
        painter.begin(printer)
        # Scale it
        xscale = printer.pageRect().width() / widgettoprint.width()
        yscale = printer.pageRect().height() / widgettoprint.height()
        scale = min(xscale, yscale)
        painter.translate(printer.paperRect().x() + printer.pageRect().width() / 2,
                          printer.paperRect().y() + printer.pageRect().height() / 2)
        painter.scale(scale, scale)
        painter.translate(-1 * widgettoprint.width() / 2, -1 * widgettoprint.height() / 2)
        widgettoprint.render(painter)
        painter.end()
        return True
    else:
        return False

It does the trick, it prints an entire A4 page as intended, but the quality of the texts is quite bad. I found out it just takes an screenshot of it instead of saving the data as text or vector data.

So that wouldn't work for me, but I had to try. I tried to print as PDF with the same method (choosing PDF as a printer) and it just generates a PDF with an screenshot on it. I can't select or copy the text data.

  1. So I researched for alternatives. I found about Reportlab but couldn't make it work. I also tried PyFPDF, but especifically creating a PDF without choosing a printer would break the ability to actually print the invoice to a different printer.
  2. Okay, days of frustration spent trying to find alternatives without rebuilding from scratch my 7000 lines of code program. I found this blog about jinja2 and qt workaround and decided to give it a try. Re-creating the entire invoice as an HTML template would be a fair amount of work (as there is a lot more different invoices, not just this one). But a new problem arises, PyQt5 doesn't have QtWebKit or QWebView, and as far as I could get was to print a white empty PDF with this code and QtWebEngine:

Code:

import os
from jinja2 import Environment, FileSystemLoader
from PyQt5 import QtWebEngineWidgets
from PyQt5.QtPrintSupport import QPrinter, QPrintDialog
from PyQt5.QtGui import QPainter

PATH = os.path.dirname(os.path.abspath(__file__))
TEMPLATE_ENVIRONMENT = Environment(
    autoescape=False,
    loader=FileSystemLoader(os.path.join(PATH, 'userfiles/templates')),
    trim_blocks=False)

def render_template(template_filename, context):
    return TEMPLATE_ENVIRONMENT.get_template(template_filename).render(context)

def test():
    something = ['something1', 'something2', 'something3']
    context = {
        'something': something,
        'invoicenumber': "17012"
    }
    # Generate the HTML data with the template without creating a file, on-the-fly
    html = render_template('invoices.html', context)

    # add html to a webengine/widget
    web = QtWebEngineWidgets.QWebEngineView()
    web.page().setHtml(html)

    # Print that widget
    printer = QPrinter()
    setupdialog = QPrintDialog(printer)
    if setupdialog.exec() == QPrintDialog.Accepted:
        web.render(printer)
        print("done")

test()

Where the HTML template is:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <title>Factura {{ invoicenumber }}</title>
</head>
<body>
<center>
    <h1>Factura {{ invoicenumber }}</h1>
    <p>{{ something|length }} something</p>
</center>
<ol align="left">
{{ something[0] }}
{{ something[1] }}
{{ something[2] }}
</ol>
</body>
</html>

I will probably spend more weeks and months trying to make that works. Printing is something that I though it should had been really easy, as every random program in the market seems to be able to print or create PDFs, but it's now for me the worst part of my programming learning experience.

The goal: This question aims to find a permanent solution to my problem: how to print to a selectable (windows platform) printer my invoice widget? And then, if PDF printer is chosen, print it with endless quality, using vectors or anything that is just don't create an screenshot.

I'd also appreciate explanations of what I am doing wrong as I'm still learning (both programming, Python and Qt).

Upvotes: 2

Views: 3417

Answers (1)

Colonder
Colonder

Reputation: 1576

Although I myself program in python, I have little knowledge about programming GUI in it. However, I found several questions and sites that can be a starting point to your own implementation. I know some of these are QT4 but please, have a look at them, I believe that things didn't change so much (but I can be wrong):
Pyqt take screenshot of certain screen area
Screenshot of a window using python
QT documentation Screenshot example
https://github.com/Python-Devs-Brasil/PyQt5-Tutorials/blob/master/Post-2(QtCore)/screenshot.py
https://github.com/baoboa/pyqt5/blob/master/examples/desktop/screenshot.py
How to grab a desktop screenshot with PyQt?

EDIT
Have you tried saving to a pdf file via matplotlib?
https://pythonspot.com/en/matplotlib-save-figure-to-image-file/
saving images in python at a very high quality

EDIT 2
Also, have a look at this
Create a pdf with fillable fields python

EDIT 3
You can also have a look at documentations and examples of libraries mentioned in this question
Python PDF library

Upvotes: 1

Related Questions