Interacting with pages

Coordinate systems

A Page can display text or graphics, have clickable links, etc. A Page also has certain dimensions and its own notion of natural size, via the dpi attribute of the Page (sub)class.

There are three ways of determining a position on a Page:

  1. The pixel position on the Page in a View, e.g. where a mouse button is pressed. A Page knows its current dimensions in pixels: in the Page’s width and height instance attributes, and as a QSize via the size() method. If a Page is rotated 90 or 270 degrees, then the Page’s original height now corresponds to the displayed page’s width in pixels.

    In most cases this is called “page coordinates.” Page coordinates are always integer values.

  2. A position on the Page in its default size and without rotation. The original size of a Page is independent of the current zoomFactor of the View, and rather determined by the underlying image, SVG or PDF file. This is used e.g. when printing or converting to vector formats. The original size is accessible via the pageWidth and pageHeight attributes, and as a QSizeF via the pageSize() method.

    This is called “original page coordinates.” Normally these are floating point values.

    (When the dpi Page class attribute is the same as the current DPI setting of the computer’s display, then the displayed size of a Page at zoom factor 1.0 in pixels is the same as the default size.)

  3. A position where both horizontal and vertical offset are floating point, in the range 0..1, without rotation. This is used to determine the position of links, rectangular areas to highlight, and to position overlay widgets by the widget overlay view mixin.

Page has the method transform() to get a QTransform matrix that can map between page coordinates and original or 0..1 coordinates. The methods mapToPage() and mapFromPage() return helper objects that can convert QPoints and QRects from and to original page coordinates. These matrices take into account the page’s scaling and current rotation, and they always return floating point values for original or 0..1 range coordinates, and integers for page coordinates.

Page position and Layout position

Many methods neatly hide the computations between mouse cursor position and position in original page coordinates on a particular page, but it is still nice to understand it a bit.

A PageLayout is just a large rectangular (virtual) area, large enough so that all Pages in the layout can be set to a position and size so that they do not overlap. Every Page is assigned a pos() on the layout. The geometry() of the layout is the rectangle encompassing all visible pages on the layout.

View.layoutPosition() returns the position of the layout relative to the top-left corner of the View’s viewport. You can find the pages that are currently visible using View.visiblePages(). To find the Page the mouse cursor points at, use:

# pos is mouse position in viewport
pos_on_layout = pos - view.layoutPosition()
page = view.pageLayout().pageAt(pos)
pos_on_page = pos_on_layout - page.pos()

# translate the pixel position to original page coordinates
pos = page.mapFromPage().point(pos_on_page)

Getting text from a page

Besides links, depending on the Page type, a page can also contain text, such as PDF pages do. You can get the text with the Page.text() method, which returns the text in a rectangle in page coordinates:

page = view.currentPage()

# get the text in some rectangle
text = page.text(some_rect)

# get the full text by using the page's rectangle
full_text = page.text(page.rect())

# using the rubberband selection
text = view.rubberband().selectedText()

Getting image data from a page

You can get pixel data using Page.image():

image = page.image()

This method returns a QImage. See the documentation for the arguments to this function, to adjust the resolution and the area (which defaults to the whole page).

You can also get graphic data in PDF, EPS or SVG format. For document formats that are vector based, this graphic data wil also be vector based. For example:

page.pdf("filename.pdf")
page.svg("filename.svg")
page.eps("filename.eps")

# using the rubberband selection:
page, rect = view.rubberband.selectedPage()
if page:
    page.pdf("filename.pdf", rect)

See the method’s documentation for more information about possible arguments to these functions. Instead of a filename, you can also give a QIODevice object. All these functions return True if they were successful.

For more advanced methods to get image data, see the export module.