How rendering works

To render Page objects graphically, a Page class should implement three methods: paint(), print() and image().

  • paint() is used to paint the image in the View, in page coordinates. If painting is expensive, this method should return immediately and schedule a pixmap to be drawn in a background thread (see below).

  • print() is used to paint the image to a QPainter on any QPaintDevice, in original coordinates (i.e. the used QPainter has already been transformed to the original page size without rotation).

  • image() is used to get a rendered QImage.

Most Page classes depend on a Renderer that implements the actual rendering. The base Renderer class has functionality for caching and for tile-based rendering in a background thread, so when you zoom in very far, only a small portion of the original page is drawn on a pixmap to be displayed on the screen.

Awaiting the rendering, the View scales another image from the cache of the same region (if available) to display instead.

It is not necessary to specify a renderer directly, although it can be useful. All builtin page classes install a default renderer. Page types that use a renderer inherit from page.AbstractRenderedPage.

Available Page types

These are the currently available Page types, and their corresponding Document types:

Module

Page type

Document type

Displays

image

ImagePage

ImageDocument

all image formats supported by QImage

svg

SvgPage

SvgDocument

SVG images, one file per page

poppler

PopplerPage

PopplerDocument

PDF documents, multiple pages per file

diff

DiffPage

DiffDocument

color composites other pages of any type

Implementing a new page type

If you study the source of the svg module, you can see that there is only very little code needed to implement a rendered Page type.

For the rendered Page, Page.paint() calls Renderer.paint(), which schedules an image to be generated. The image is generated by Renderer.render(), which by default calls Renderer.draw(), which does the actual drawing work. Also Page.print() calls Renderer.draw() directly, while Page.image() simply calls Renderer.image(), which also calls Renderer.render(), which in turns calls Renderer.draw().

So you actually only need to implement Renderer.draw() :-) But, depending on the characteristics of the underlying graphics type, other strategies may be combined to achieve a well-working Page type.