[solved] how to paint QTextDocument on QImage with correct DPI



  • I'm trying to use QTextDocument to render rich text onto a QImage, which will then be used for printing (stupid non-free binary-only CD Label printer driver requires me to provide an image - can't use QPrinter).
    I'm stuck now, because QTextDocument fails to render at the correct font size. I.e. the code looks like this:
    @
    QImage img = m_baseImage;
    img.setDotsPerMeterX(qRound(img.width() / 0.118)); // the CD label has a diameter of 118mm
    img.setDotsPerMeterY(qRound(img.height() / 0.118));
    QPainter p(&img);
    // p.translate to the right position
    m_document->drawContents(&p);
    // compare with QPainter::drawText:
    p.setFont(m_document->defaultFont());
    p.drawText(0, 0, QLatin1String("test text"));
    p.end();
    img.save("/tmp/check.png", "PNG");
    @
    The result is that QTextDocument renders at the DPI of the screen, while QPainter::drawText renders the font at the expected 600x600 dpi (which is the value img.logicalDpiX() and img.physicalDpiX() (and Y) return).

    I can add a QPainter::scale call that would lead to the correct magnification of the font, but it results in incorrect font rendering. This is most visible for small font sizes and serifs: they are rendered in a way to accommodate for the low number of pixels on screen, and this looks very ugly in print.

    Is this a bug in QTextDocument or am I missing something?



  • Does anybody have experience with QTextDocument? I'm stuck and could use some other opinion, please.



  • I finally found a way to fix it now:
    QTextDocument uses a different QPaintDevice to do the layouting than it uses to do the rendering. I.e. you need to access QTextDocument::documentLayout() and call setPaintDevice(QPaintDevice *) on it. This will lead to correct font size but incorrect placement. So you still need to call some QTextDocument function that will lead to a relayout, for example setTextWidth. So the final code that works goes like this:
    @
    QImage img = m_baseImage;
    img.setDotsPerMeterX(qRound(img.width() / 0.118)); // the CD label has a diameter of 118mm
    img.setDotsPerMeterY(qRound(img.height() / 0.118));
    QTextDocument *doc = m_document->clone();
    doc->documentLayout()->setPaintDevice(&img);
    doc->setTextWidth(img.width());
    QPainter p(&img);
    // p.translate to the right position
    doc->drawContents(&p);
    p.end();
    delete doc;
    img.save("/tmp/check.png", "PNG");
    @

    I consider this behavior unintuitive if not incorrect.



  • you could too change the scale of the painter QPaint::scale(), but like you are saying it's impossible to avoid the relayouting of the text (the text width changes! For trick if you call the function QTextDocument::size() it's make too a relayout of the text)



  • [quote author="BilbonSacquet" date="1321861434"]you could too change the scale of the painter QPaint::scale()[/quote]

    [quote author="mkretz" date="1319557277"]
    I can add a QPainter::scale call that would lead to the correct magnification of the font, but it results in incorrect font rendering. This is most visible for small font sizes and serifs: they are rendered in a way to accommodate for the low number of pixels on screen, and this looks very ugly in print.[/quote]

    So please, don't use QPainter::scale with font rendering. It can lead to ugly looking fonts!



  • [quote author="BilbonSacquet" date="1321861434"]like you are saying it's impossible to avoid the relayouting of the text (the text width changes! For trick if you call the function QTextDocument::size() it's make too a relayout of the text)[/quote]

    Actually when you only use QPainter::scale there's no need to relayout the QTextDocument (unless, of course the text width on screen and in the image must be different). In my case I simply didn't define a text width/page size. So scale didn't need a relayout.

    Also, I added a QTextDocument::size() call to my solution (so without the setTextWidth call) and it did not change the wrong layout.



  • thank you mkretz for this post.
    You saved my day!!


Log in to reply
 

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