Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. PDF Query
QtWS25 Last Chance

PDF Query

Scheduled Pinned Locked Moved Unsolved General and Desktop
11 Posts 4 Posters 721 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    AhmedAlshawi
    wrote on last edited by AhmedAlshawi
    #1

    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:
    1e0c80f8-1a76-49c9-b992-8f34fabcef71-image.png

    I'd then like to use variables calculated in my code to fill in the gaps like this:
    07e6ed72-f0ce-411f-8f9e-f4c5d1e1dff6-image.png

    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!

    1 Reply Last reply
    0
    • mrjjM Offline
      mrjjM Offline
      mrjj
      Lifetime Qt Champion
      wrote on last edited by mrjj
      #2

      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.

      1 Reply Last reply
      2
      • A Offline
        A Offline
        AhmedAlshawi
        wrote on last edited by AhmedAlshawi
        #3

        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:

        916e4cba-26a7-45a3-9173-9a63d667e079-image.png

        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:
        c93e93ef-835c-48f3-9b63-814f77dd06a4-image.png

        Maybe I have misunderstood the named markers (ids)?

        Thanks again for the help :)

        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          Hi,

          Why not just generate the PDF on the fly using QPdfWriter ?

          Do you even need that template for that document ?

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          A 1 Reply Last reply
          0
          • SGaistS SGaist

            Hi,

            Why not just generate the PDF on the fly using QPdfWriter ?

            Do you even need that template for that document ?

            A Offline
            A Offline
            AhmedAlshawi
            wrote on last edited by AhmedAlshawi
            #5

            @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.

            2f88daf4-e700-4474-aa54-938d42ba70b1-image.png

            1 Reply Last reply
            0
            • mrjjM Offline
              mrjjM Offline
              mrjj
              Lifetime Qt Champion
              wrote on last edited by mrjj
              #6

              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.

              A 1 Reply Last reply
              3
              • mrjjM 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)?

                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.

                A Offline
                A Offline
                AhmedAlshawi
                wrote on last edited by AhmedAlshawi
                #7

                @mrjj @SGaist
                I have found two main problems with this approach.

                1. Inkscape misses many elements from the original PDF.
                2. 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:
                cbe2c39e-f0fd-40aa-a0e3-c1eaee5dffa0-image.png

                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 :)

                1 Reply Last reply
                0
                • A Offline
                  A Offline
                  AhmedAlshawi
                  wrote on last edited by AhmedAlshawi
                  #8

                  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

                  A 1 Reply Last reply
                  1
                  • A AhmedAlshawi

                    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

                    A Offline
                    A Offline
                    AhmedAlshawi
                    wrote on last edited by
                    #9

                    @mrjj @SGaist

                    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 %??

                    JonBJ 1 Reply Last reply
                    0
                    • A AhmedAlshawi

                      @mrjj @SGaist

                      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 %??

                      JonBJ Offline
                      JonBJ Offline
                      JonB
                      wrote on last edited by
                      #10

                      @AhmedAlshawi
                      Guess (not much point asking me about it): does your screenPrinter.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?

                      A 1 Reply Last reply
                      0
                      • JonBJ JonB

                        @AhmedAlshawi
                        Guess (not much point asking me about it): does your screenPrinter.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?

                        A Offline
                        A Offline
                        AhmedAlshawi
                        wrote on last edited by AhmedAlshawi
                        #11

                        @JonB said in PDF Query:

                        @AhmedAlshawi
                        Guess (not much point asking me about it): does your screenPrinter.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.

                        1 Reply Last reply
                        0

                        • Login

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Users
                        • Groups
                        • Search
                        • Get Qt Extensions
                        • Unsolved