Drawing With Cairo

#!/usr/bin/env python
#
# [SNIPPET_NAME: Drawing With Cairo]
# [SNIPPET_CATEGORIES: PyGTK, Cairo]
# [SNIPPET_DESCRIPTION: Create a drawing with cairo]
# [SNIPPET_AUTHOR: Jurjen Stellingwerff <jurjen@stwerff.xs4all.nl>]
# [SNIPPET_LICENSE: GPL]

# example cairo_demo.py

import pygtk
pygtk.require('2.0')
import gtk
import math
import cairo

class DrawingAreaExample:
    def __init__(self):
        window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        window.set_title("Drawing With Cairo")
        window.connect("destroy", lambda w: gtk.main_quit())
        self.area = gtk.DrawingArea()
        self.area.set_size_request(380, 300)
        window.add(self.area)
        self.area.connect("expose-event", self.expose)
        self.area.show()
        window.show()

    def expose(self, area, event):
        self.context = area.window.cairo_create()
        self.context.rectangle(event.area.x, event.area.y, event.area.width,
            event.area.height)
        self.context.clip()
        self.context.scale(event.area.width/380.0, event.area.height/300.0)
        self.draw_point(10,10)
        self.draw_points(110, 10)
        self.draw_line(210, 10)
        self.draw_lines(310, 10)
        self.draw_segments(10, 100)
        self.draw_rectangles(110, 100)
        self.draw_arcs(210, 100)
        self.draw_pixmap(310, 100)
        self.draw_polygon(10, 200)
        self.draw_rgb_image(110, 200)
        self.context.move_to(210, 290)
        self.context.show_text("Try to resize the window")
        return False

    def point(self, x, y):
        self.context.arc(x, y, 1, 0.0, 2.0 * math.pi)
        self.context.fill()

    def draw_point(self, x, y):
        self.point(x+30, y+30)
        self.context.move_to(x+5, y+50)
        self.context.show_text("Point")
        return

    def draw_points(self, x, y):
        points = [(x+10,y+10), (x+10,y), (x+40,y+30),
                 (x+30,y+10), (x+50,y+10)]
        for px,py in points:
            self.point(px,py)
        self.context.move_to(x+5, y+50)
        self.context.show_text("Points")
        return

    def draw_line(self, x, y):
        self.context.move_to(x+10, y+10)
        self.context.line_to(x+20, y+30)
        self.context.stroke()
        self.context.move_to(x+5, y+50)
        self.context.show_text("Line")
        return

    def draw_lines(self, x, y):
        points = [(x+10,y), (x+40,y+30),
                  (x+30,y+10), (x+50,y+10)]
        self.context.move_to(x+10, y+10)
        for px,py in points:
            self.context.line_to(px, py)
        self.context.set_line_width(4.5)
        self.context.stroke()
        self.context.save()
        self.context.set_source_rgb(1, 1, 0.7)
        self.context.translate(1.5, 1)
        self.context.move_to(x+10, y+10)
        for px,py in points:
            self.context.line_to(px, py)
        self.context.set_line_width(1.5)
        self.context.stroke()
        self.context.restore()
        self.context.set_line_width(2)
        self.context.move_to(x+5, y+50)
        self.context.show_text("Lines")
        return

    def draw_segments(self, x, y):
        segments = ((x+20,y+10, x+20,y+70), (x+60,y+10, x+60,y+70),
            (x+10,y+30 , x+70,y+30), (x+10, y+50 , x+70, y+50))
        for fx, fy, tx, ty in segments:
            self.context.move_to(fx, fy)
            self.context.line_to(tx, ty)
        self.context.stroke()
        self.context.move_to(x+5, y+90)
        self.context.show_text("Segments")
        return

    def draw_rectangles(self, x, y):
        self.context.save()
        self.context.set_source_rgb(.6, 0, 0)
        self.context.rectangle(x, y, 80, 70)
        self.context.stroke()
        self.context.restore()
        rectangles = ((x+10, y+10, 20, 20), (x+50, y+10, 20, 20), (x+20, y+50, 40, 10))
        for px, py, h, w in rectangles:
            self.context.rectangle(px, py, h, w)
            self.context.fill()
        self.context.move_to(x+5, y+90)
        self.context.show_text("Rectangles")
        return

    def draw_arcs(self, x, y):
        self.context.set_line_width(1)
        arcs = [(False, x+45, y+35, 35),
            (True, x+35, y+25, 5),
            (True, x+55, y+25, 5)]
        for fill, px, py, r in arcs:
            self.context.move_to(px+r, py)
            self.context.arc(px, py, r, 0, 2*math.pi)
            if fill:
                self.context.fill()
            else:
                self.context.set_source_rgb(1, 1, 0.5)
                self.context.fill_preserve()
                self.context.set_source_rgb(0, 0, 0)
                self.context.stroke()
        self.context.move_to(x+45, y+35)
        s = 1.66
        self.context.save()
        self.context.scale(1, s)
        self.context.arc(x+45, (y+35)/s, 15, 30*math.pi/180, 150*math.pi/180)
        self.context.restore()
        self.context.save()
        self.context.move_to(x+5, y+90)
        self.context.select_font_face("serif", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD)
        self.context.show_text("Arcs")
        self.context.restore()
        return

    def draw_pixmap(self, x, y):
        try:
            img = cairo.ImageSurface.create_from_png("gtk.png")
        except Exception, e:
            print e
            exit(1)
        self.context.save()
        self.context.set_source_surface(img, x+5, y+15)
        self.context.paint()
        self.context.restore()
        self.context.move_to(x+5, y+90)
        self.context.show_text("Pixmap")
        return

    def draw_polygon(self, x, y):
        points = [(x+10,y+20), (x+40,y+70),
                  (x+30,y+30), (x+50,y+40)]
        self.context.move_to(x+10, y+60)
        for px,py in points:
            self.context.line_to(px, py)
        self.context.fill()
        self.context.move_to(x+5, y+90)
        self.context.show_text("Polygon")
        return

    def draw_rgb_image(self, x, y):
        s = 80
        h = 40
        self.context.save()
        linpat = cairo.LinearGradient(x, y, x+s, y+s)
        linpat.add_color_stop_rgb(0.0, 1, 1, 1)
        linpat.add_color_stop_rgb(1.0, 0, 1, 0)
        self.context.set_source(linpat)
        self.context.move_to(x,y)
        self.context.line_to(x,y+s)
        self.context.line_to(x+s,y+s)
        self.context.line_to(x+s,y)
        self.context.fill()
        linpat = cairo.LinearGradient(x, y+s, x+s, y)
        linpat.add_color_stop_rgba(0.0, 0, 0, 1, 1)
        linpat.add_color_stop_rgba(0.5, 1, 0, 1, 0)
        linpat.add_color_stop_rgba(1.0, 1, 0, 0, 1)
        self.context.set_source(linpat)
        self.context.move_to(x,y)
        self.context.line_to(x,y+s)
        self.context.line_to(x+s,y+s)
        self.context.line_to(x+s,y)
        self.context.fill()
        self.context.restore()
        self.context.save()
        self.context.move_to(x+5, y+92)
        self.context.set_font_size(11.5)
        self.context.show_text("RGB Image")
        self.context.restore()
        return

def main():
    gtk.main()
    return 0

if __name__ == "__main__":
    DrawingAreaExample()
    main()