Printing html using QWebEngineView fails (PyQt5)
-
wrote on 3 May 2020, 13:38 last edited by Koenux 5 Mar 2020, 13:40
Hello everyone,
I'm trying to get print html code which is generated by my application, but unfortunately I can't get it to work.
The print preview shows the page but the quality looks bad, all I get is a corrupted PDF file and it is kinda slow. I had it working for years with PyQt4.x.The code where I call my printer class:
def _print(self, preview=False, PDF=False): if(not self.printer.readyState): print('printer class not ready yet.') return; tpl = '<html><head></head><body>Test</body></html>'; self.printer.load(); self.printer.forceLandscape = True; self.printer.fontfamily = str(self.cfg.value('fontsettings_0_font')) self.printer.fontsize = str(self.cfg.value('fontsettings_0_size')) self.printer.preview = preview; self.printer.pdf = PDF; self.printer.setHtml(tpl); self.printer.print();
The printer class (printer.py)
from typing import List try: import sys, os, locale, subprocess from PyQt5.QtGui import * from PyQt5.QtCore import * from PyQt5.QtNetwork import * from PyQt5.QtPrintSupport import QPrinter, QPrintPreviewDialog, QPrintDialog from PyQt5 import QtSql, QtGui from PyQt5.QtWidgets import QWidget, QDialog, QTextEdit from PyQt5.QtWebEngineWidgets import QWebEngineView,QWebEnginePage,QWebEngineSettings except ImportError as msg: print("Exception: Couldn't import all required modules:\n-> ImportError: ", msg) sys.exit() locale.setlocale(locale.LC_ALL, '') locale.setlocale(locale.LC_NUMERIC, '') class printer(QWidget): # Initialize printer class def __init__(self, parent=None): QWidget.__init__(self); self.parent = parent; self.pagecounter=-1; self.html=""; self.preview="" self.m_page = None self.m_inPrintPreview = False self.page = QWebEnginePage(); self.progress = 0; self.waiting = False; # tasklist self.readyState = True; self.defaultPageMargins=[float(self.parent.cfg.value('page_margin_rawdec_left')) \ , float(self.parent.cfg.value('page_margin_rawdec_top')) \ , float(self.parent.cfg.value('page_margin_rawdec_right')) \ , float(self.parent.cfg.value('page_margin_rawdec_bottom')) \ , int(self.parent.cfg.value('page_margin_rawdec_unit'))]; def setPageMargins(self,a,b,c,d,e): self.pageMargins=[a,b,c,d,e]; # Load printer for new job def load(self): self.fontfamily='Sans' self.fontsize='12' self.progress = 0; self.pages = []; self.pagecounter=-1; self.forceLandscape=False; self.pageMargins=self.defaultPageMargins; def readyTask(self): self.readyState = True; def pageSetup(self): ps = QPageSetupDialog(self.printer,self.doc); ps.open(); def openPDF(self, filename="output.pdf"): if os.name == 'mac': subprocess.call(['open', filename]) elif os.name == 'nt': subprocess.call(['start', filename], shell=True) elif os.name == 'posix': subprocess.call(['xdg-open', filename]) def setHtml(self, html): self.page.setHtml(html) def pageloaded(self): print('webviewloaded') if(self.waiting): self.waiting = False; return self.print(); def pageprogress(self,progress): print(progress) self.progress = progress; @property def page(self): return self.m_page @page.setter def page(self, page): if isinstance(page, QWebEnginePage): self.m_page = page self.page.printRequested.connect(self.printPreview) self.page.loadFinished.connect(self.pageloaded) self.page.loadProgress.connect(self.pageprogress); else: raise TypeError("page must be a QWebEnginePage") def getPrinter(self): pm = self.pageMargins; printer = QPrinter(QPrinter.HighResolution) printer.setPageSize(QPrinter.A4); printer.setFullPage (True); # must be before set margin printer.setPageMargins(pm[0],pm[1],pm[2],pm[3], pm[4]); # Landscape or Portraitself.webview.show(); if self.forceLandscape: printer.setOrientation(QPrinter.Landscape); self.forceLandscape=False; else: printer.setOrientation(QPrinter.Portrait); return printer; @pyqtSlot() def print(self): if(self.progress is not 100): self.waiting = True; print('waiting...') print(self.progress) return; print('ok') if(self.preview): return self.printPreview(); printer = self.getPrinter(); # PDF tmpfile=None; if(self.pdf): tmpfile = QTemporaryFile(); if(tmpfile.open()): print(tmpfile) printer.setOutputFormat(QPrinter.PdfFormat) printer.setOutputFileName(tmpfile.fileName()) return self.printDocument(printer,tmpfile) else: debug().critical("NoesAdmin printer.py couldn't open a temporary file.") return False; # Print dialog dialog = QPrintDialog(printer, self.page.view()) if dialog.exec_() != QDialog.Accepted: self.readyTask(); return self.printDocument(printer, tmpfile) @pyqtSlot() def printPreview(self): if self.page is None: return if self.m_inPrintPreview: return self.m_inPrintPreview = True printer = self.getPrinter(); preview = QPrintPreviewDialog(printer,self.page.view()) preview.paintRequested.connect(self.printDocument); if preview.exec_() != QDialog.Accepted: self.readyTask(); self.m_inPrintPreview = False @pyqtSlot(QPrinter) def printDocument(self, printer, tmpfile=None): result = False loop = QEventLoop() self.parent.changeStatusBar('Printjob loading...'); def printPreview(sucess): nonlocal result result = sucess loop.quit() self.page.print(printer,printPreview) loop.exec_() if not result: print('no result') painter = QPainter() if painter.begin(printer): font = painter.font() font.setPixelSize(20) painter.setFont(font) painter.drawText(QPointF(10, 25), "Could not generate print preview.") painter.end() self.readyTask(); self.parent.readyStatusBar(); if self.pdf and tmpfile: print('PDF print opening....'); self.openPDF(tmpfile.fileName())
I tried to use QTextDocument as an alternative for QWebEngineView which worked perfectly fine except for the lack of support for modern html and css and I had trouble with the page size, so I rather use webengine if possible.
Does anyone have an idea where it goes wrong? Sorry if the code is a bit messy.
Thanks!
(Qt 5.12.5 - Python 3.7.7)
-
wrote on 4 May 2020, 09:54 last edited by
I've got a bit further than yesterday with this issue. I went back to the example on this website:
http://quabr.com:8182/59438021/how-do-i-create-a-print-preview-of-qwebengineview-in-pyqt5The problem has to do something with:
printer = QPrinter(QPrinter.HighResolution)
When I use QPrinter() without the HighResolution part, everything works as expected. I didn't realise that the example had the same problem since it calls the printPreview method which doesn't have the resolution part.
Is this a bug in (Py)Qt?
Since my problem is fixed, I'm will mark it as solved.
1/2