Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set QTextDocument margins and other properties (setHTML, print to pdf)?

I have the following certificate class for producing pdf document out of some images and data. After setting image sources, I call generate() function and get test.pdf output file. The document is created based on QTextDocument class using setHtml(html) method.

The problem is that I have huge white spaces around the document, while I want the title 'REPORT' with logo image to be on the very top of the page. I would also like to add lower border to the table, but as I understand it is not supported by Qt (Supported HTML Subset).

Python3 code:

class certificate:

def __init__(self):
    self.logo = None
    pdffile = 'test.pdf'
    self.histogram = None
    self.printer = QPrinter()
    self.printer.setPageSize(QPrinter.Letter)
    self.printer.setOutputFormat(QPrinter.PdfFormat)
    self.printer.setOutputFileName(pdffile)

def generate(self):
    document = QTextDocument()
    html = ""
    html += ('<head><title>Report</title><style></style></head>'
                 '<body><table width="100%"><tr>'
                    '<td><img src="{}" width="30"></td>'
                    '<td><h1>REPORT</h1></td>'
                 '</tr></table>'
                 '<p align=right><img src="{}" width="300"></p>'
                 '<p align=right>Sample</p></body>').format(self.logo, self.histogram)
    document.setHtml(html)
    document.print_(self.printer)

I never extensively used html before and never worked with QTextDocument, and would appreciate any advice on how to control document margins and table properties.

Other related property I want to control is resolution - I use pixel image size and need to know page and margin sizes in pixels.

EDITED: The question is almost answered by @mata. I can set now any margins and resolution, but do not understand how to control image and font sizes. E.g. if I need that an image is always 50mm wide, and html header and main text font sizes are visually the same - how to implement it?

EDITED2: The last part is solved too. Here is modified code by @mata, it gives the same result for any dpi value:

dpi=96

document = QTextDocument()
html = """
<head>
    <title>Report</title>
    <style>
    </style>
</head>
<body>
    <table width="100%">
        <tr>
            <td><img src="{0}" width="{1}"></td>
            <td><h1>REPORT</h1></td>
        </tr>
    </table>
    <hr>
    <p align=right><img src="{2}" width="{3}"></p>
    <p align=right>Sample</p>
</body>
""".format('D:\Documents\IST Projects\diashape\docbook\Installation\images\istlogo_medium.png',
              40*dpi/96, 
              'D:\Documents\IST Projects\diashape\docbook\Installation\images\istlogo_medium.png', 
              200*dpi/96)

document.setHtml(html)

printer = QPrinter()
font = QFont()
font.setPointSize(12*dpi/96)
document.setDefaultFont(font)
printer.setResolution(dpi)
...
like image 749
Ekaterina Mishina Avatar asked Feb 02 '23 05:02

Ekaterina Mishina


1 Answers

You can specify what resolution you want to use in the constructor when you create the QPrinter. Then after you've set the pagesize, you can use width, height and resolution on the printer to fint out that values, here's what I got for Letter (dpi-values can be different, they depend on the screen or the printer):

QPrinter(QPrinter.ScreenResolution)   #   96dpi,  752x992
QPrinter(QPrinter.PrinterResolution)  #   72dpi,  564x744
QPrinter(QPrinter.HighResolution)     # 1200dpi, 9400x12400

You can also set the dpi directly using setResolution. The size returned by width and height is the page size (same as pageRect().size()), which ist not the same as the paper size - as the page also has margins, which you can set like this:

printer.setPageMargins(12, 16, 12, 20, QPrinter.Millimeter)

this sets left and right margins to 12mm, top to 16mm and bottom to 20mm - just for example, if you want less white space you can obviously just use smaller values. And you should set the document size to the size of the resulting size:

document.setPageSize(QSizeF(printer.pageRect().size()))

as you've noticed yourself, the subset of html and css allowed is very limited, specially for formatting tables. But instead of using a lower border on the table you could just use a hr, which probably will look like you want it. At least it doesn't look that bad if I test it like this:

from PyQt4.QtGui import *
from PyQt4.QtCore import *

a=QApplication([])
document = QTextDocument()
html = """
<head>
    <title>Report</title>
    <style>
    </style>
</head>
<body>
    <table width="100%">
        <tr>
            <td><img src="{}" width="30"></td>
            <td><h1>REPORT</h1></td>
        </tr>
    </table>
    <hr>
    <p align=right><img src="{}" width="300"></p>
    <p align=right>Sample</p>
</body>
""".format('', '')

document.setHtml(html)

printer = QPrinter()
printer.setResolution(96)
printer.setPageSize(QPrinter.Letter)
printer.setOutputFormat(QPrinter.PdfFormat)
printer.setOutputFileName("test.pdf")
printer.setPageMargins(12, 16, 12, 20, QPrinter.Millimeter)
document.setPageSize(QSizeF(printer.pageRect().size()))
print(document.pageSize(), printer.resolution(), printer.pageRect())

document.print_(printer)
like image 194
mata Avatar answered Mar 08 '23 23:03

mata