Home > Software design >  Qt: Set background image on QTextDocument using HTML to generate pdf file
Qt: Set background image on QTextDocument using HTML to generate pdf file

Time:02-18

i am wrapping my head in this problem for a few time. I need to create a report by creating a pdf file with some data on it. So my plan was to instead of using the QTextCursor, i use HTML CSS to create the content in my pdf file. Unfortunately I can't go with the QWebEngine widgets solution because I am compiling into MinGW and setting the MVSC 2017 environment is a huge mess. Sadly i have to go with the QTextDocument and his HTML subset support.

My problem is I can't put a background image in my pdf file. I want to put this image as a background image: blue-gradient-background.jpg

What make me crazy is that I use the css property to display a background image in my pdf file.

background-image: url(:/images/blue-gradient-background.jpg);

And it seems that Qt is taking this into account but it still don't display the background.

Have a look: file.JPG

The first pdf file don't contain the css property background image on the html content but the second does and you can see that the size of the file is bigger so it has considered the css property. But it hasn't displayed the background: two_report.JPG On the left is the first file and on the right is the second file with the css property.

I use a html file in the ressource to generate the report :

<!DOCTYPE html>
<html>
  <style>

    body {
      background-image: url(:/images/blue-gradient-background.jpg);
    }

    h1 {
      color: blue;
    }
    
    #table-content {

    }
    
    #table-content table {
        margin: 1em    
    }
    
  </style>

  <body>
    <div align="center"><h1>[title-template]</h1></div>
    
    <div align="center" id="table-content">[table-template]</div>
    
  </body>
</html>

This html file is open and read in the constructor of the class:

FileEditor::FileEditor()
{
    QFile htmlTemplate(":/html/report.html");
    if (htmlTemplate.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        QTextStream in(&htmlTemplate);
        m_reportPageHTMLTemplate = in.readAll();
    }

}

Then i use a custom class with this function that use QPrinter and QPainter to write the data:

void FileEditor::writeReportPdfFile(const QString &i_path, const S12xConf &i_s12xConf, const S12xData &i_s12xData, const BenchTestData &i_benchTestData)
{
    QDir directory(i_path); // we create a QDir with the path
    if (!directory.exists()) // if the directory does not exist then
    {
        directory.mkpath("."); // we create the path
    }

    QString fileName = getCurrentHourDate()   "_S12xNG_Test_Report.pdf";

    QPrinter pdfPrinter(QPrinter::HighResolution);
    pdfPrinter.setOutputFormat(QPrinter::PdfFormat);
    pdfPrinter.setPageSize(QPageSize(QPageSize::A4));
    pdfPrinter.setOutputFileName(i_path   "/"   fileName);
    pdfPrinter.setFullPage(true);
    QPainter painter(&pdfPrinter);
    painter.setBackgroundMode(Qt::OpaqueMode);

    QTextDocument measuresDoc;
    QTextDocument averagesDoc;
    QTextDocument inOutDoc;
    measuresDoc.documentLayout()->setPaintDevice(&pdfPrinter);
    measuresDoc.setPageSize(pdfPrinter.pageRect().size());
    averagesDoc.documentLayout()->setPaintDevice(&pdfPrinter);
    averagesDoc.setPageSize(pdfPrinter.pageRect().size());
    inOutDoc.documentLayout()->setPaintDevice(&pdfPrinter);
    inOutDoc.setPageSize(pdfPrinter.pageRect().size());
    setMeasuresTextDocument(&measuresDoc);
    setAveragesTextDocument(&averagesDoc);
    setInputsOutputsTextDocument(&inOutDoc);

    measuresDoc.drawContents(&painter); // We print TextDocument of the Measures into the document
    pdfPrinter.newPage(); // We inject the current page and continue printing on new page
    averagesDoc.drawContents(&painter); // We print the TextDocument of the Averages into the document
    pdfPrinter.newPage(); // We inject the current page and continue printing on new page
    inOutDoc.drawContents(&painter); // We print the TextDocument of the Inputs/Outputs into the document

    measuresDoc.undo();
    averagesDoc.undo();
    inOutDoc.undo();

}

Here is the function to add the html data into the measures QTextDocument:

void FileEditor::setMeasuresTextDocument(QTextDocument *o_measuresDoc)
{
    QString htmlContent = m_reportPageHTMLTemplate;
    htmlContent.replace("[title-template]","I. Measures Data");
    o_measuresDoc->setHtml(htmlContent);
}

So what i am doing wrong? Thanks in advance for your responses.

CodePudding user response:

I have found the answer!

it is about the drawContents method of QTextDocument. There is a second parameter that you need to add in order to see the background image in your document. It's the a QRectF object that represend the size of the rect that the background image will be clipped into.

void QTextDocument::drawContents(QPainter *p, const QRectF &rect = QRectF()) Draws the content of the document with painter p, clipped to rect. If rect is a null rectangle (default) then the document is painted unclipped.

So what I did is:

easuresDoc.drawContents(&painter, pdfPrinter.paperRect()); // We print TextDocument of the Measures into the document
pdfPrinter.newPage(); // We inject the current page and continue printing on new page
averagesDoc.drawContents(&painter, pdfPrinter.paperRect()); // We print the TextDocument of the Averages into the document
pdfPrinter.newPage(); // We inject the current page and continue printing on new page
inOutDoc.drawContents(&painter, pdfPrinter.paperRect()); // We print the TextDocument of the Inputs/Outputs into the document

pdfPrinter.paperRect is the rectangle of the page without the margin.

Also if you want the background image to be printed scaled with no repeat than you need to put the printer into QPrinter::PrinterResolution

QPrinter pdfPrinter(QPrinter::PrinterResolution);

  • Related