Printing widgets not as bitmap, but in a vector based format



  • Hi there,

    I already searched a lot but didn't find anything of use about this topic, so I'd like to ask here.

    In my application I'd like to print a widget (a QTreeView, I don't think it matters).

    Based on an example I found I use the following code (PySide)

    [code]
    printer = QtGui.QPrinter(QtGui.QPrinter.HighResolution)
    printer.setOutputFileName("print.pdf")
    painter = QtGui.QPainter()
    painter.begin(printer)

    self.my_widget.render(painter, QtCore.QPoint())

    painter.end()
    [/code]

    Unfortunately, the PDF file is quite large, because it contains the widget as one big bitmap.

    Strangely, modifying the above code for usage with QSvgGenerator however:

    [code]
    printer = QtSvg.QSvgGenerator()
    printer.setFileName("print.svg")
    painter = QtGui.QPainter()
    painter.begin(printer)

    self.my_widget.render(painter, QtCore.QPoint())

    painter.end()
    [/code]

    ... yields a nice SVG drawing of my widget -- composed of separate SVG entities, no bitmaps at all.

    I also tried:

    • ... to read the produced SVG image and print it out again like above, using QSvgRenderer, but the produced PDF is rasterised, too.
    • Not using QPrinter::setOutputFilename() and "really" printing using a PDF renderer (FreePDF XP) also yielded a raster PDF file.
    • Printing the SVG out of inkscape using the same PDF printer produces a nice vector-based PDF file ...

    How can I configure or modify QPrinter to render the output vector based as well?

    Digging in the source code I found no real hints about this after over an hour -- the API is quite complex. So I hope anybody has experience with this and could point me in the right direction about how to set up or derive QPrinter so that it outputs vector data.

    Regards&thanks for your time,

    Björn



  • I had the same question and found a solution. Posting here for anyone trying to figure out how to print QWidgets to a PDF as vectors and text.

    I did this in C++, but it should translate to Python roughly as follows:

    @
    // First render the widget to a QPicture, which stores QPainter commands.
    QPicture pic;
    QPainter picPainter(pic);
    self.my_widget.render(picPainter);
    picPainter.end();

    // Set up the printer
    printer = QtGui.QPrinter(QtGui.QPrinter.HighResolution)
    printer.setOutputFormat(QtGui.QPrinter.PdfFormat)
    printer.setOutputFileName("print.pdf")
    
    // Finally, draw the QPicture to your printer
    painter = QtGui.QPainter()
    painter.begin(printer)
    painter.drawPicture(QtCore.QPointF(0, 0), pic);
    painter.end()
    

    @

    The reason this extra step of drawing to a QPicture is necessary is that QWidget uses a different code path when printing to a printer than printing to any other QPaintDevice. For some reason it thinks you must want a bitmap if you're printing, so it renders to a QPixmap explicitly, then draws the pixmap to the painter. Rendering to a QPicture circumvents that behavior.

    I discovered this by looking through the Qt source code. I could not find any documentation describing this behavior.

    Hope that helps!



  • Can you post c++ equilavent of this code. I try this but not work. I try to export a widget as pdf.

    @ QPicture pic;
    QPainter picPainter(pic);
    ui->widget->render(picPainter);
    picPainter.end();

        QPrinter printer(QPrinter::HighResolution);
        printer.setOutputFormat(QPrinter::PdfFormat);
        printer.setOutputFileName("12.pdf");
    
        QPainter paint();
        paint().begin(&printer);
        paint().drawPicture(0,20,pic);
        paint().end();
    

    @



  • Can you post c++ equilavent of this code. I try this but not work. I try to export a widget as pdf.

    @ QPicture pic;
    QPainter picPainter(pic);
    ui->widget->render(picPainter);
    picPainter.end();

        QPrinter printer(QPrinter::HighResolution);
        printer.setOutputFormat(QPrinter::PdfFormat);
        printer.setOutputFileName("12.pdf");
    
        QPainter paint();
        paint().begin(&printer);
        paint().drawPicture(0,20,pic);
        paint().end();
    

    @


  • Lifetime Qt Champion

    Hi,

    No tested but it should rather be something like:

    @
    QPicture pic;
    QPainter picPainter(&pic);
    ui->widget->render(&picPainter);

    QPrinter printer(QPrinter::HighResolution);
    printer.setOutputFormat(QPrinter::PdfFormat);
    printer.setOutputFileName("12.pdf");

    QPainter painter(&printer);
    painter.drawPicture(0,20,pic);
    painter.end();
    @


  • Lifetime Qt Champion

    Hi,

    No tested but it should rather be something like:

    @
    QPicture pic;
    QPainter picPainter(&pic);
    ui->widget->render(&picPainter);

    QPrinter printer(QPrinter::HighResolution);
    printer.setOutputFormat(QPrinter::PdfFormat);
    printer.setOutputFileName("12.pdf");

    QPainter painter(&printer);
    painter.drawPicture(0,20,pic);
    painter.end();
    @



  • SGaist, your code works. but now pdf is empty white paper. nothing in it. I want to export my widget to pdf with high quality. I found another way to do this. but quality is low. There is some shapes in widget and these shapes look ugly with this code. How can I export my widget with high quality?

    Thank you and sorry for my English

    the code I found:

    @QPixmap pixmap;
    pixmap=QPixmap::grabWindow(ui->widget->winId());

    QPrinter printer(QPrinter::HighResolution);
    printer.setOrientation(QPrinter::Landscape);
    printer.setOutputFormat(QPrinter::PdfFormat);
    //printer.setPageMargins(10,10,10,10,QPrinter::Millimeter);

    printer.setOutputFileName("12.pdf");

    QPainter painter(&printer);
    QRect rect=painter.viewport();
    QSize size=pixmap.size();

    size.scale(rect.size(), Qt::KeepAspectRatio);
    painter.setViewport(rect.x(), rect.y(), size.width(), size.height());
    painter.setWindow(pixmap.rect());

    int pdfX=680-(640/20);
    int pdfY=460-(460/10);

    painter.drawText(0, 0, 640, 20, Qt::AlignHCenter, "graph");
    painter.drawPixmap(0, 20, pdfX, pdfY, pixmap);@



  • SGaist, your code works. but now pdf is empty white paper. nothing in it. I want to export my widget to pdf with high quality. I found another way to do this. but quality is low. There is some shapes in widget and these shapes look ugly with this code. How can I export my widget with high quality?

    Thank you and sorry for my English

    the code I found:

    @QPixmap pixmap;
    pixmap=QPixmap::grabWindow(ui->widget->winId());

    QPrinter printer(QPrinter::HighResolution);
    printer.setOrientation(QPrinter::Landscape);
    printer.setOutputFormat(QPrinter::PdfFormat);
    //printer.setPageMargins(10,10,10,10,QPrinter::Millimeter);

    printer.setOutputFileName("12.pdf");

    QPainter painter(&printer);
    QRect rect=painter.viewport();
    QSize size=pixmap.size();

    size.scale(rect.size(), Qt::KeepAspectRatio);
    painter.setViewport(rect.x(), rect.y(), size.width(), size.height());
    painter.setWindow(pixmap.rect());

    int pdfX=680-(640/20);
    int pdfY=460-(460/10);

    painter.drawText(0, 0, 640, 20, Qt::AlignHCenter, "graph");
    painter.drawPixmap(0, 20, pdfX, pdfY, pixmap);@



  • Also I tried to export Qimage to pdf but again quality is low.

    @QPrinter printer;
    printer.setOrientation(QPrinter::Portrait);
    printer.setOutputFileName("test.pdf");
    printer.setOutputFormat(QPrinter::PdfFormat);

    QImage image("/home/asd/a.png");

    QPainter painter;
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.begin(&image);
    painter.end();

    QPainter p;
    p.begin(&printer);
    p.drawImage(0, 0, image);
    p.end();@

    "http://www.qtcentre.org/threads/11236-2-questions-on-QPrint-QImage-PDF":http://www.qtcentre.org/threads/11236-2-questions-on-QPrint-QImage-PDF



  • Also I tried to export Qimage to pdf but again quality is low.

    @QPrinter printer;
    printer.setOrientation(QPrinter::Portrait);
    printer.setOutputFileName("test.pdf");
    printer.setOutputFormat(QPrinter::PdfFormat);

    QImage image("/home/asd/a.png");

    QPainter painter;
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.begin(&image);
    painter.end();

    QPainter p;
    p.begin(&printer);
    p.drawImage(0, 0, image);
    p.end();@

    "http://www.qtcentre.org/threads/11236-2-questions-on-QPrint-QImage-PDF":http://www.qtcentre.org/threads/11236-2-questions-on-QPrint-QImage-PDF



  • Let's get clear on what you want to achieve, instead of on how you are doing it. Your code suggests that you are not just trying to print any widget, but specifically a graph widget. Is that correct?



  • Let's get clear on what you want to achieve, instead of on how you are doing it. Your code suggests that you are not just trying to print any widget, but specifically a graph widget. Is that correct?



  • Andre, I have graphs (pie chart and "qcustomplot":http://www.qcustomplot.com/) and explanations(qlabel) in widget. I want to export these graphs and texts to pdf. codes which I used can export but quality is low. I want to export with high quality.



  • Andre, I have graphs (pie chart and "qcustomplot":http://www.qcustomplot.com/) and explanations(qlabel) in widget. I want to export these graphs and texts to pdf. codes which I used can export but quality is low. I want to export with high quality.



  • I figured as much.

    I've had similar issues last year. The solution I wend for is scaling up my rendering to match the output device. That really is the only way to get a good-looking result I found. That also means calculating a good font size for your items, and taking into account that some elements don't get too small (a hairline at 1200dpi will look really, really, really fine). I ended up having to deal with that on an element-by-element basis.

    Note that you're dealing with about an order of magnitude higher resolutions than what you're getting on-screen.

    Our printouts and PDF's look very crisp and clear now...



  • I figured as much.

    I've had similar issues last year. The solution I wend for is scaling up my rendering to match the output device. That really is the only way to get a good-looking result I found. That also means calculating a good font size for your items, and taking into account that some elements don't get too small (a hairline at 1200dpi will look really, really, really fine). I ended up having to deal with that on an element-by-element basis.

    Note that you're dealing with about an order of magnitude higher resolutions than what you're getting on-screen.

    Our printouts and PDF's look very crisp and clear now...


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.