#! /usr/bin/env python
import cairo
from math import pi
import sys
class Diagram(object):
def __init__(self, filename, width, height, alpha, separate=True):
iwidth = width
if separate:
iwidth = int(width * 4.0 / 3 + 0.99)
iheight = height
#self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, iwidth, iheight)
self.surface = cairo.SVGSurface(filename + '.svg', iwidth, iheight)
cr = self.cr = cairo.Context(self.surface)
cr.scale(width, height)
cr.set_line_width(0.01)
cr.save()
cr.transform(cairo.Matrix(0.6, 0, 1.0/3, 0.5, 0.02, 0.45))
cr.push_group()
cr.rectangle(0, 0, 1, 1); cr.clip()
self.draw_dest(self.cr)
cr.set_source_rgb(0, 0, 0)
cr.set_line_width( max(cr.device_to_user_distance(2, 2)) )
cr.rectangle(0, 0, 1, 1)
cr.stroke()
cr.pop_group_to_source()
cr.paint_with_alpha(alpha[0])
cr.restore()
cr.save()
cr.transform(cairo.Matrix(0.6, 0, 1.0/3, 0.5, 0.04, 0.25))
cr.push_group()
cr.rectangle(0, 0, 1, 1); cr.clip()
self.draw_mask(self.cr)
cr.pop_group_to_source()
cr.paint_with_alpha(alpha[1])
cr.restore()
cr.save()
cr.transform(cairo.Matrix(0.6, 0, 1.0/3, 0.5, 0.06, 0.05))
cr.push_group()
cr.rectangle(0, 0, 1, 1); cr.clip()
self.draw_src(self.cr)
cr.pop_group_to_source()
cr.paint_with_alpha(alpha[2])
cr.restore()
if separate:
cr.save()
cr.translate(1, 0)
cr.scale(1.0 / 3, 1.0 / 3)
cr.push_group()
cr.rectangle(0, 0, 1, 1); cr.clip()
self.draw_src(self.cr)
cr.pop_group_to_source()
cr.paint()
cr.restore()
cr.save()
cr.translate(1, 1.0 / 3)
cr.scale(1.0 / 3, 1.0 / 3)
cr.push_group()
cr.rectangle(0, 0, 1, 1); cr.clip()
self.draw_mask(self.cr)
cr.pop_group_to_source()
cr.paint()
cr.restore()
cr.save()
cr.translate(1, 2.0 / 3)
cr.scale(1.0 / 3, 1.0 / 3)
cr.push_group()
cr.rectangle(0, 0, 1, 1); cr.clip()
self.draw_dest(self.cr)
cr.pop_group_to_source()
cr.paint()
cr.restore()
cr.set_line_width( max(cr.device_to_user_distance(2, 2)) )
cr.rectangle(1, 0, 1.0/3, 1)
cr.clip_preserve()
cr.stroke()
cr.rectangle(1, 1.0/3, 1.0/3, 1.0/3)
cr.stroke()
self.surface.write_to_png(filename + '.png')
cr.show_page()
self.surface.finish()
def draw_dest(self, cr):
cr.set_source_rgb(1, 1, 1)
cr.rectangle(0, 0, 1, 1)
cr.fill()
def draw_mask(self, cr, mask=None):
cr.set_source_rgb(1, 0.9, 0.6)
if mask:
cr.mask(mask)
else:
cr.rectangle(0, 0, 1, 1)
cr.fill()
def draw_src(self, cr):
cr.set_source_rgb(0, 0, 0)
cr.rectangle(0, 0, 1, 1)
cr.fill()
class Stroke(Diagram):
def draw_mask(self, cr):
cr.push_group()
cr.rectangle(0, 0, 1, 1)
cr.rectangle(0.20, 0.20, 0.6, 0.6)
cr.rectangle(0.30, 0.30, 0.4, 0.4)
cr.set_fill_rule(cairo.FILL_RULE_EVEN_ODD)
cr.fill()
cr.set_fill_rule(cairo.FILL_RULE_WINDING)
Diagram.draw_mask(self, cr, cr.pop_group())
cr.rectangle(0.25, 0.25, 0.5, 0.5)
cr.set_source_rgb(0, 0.6, 0)
cr.set_line_width( max(cr.device_to_user_distance(1, 1)) )
cr.stroke()
def draw_dest(self, cr):
Diagram.draw_dest(self, cr)
cr.set_line_width(0.1) #stroke
cr.set_source_rgb(0, 0, 0) #stroke
cr.rectangle(0.25, 0.25, 0.5, 0.5) #stroke
cr.stroke() #stroke
class Fill(Diagram):
def draw_mask(self, cr):
cr.push_group()
cr.rectangle(0, 0, 1, 1)
cr.rectangle(0.25, 0.25, 0.5, 0.5)
cr.set_fill_rule(cairo.FILL_RULE_EVEN_ODD)
cr.fill()
cr.set_fill_rule(cairo.FILL_RULE_WINDING)
Diagram.draw_mask(self, cr, cr.pop_group())
cr.rectangle(0.25, 0.25, 0.5, 0.5)
cr.set_source_rgb(0, 0.6, 0)
cr.set_line_width( max(cr.device_to_user_distance(1, 1)) )
cr.stroke()
def draw_dest(self, cr):
Diagram.draw_dest(self, cr)
cr.set_source_rgb(0, 0, 0) #fill
cr.rectangle(0.25, 0.25, 0.5, 0.5) #fill
cr.fill() #fill
class ShowText(Diagram):
def draw_mask(self, cr):
cr.select_font_face("Georgia",
cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD)
cr.set_font_size(1.2)
x_bearing, y_bearing, width, height = cr.text_extents("a")[:4]
cr.push_group()
cr.rectangle(0, 0, 1, 1)
cr.move_to(0.5 - width / 2 - x_bearing, 0.5 - height / 2 - y_bearing)
cr.text_path("a")
cr.set_fill_rule(cairo.FILL_RULE_EVEN_ODD)
cr.fill()
cr.set_fill_rule(cairo.FILL_RULE_WINDING)
Diagram.draw_mask(self, cr, cr.pop_group())
cr.move_to(0.5 - width / 2 - x_bearing, 0.5 - height / 2 - y_bearing)
cr.set_source_rgb(0, 0.6, 0)
cr.set_line_width( max(cr.device_to_user_distance(1, 1)) )
cr.text_path("a")
cr.stroke()
def draw_dest(self, cr):
Diagram.draw_dest(self, cr)
cr.set_source_rgb(0.0, 0.0, 0.0) #text
cr.select_font_face("Georgia", #text
cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) #text
cr.set_font_size(1.2) #text
x_bearing, y_bearing, width, height = cr.text_extents("a")[:4] #text
cr.move_to(0.5 - width / 2 - x_bearing, 0.5 - height / 2 - y_bearing) #text
cr.show_text("a") #text
class Paint(Diagram):
def draw_mask(self, cr):
pass
def draw_dest(self, cr):
Diagram.draw_dest(self, cr)
cr.set_source_rgb(0.0, 0.0, 0.0) #paint
cr.paint_with_alpha(0.5) #paint
def draw_src(self, cr):
cr.set_source_rgb(0.0, 0.0, 0.0)
cr.rectangle(0, 0, 1, 1)
cr.fill()
class Mask(Diagram):
def __init__(self, *args):
self.linear = cairo.LinearGradient(0, 0, 1, 1) #mask
self.linear.add_color_stop_rgb(0, 0, 0.3, 0.8) #mask
self.linear.add_color_stop_rgb(1, 0, 0.8, 0.3) #mask
#mask
self.radial = cairo.RadialGradient(0.5, 0.5, 0.25, 0.5, 0.5, 0.75)#mask
self.radial.add_color_stop_rgba(0, 0, 0, 0, 1) #mask
self.radial.add_color_stop_rgba(0.5, 0, 0, 0, 0) #mask
#mask
self.radialinv = cairo.RadialGradient(0.5, 0.5, 0.25, 0.5, 0.5, 0.75)
self.radialinv.add_color_stop_rgba(0, 0, 0, 0, 0)
self.radialinv.add_color_stop_rgba(0.5, 0, 0, 0, 1)
super(Mask, self).__init__(*args)
def draw_mask(self, cr):
cr.save()
cr.rectangle(0, 0, 1, 1)
cr.clip()
Diagram.draw_mask(self, cr, self.radialinv)
cr.restore()
def draw_dest(self, cr):
Diagram.draw_dest(self, cr)
cr.save()
cr.rectangle(0, 0, 1, 1)
cr.clip()
cr.set_source(self.linear) #mask
cr.mask(self.radial) #mask
cr.restore()
def draw_src(self, cr):
cr.set_source(self.linear)
cr.rectangle(0, 0, 1, 1)
cr.fill()
if __name__ == '__main__':
size = 120
Diagram('destination', size, size, [1, 0.15, 0.15])
Diagram('the-mask', size, size, [0.15, 1, 0.15])
Diagram('source', size, size, [0.15, 0.15, 1])
Stroke('stroke', size, size, [1, 0.8, 0.4])
Fill('fill', size, size, [1, 0.8, 0.4])
ShowText('showtext', size, size, [1, 0.8, 0.4])
Paint('paint', size, size, [1, 0.8, 0.4])
Mask('mask', size, size, [1, 0.8, 0.4])