PDF Query
-
Hi All,
Can anyone recommend the best way to take an existing PDF, embed that in the Qt resources (so it is compiled and unaccessible), then use QPainter to add calculated variables to that PDF, and save a copy of it in a specific location.
For example, if this is my existing (template) PDF:
I'd then like to use variables calculated in my code to fill in the gaps like this:
I know I can use QPdfWriter and QPainter to make the PDF with code, but that would take me way too long for the level of detail in the PDFs I have in mind.
Really appreciate any guidance.
Thanks!
-
Hi
Editing PDF is not really easy. You need a library like
http://podofo.sourceforge.net/
or maybe https://poppler.freedesktop.org/So may i propose another way.
Use SVG files to be the details of the pdf.
It should not be too hard to convert existing pdf to svg using inkscape.Used named markers (ids) to know where to put the generated texts.
and use
https://doc.qt.io/qt-5/qsvgrenderer.html#boundsOnElement
to get its location from within Qt.Then print the SVG to pdf and then print the values on top of it.
Since SVG is vectors the output is crisp no matter page size etc. -
Thanks for this!
So I have used Inkscape to change each page of my PDF into an SVG which is simple and works well.
In the text of my PDF (that I change to SVG) I have placed some markers like this:
Here is the code I have used in a small function to test it works.
void SvgTest() { QSvgRenderer renderer(QString("C:/Temp/testInputSVG.svg")); QPrinter printer; printer.setOutputFormat(QPrinter::PdfFormat); printer.setOutputFileName(QString("C:/Temp/testOuputPDF.pdf")); QPainter painter(&printer); QRectF testRect = renderer.boundsOnElement(QString("{0}")); painter.drawText(testRect, "TEST PRINT - DID THIS WORK?"); renderer.render(&painter); painter.end(); }
This is the output I get:
Maybe I have misunderstood the named markers (ids)?
Thanks again for the help :)
-
Hi,
Why not just generate the PDF on the fly using QPdfWriter ?
Do you even need that template for that document ?
-
@SGaist The example I have shown above is extremely basic. The one I am actually trying to use is significantly more complex with lots of diagrams and mathematical equations.
I have already started using QPDFWriter to write it from scratch within Qt but it is highly impractical. Using this SVG method would be perfect.
@mrjj I have found (by opening the SVG in notepad++) that each item has its own id. Is this what you were referring to as named markers (ids)?
Also, the final PDF size seems to be VERY large. e.g. the SVG is 5KB but the produced PDF is 102KB which is 20x larger.
-
I have found (by opening the SVG in notepad++) that each item has its own id. Is this what you were referring to as named markers (ids)?
Hi. yes. those. That ID can be set directly in Inkscape (via properties, i think) and given good names
instead of those auto generated.
And you can then use that ID,
renderer.boundsOnElement(QString("GoodName"));
to get the a rectangle for the area. perfect for drawing on top of the svg.
Even if scaled. :)
However, Inkscape has inverted y, so check the return value (the rect) to
see what i mean. ( i recall it just worked but just in case )About the size. Yes i wondered that too. I think we rasterize the svg to the page
so hence the size increase. However, they rendered fast and even much larger its still small enough. However, if you generate 1000 pages this way. It might get too heavy. -
@mrjj @SGaist
I have found two main problems with this approach.- Inkscape misses many elements from the original PDF.
- The rendering size for a 15-20 page document is huge.
I have tried to reconsider and change to writing out the PDF in Qt but using HTML with the help of: https://wordtohtml.net/ or https://wordhtml.com/. I have used the following code to get this into my PDF:
//PDF QPdfWriter pdf(location); QPageLayout pdfLayout = QPageLayout( QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(10,10,10,10), QPageLayout::Unit(QPageLayout::Unit::Millimeter)); int pageWidth = pdf.width(); int pageHeight = pdf.height(); //PAINTER QPainter painter; painter.begin(&pdf); //BOX FOR TEXT QRect mainBox = QRect(QPoint(0, 0 + pageHeight * 0.08 + 150), QPoint(pageWidth - 0, pageHeight - 0 - pageHeight * 0.04 - 150)); //QTEXTDOCUMENT QTextDocument td; td.setPageSize(QSize(pageWidth, pageHeight)); td.documentLayout()->setPaintDevice(&pdf); //SET HTML TEXT td.setHtml("<p>INSERT TEXT AS HTML HERE</p>"); //DRAW TD CONTENTS TO PDF td.drawContents(&painter, mainBox);
This works, however, when I am using my laptop, the text comes onto the PDF very small. When I hook it up to the monitor, the text comes out really big. Do you know why this is and how I can make the text size consistent regardless of the screen I am using?
Thank you
EDIT: I have found that the difference between the two screens is this setting:
EDIT2: I have tried the following but it still does not work. Small text in the PDF with 150% scaling and Large text in the PDF with 100% scaling.
QApplication::setAttribute(Qt::AA_Use96Dpi); QApplication a(argc, argv); a.setAttribute(Qt::AA_Use96Dpi);
I even set Qt::AA_Use96Dpi before AND after instantiating the QApplication.
Thanks again :)
-
I have now found a solution (can't see any issues with it yet)
Initial - Set up the printer and painter
//PDF QPdfWriter pdf(location); QPageLayout pdfLayout = QPageLayout( QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(10,10,10,10), QPageLayout::Unit(QPageLayout::Unit::Millimeter)); int pageWidth = pdf.width(); int pageHeight = pdf.height(); //PAINTER QPainter painter; painter.begin(&pdf);
1st - Get the screen resolution and determine a scale factor from the screenresolution to 96dpi
//identify the resolution of the screen QPrinter screenPrinter(QPrinter::ScreenResolution); int screenResolution = screenPrinter.resolution(); //set a scale factor based on 96dpi int defaultResolution = 96; double scaleFactor = double(screenResolution)/double(defaultResolution);
2nd - Initialise the QTextDocument, set the paint device and the page size. NOTE THE SCALE FACTOR.
//set up the HTML writing QTextDocument QTextDocument td; td.documentLayout()->setPaintDevice(&pdf); td.setPageSize(QSize(pageWidth/scaleFactor, pageHeight/scaleFactor));
3rd - Use the painter to draw text normally if needed e.g.
painter.drawText(QPoint(500, 500), QString("You can insert text like this"));
4th - Write text using QTextDocument - SCALE THE PAINTER FIRST AND SCALE THE RECTANGLE TO PAINT IN
painter.scale(scaleFactor, scaleFactor); QString html = "<p> Enter HTML Text here </p>" td.setHtml(html); QRect mainBox = QRect(QPoint(0/scaleFactor, 0/scaleFactor), QPoint(pageWidth/scaleFactor, pageHeight/scaleFactor)); td.drawContents(%painter, mainBox); painter.scale(-1.0 * scaleFactor, -1.0 * scaleFactor); //scale the painter back if needed
I hope this helps someone and if anyone sees any potential problems with this approach, please let me know.
Thanks
-
So I thought this solution worked, but it has some problems. When I disconnect my monitor, the layout of the text changes. When I reconnect it and then disconnect it again, the layout changes yet again. No changes in code whatsoever, only disconnecting and reconnecting my monitors.
Is there no way to have QTextDocument write to a pdf and produce the same layout every time regardless of the screen resolution or scaling %??
-
@AhmedAlshawi
Guess (not much point asking me about it): does yourscreenPrinter.resolution()
return different result as your monitors disconnect/connect? If you want "regardless of the screen resolution or scaling %", why are you doing screen resolution/scaling? -
@AhmedAlshawi
Guess (not much point asking me about it): does yourscreenPrinter.resolution()
return different result as your monitors disconnect/connect? If you want "regardless of the screen resolution or scaling %", why are you doing screen resolution/scaling?It returns a different result when I change the scaling in display settings from 100% to 150% or otherwise. E.g. at 100% scaling it returns 96, at 150% it returns 144, at 175% it returns 168 etc.
I want my application to work regardless of which screen resolution or scaling % the user has on their machine. It seems that QTextDocument is really poor at maintaining consistency. I am now finding that even if I do not change any of my code and only reset my machine, the pdf comes out differently. If I do not do any scaling, then when the Microsoft windows scaling is changed, the text size and layout completely changes.
painter.drawtext() works perfectly but I can't use html with it.