Using pangocairo from Python


I wanted to include nice rendering of text in pyGTK, and was first tempted (and lost quite a bit of time) in using Pango on a gtk.TextView. Mind - I'm not criticizing Pango. It's a great tool. The disadvantage is that there doesn't seem to be a way to print the rendered output from a gtk.TextView including the formatting.

So, the next step in the development process was to look at combining Pango and Cairo, and show that on the screen. it's (quite) a bit more involved. And precious few examples can be found on how to do it on the 'net. And many of those examples seem to have been written by the authors, maybe under duress :-)

Anyway, it takes conviction to translate C into Python, and though the naming conversion is quite systematic, some things have to be done in a more object-oriented way.

Here's the (working) translation of tutorial on the Gnome Developer pages. Though the final program is quite readable, I do not find "using Pango with Cairo is straightforward." applicable (from the text on the same page).

Below is the listing of the program. I took the liberty to change the font slightly, just to mark a difference. The image that will be generated on executing:

python tutorial.py test.png

is the following:


#!/usr/bin/env python

import sys
import math
import cairo
import pango
import pangocairo as pc

RADIUS = 150
N_WORDS = 10
FONT = "Serif 27"

def draw_text(cairo_ctx):
    # Center coordinates on the middle of the region we are drawing
    cairo_ctx.translate(RADIUS, RADIUS)

    # Create a Pango Context and Layout, set the font and text
    pc_ctx = pc.CairoContext(cairo_ctx)
    pc_layout = pc_ctx.create_layout()

    desc = pango.FontDescription(FONT)

    # Draw the layout N_WORDS times in a circle
    for i in range(N_WORDS):
        angle = (360. * i) / N_WORDS


        # Gradient from red at angle == 60 to blue at angle == 240
        red = (1 + math.cos((angle - 60) * math.pi / 180.)) / 2
        pc_ctx.set_source_rgb(red, 0, 1.0 - red);

        pc_ctx.rotate(angle * math.pi / 180.)

        # Inform Pango to re-layout the text with the new transformation

        width, height = pc_layout.get_size()
        cairo_ctx.move_to(-(float(width) / pango.SCALE) / 2, -RADIUS)


def main():
    if len(sys.argv) != 2:
        print "Usage: cairosimple OUTPUT_FILENAME\n"
        return 1

    filename = sys.argv[1]

    surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 2 * RADIUS, 2 * RADIUS)
    cairo_ctx = cairo.Context(surface)

    cairo_ctx.set_source_rgb(1.0, 1.0, 1.0)

        status = surface.write_to_png(filename)
        print "Could not save png to '%s'\n" % filename
        return 1

    return 0

(c) John Coppens ON6JC/LW3HAZ mail