QPrinter unable to style HTML page properly to render image in PDF document
Asked Answered
M

2

6

I want to create a PDF document with properly styled HTML. This is what I am trying:

QTextDocument *doc = new QTextDocument();
const char* s1 = "<html><head><style>body { font-family: sans-serif;}.note-atomic { background: rgb(242,242,242); width: 1000px; margin: 5px auto; border: 1px solid grey; border-radius: 8px;padding: 5px;}</style></head><body><div class = 'note-atomic'>Hi</div><img src = '/Users/attitude/Desktop/RnSghvV.png' width='400' height='300' /></body></html>";
doc->setHtml(QString::fromStdString(s1));

QPrinter *printer = new QPrinter();
printer->setOutputFileName("/Users/attitude/Desktop/fool.pdf");
printer->setOutputFormat(QPrinter::PdfFormat);

QPainter *painter = new QPainter();
painter->begin( printer );
doc->drawContents(painter, printer->pageRect().translated( -printer->pageRect().x(), -    printer->pageRect().y() ));
doc->print(printer);

const char* s2 = "<html><body><div>Bye</div></body></html>";
doc->setHtml(QString::fromStdString(s2));

printer->newPage();
doc->drawContents(painter, printer->pageRect().translated( -printer->pageRect().x(), - printer->pageRect().y() ));

doc->print(printer);
painter->end();

I expect the PDF to have 2 pages - first one with text Hi, and the next and last one with text Bye. And the first page styled like it appears in a HTML page with the same markup:

enter image description here

However, the first page of the PDF comes up with content completely messed up:

enter image description here

How do I make it look as expected?

The image I am trying in the HTML doc: https://i.sstatic.net/2I3aG.jpg

Platform - Qt 5.3.1, 32 bit. OS X Yosemite.

Medicable answered 1/2, 2016 at 19:16 Comment(1)
This is to award the answer by @timocov a promised bounty. No new answer is needed!Medicable
O
5

This is QTextDocument. It rendered rich text (it is not HTML + CSS).

Available properties and elements you may check on http://doc.qt.io/qt-5/richtext-html-subset.html (for example there is no css property border for p or div).

Also you can see how it looks in Qt Designer, if you put your html code into QTextEdit.

For rendering HTML you can use QWebView (http://doc.qt.io/qt-5/qwebframe.html#print)

webview->mainFrame()->print(printer);

Onus answered 6/2, 2016 at 23:35 Comment(3)
I tried it as you said. I am getting a blank pdf. By the way it should be webview->page()->mainFrame()->print(printer);...Medicable
Hmm this works, content is loded asynchronously, hence I have to wait for the loadFinished signal and do the printing in a slot. I have one more minor problem, no matter what I try, Qprinter breaks the pages. How do I ensure that there is only a single long page where all the content is dumped, instead of the pages breaking after every A4 size interval?Medicable
Never mind, I got it fixed. Apologies, this answer should have been given the bounty. I am currently broke, hence cannot offer any more bounty. When I will be rich again, I will offer this answer a generous bounty.. :)Medicable
P
2

QTextDocument is not a web browser. It won't go fetching networked URLs for you. You need to add a QVariant QTextDocument::loadResource(int type, const QUrl & name) method to your QObject (QWidget is-a QObject!), and make the QTextDocument a child of that object. The document instance will the invoke your implementation of loadResource, where you can leverage the QNetworkAccessManager to do the fetching.

For this to have any chance of being user-friendly, you cannot block on network requests. This is accomplished by doing the processing twice. First simply take note of what URLs are to be loaded and initiate their fetching, returning an empty QVariant. Once all network requests are completed successfully and you've stored them in a cache, you can re-run the same code and it'll correctly render the page and won't block for network access.

All of this has to be done asynchronously.

Pearsall answered 2/2, 2016 at 14:9 Comment(4)
Umm, no, no. In the code I was doing it by loading the image from disk only. I gave it just so that anybody can see the URL immediately. Changing the code. The current code is what I have actually tried and got the said result. Thanks.Medicable
@AttitudeMonger Your html doesn't use valid URLs now. Furthermore, once you fix it up to use valid file URLs, ensure that they are absolute paths.Exhilarative
Oh okay. They were there in the same place as the executable. I even tried giving absolute path like the newly edited question. Same result.Medicable
The path to the image was indeed incorrect. Now image is coming fine, but still the layout is messed up. Edited question.Medicable

© 2022 - 2024 — McMap. All rights reserved.