Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 1 addition & 14 deletions qpageview/pdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,16 +220,7 @@ def document(self):

class PdfRenderer(render.AbstractRenderer):
oversampleThreshold = 96 # DPI of a standard PC screen

def tiles(self, width, height):
"""Yield four-tuples Tile(x, y, w, h) describing the tiles to render.

For the QtPdf backend, this always returns a single tile covering
the entire page because QtPdf does not support selectively rendering
a smaller area.

"""
yield render.Tile(0, 0, width, height)
renderFullPages = True # QtPDF doesn't support partial page rendering

def draw(self, page, painter, key, tile, paperColor=None):
"""Draw a tile on the painter.
Expand Down Expand Up @@ -303,10 +294,6 @@ def draw(self, page, painter, key, tile, paperColor=None):
Qt.AspectRatioMode.IgnoreAspectRatio,
Qt.TransformationMode.SmoothTransformation)

# Erase the target area and draw the image
painter.eraseRect(target)
if paperColor:
painter.fillRect(target, paperColor)
painter.drawImage(target, image, QRectF(image.rect()))


Expand Down
42 changes: 32 additions & 10 deletions qpageview/render.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@ class AbstractRenderer:
# antialias True by default (not all renderers may support this)
antialiasing = True

# qpageview was designed to render pages tile-by-tile. However, some
# backends like QtPDF only support full-page rendering, so for these we
# render the page first and divide it into tiles later. This is less
# efficient, but still provides certain performance advantages of using
# tiles like reduced flicker when repainting the widget.
renderFullPages = False

def __init__(self, cache=None):
if cache:
self.cache = cache
Expand Down Expand Up @@ -219,17 +226,15 @@ def render(self, page, key, tile, paperColor=None):
The default implementation prepares the image, a painter and then
calls draw() to actually draw the contents.

If the paperColor is not specified, it will be read from the Page's
paperColor attribute (if not None) or else from the renderer's
paperColor attribute.
If the paperColor is not specified, the returned image will have a
transparent background, and the caller is responsible to paint or
erase the background as needed before calling this method.

"""
if paperColor is None:
paperColor = page.paperColor or self.paperColor

i = QImage(tile.w, tile.h, self.imageFormat)
if paperColor:
i.fill(paperColor)
# leave the background transparent if no paperColor is specified,
# since we don't necessarily want to fill it e.g. when printing
i.fill(paperColor or Qt.GlobalColor.transparent)
painter = QPainter(i)

# rotate the painter accordingly
Expand Down Expand Up @@ -371,6 +376,8 @@ def paint(self, page, painter, rect, callback=None):
for (r, image, source) in reversed(images):
# scale the target rect back to the paint device
target = QRectF(r.x() / info.ratio, r.y() / info.ratio, r.width() / info.ratio, r.height() / info.ratio)
# job() already filled the background when rendering the page
# so we don't have to do that separately, which can cause flicker
painter.drawImage(target, image, source)

def schedule(self, page, key, tiles, callback):
Expand All @@ -380,6 +387,14 @@ def schedule(self, page, key, tiles, callback):
pending job.

"""
if self.renderFullPages:
# ignore the caller's request and always render the full page;
# job() will do the actual division into tiles later
tiles = [Tile(0, 0, key.width, key.height)]
# ensure the cache can always hold at least two full pages to
# avoid excessive re-rendering at higher zoom levels
pageBytes = key.width * key.height * 4 # 32 bits == 4 bytes
self.cache.maxsize = max(cache.ImageCache.maxsize, pageBytes * 2)
for tile in tiles:
try:
job = _jobs[(key, tile)]
Expand All @@ -398,12 +413,19 @@ def job(self, page, key, tile):
exception = []
def work():
try:
return self.render(page, key, tile)
# filling the background here is an optimization for paint()
return self.render(page, key, tile,
page.paperColor or self.paperColor)
except Exception:
exception.extend(sys.exc_info())
return QImage()
def finalize(image):
self.cache.addtile(key, tile, image)
if self.renderFullPages:
for subtile in self.tiles(key.width, key.height):
self.cache.addtile(key, subtile,
image.copy(QRect(*map(int, subtile))))
else:
self.cache.addtile(key, tile, image)
for cb in callbacks:
cb(page)
del _jobs[(key, tile)]
Expand Down
Loading