.. currentmodule:: qpageview

How rendering works
===================

To render Page objects graphically, a Page class should implement three
methods: :meth:`paint() <page.AbstractPage.paint>`, :meth:`print()
<page.AbstractPage.print>` and :meth:`image() <page.AbstractPage.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 :class:`Renderer <render.AbstractRenderer>` 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 :class:`page.AbstractRenderedPage`.

Available Page types
~~~~~~~~~~~~~~~~~~~~

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

.. list-table::
   :header-rows: 1
   :widths: 10 25 25 40

   * - Module
     - Page type
     - Document type
     - Displays

   * - :mod:`~qpageview.image`
     - :class:`~image.ImagePage`
     - :class:`~image.ImageDocument`
     - all image formats supported by QImage

   * - :mod:`~qpageview.svg`
     - :class:`~svg.SvgPage`
     - :class:`~svg.SvgDocument`
     - SVG images, one file per page

   * - :mod:`~qpageview.poppler`
     - :class:`~poppler.PopplerPage`
     - :class:`~poppler.PopplerDocument`
     - PDF documents, multiple pages per file

   * - :mod:`~qpageview.diff`
     - :class:`~diff.DiffPage`
     - :class:`~diff.DiffDocument`
     - color composites other pages of any type


Implementing a new page type
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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

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

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

