Optimize PDF rendering to save memory#58
Conversation
|
|
d9fe395 to
365a889
Compare
Because QPdfDocument.render() already returns a QImage, we can save memory in PdfRenderer.render() by reusing that image rather than creating a second QImage to draw it onto. This can reduce peak memory usage by hundreds of MB when rendering at higher zoom levels.
This makes the rendering code easier to read, and allows for future reuse in other backends if needed. While I was at it, I also documented why 96 DPI was chosen as the threshold. (It was inherited from the old Poppler code, where no explanation was given, but experimenting with different values led me to conclude it was based on screen density as noted here.)
365a889 to
43b928d
Compare
|
This is finally ready to review -- and I promise I don't have any more surprise PRs waiting after this. :) |
| # this is only doable by drawing on a second QImage | ||
| return super().render(page, key, tile, paperColor) | ||
| else: | ||
| # reuse the QImage returned by QPdfDocument.render() to save memory |
There was a problem hiding this comment.
For clarification: the default implementation in render.py creates a new QImage, fills its background if needed, then calls draw() to add the content. But QtPDF already returns the content as a QImage (on new line 302), so there's no need to create a second QImage most of the time. This can save a considerable amount of memory.
We do need two images when performing manipulations like rotating the page, which is implemented by using QPainter to draw the content rotated on top of the background image.
| import platform | ||
|
|
||
| from PyQt6.QtCore import Qt, QByteArray, QModelIndex, QRect, QRectF, QSize, QUrl | ||
| from PyQt6.QtGui import QPainter, QTransform |
| return QRegion(QBitmap.fromImage(mask)).boundingRect() | ||
|
|
||
|
|
||
| def oversampleFactor(key, pageSize): |
There was a problem hiding this comment.
I thought I was going to have to duplicate a lot more code when I refactored the rendering logic. That turned out not to be the case, but separating this out seemed like a good idea anyway for code clarity and reuse.
fedelibre
left a comment
There was a problem hiding this comment.
I trust you know what you are doing.
I'm waiting for this to be merged to do a new qpageview and Frescobaldi releases. Feel free to merge it if it's final.
|
Done. Should I merge #59 as well? That one is also final. |
Because
QPdfDocument.render()already returns a QImage, we can save memory inPdfRenderer.render()by reusing that image rather than creating a second QImage to draw it onto. This can reduce Frescobaldi's peak memory usage by hundreds of MB when rendering at higher zoom levels.