Visions of Aestia

18 Aug 2005

Using Pangocairo

Filed under: GNOME, Python — JBowtie @ 4:46 pm

I’ve been experimenting with the new Pango/Cairo integration in the latest PyGTK and have figured out a few things (cairo is somewhat sparsely documented at the moment).

I decided to try my hand on PDFs to start with, since printing is my biggest issue at present. Presumably other backends work in a similar fashion.

The first challenge was figuring out the units for specifying the surface width and height. After some work, I discovered that this should be in Postscript points. A4 paper is 595 x 842 points; I found this and other well-know page sizes defined in the Scribus online documentation.

So, the workflow seems to be as follows.

  • Create a surface, specifying size in Postscript points. Each backend seems to define its own surface type.
  • Create a rendering context. Pango has its own context that wraps a standard cairo context.
  • Create a pango layout for each paragraph, preferably using the Pango markup format to apply formatting within the paragraph. Pango exposes a bunch of other ways to format the text, have fun. Postscript points are 3/4 the size of font points (fontSize/0.75=Postscript points). That’s because fonts assume 72pt/inch, while PS assumes 96pt/inch.
  • For a given paragraph, call layout.set_width() so that the paragraph wraps correctly. It’s not obvious, but width is expressed in thousandths of a point, so basically multiply the desired width by 1000.
  • Line spacing is supposed to be controlled by layout.set_spacing() [also in thousandths of a point], but the version I have installed seems to ignore this - I’ll assume this a bug that will be fixed in short order.
  • Position the paragraph using cairocontext.move_to() or cairocontext.rel_move_to(). Again, the coordinates shound be in Postscript points. Calling layout.get_pixel_size() will give you the width and height in Postscript points.
  • Render the paragraph by calling cairocontext.show_layout().
  • Finished laying out a page? Call cairocontext.show_page() to create the actual page. Any work you do after this point will be on a new page.
  • Finally, call surface.finish() to write out the actual PDF file and release your handles.

If you want to lay out the individual lines yourself, you can get individual lines using layout.get_line(index) and use the resulting object to access the line measurements. You will probably want to do this when spanning page or column breaks. Use cariocontext.show_layout_line() to render individual lines.

3 Responses to “Using Pangocairo”

  1. Dave Beckett Says:

    You might not have noticed but as well as RDF, I maintain the Cairo debian packages for the project itself - http://cairographics.org/packages/debian/ and in Debian itself. One day I’ll try to join these two interests up :)

  2. Mayank Jain Says:

    I agree with you that cairo & pango have almost nil documentation (apart from the api reference). I’m myself trying to get the head & tail of pango from past some days. Looking at other people’s code is the only possible was (os of now) :-)

    Your workflow description is really nice & helpfull. Thanks.

    Oh, yes, there’s a typo in workflow-point-1

    :)
    Mayank

  3. JBowtie Says:

    Thanks, I’ve fixed the typo. I really wrote that workflow down for myself; glad that it has helped somebody.

    I’ll put together a proper tutorial once there’s an official release of cairo with PDF support turned on.

Leave a Reply

Powered by WordPress