Imagine you want draw two figures with a border, is really easy:
The code is:
#!/usr/bin/python
from gi.repository import Gtk
class MinimalCairoTest(Gtk.Window):
def __init__(self):
super(MinimalCairoTest, self).__init__()
self.set_size_request(300, 300)
self.connect("destroy", Gtk.main_quit)
darea = Gtk.DrawingArea()
darea.connect("draw", self.__draw_cb)
self.add(darea)
self.show_all()
def __draw_cb(self, widget, cr):
cr.set_line_width(10)
cr.set_source_rgb(1.0, 0.0, 0.0)
cr.rectangle(140, 20, 120, 120)
cr.fill_preserve()
cr.set_source_rgb(0.0, 0.0, 1.0)
cr.stroke()
cr.set_source_rgb(1.0, 1.0, 0.0)
cr.arc(150, 150, 70, 0, 2 * 3.14)
cr.fill_preserve()
cr.set_source_rgb(0.0, 1.0, 1.0)
cr.set_line_width(10)
cr.stroke()
MinimalCairoTest()
Gtk.main()
If we want draw the same figures using alpha, we can do:
#!/usr/bin/python
from gi.repository import Gtk
class MinimalCairoTest(Gtk.Window):
def __init__(self):
super(MinimalCairoTest, self).__init__()
self.set_size_request(300, 300)
self.connect("destroy", Gtk.main_quit)
darea = Gtk.DrawingArea()
darea.connect("draw", self.__draw_cb)
self.add(darea)
self.show_all()
def __draw_cb(self, widget, cr):
cr.set_line_width(10)
# now the same but using alpha
cr.set_source_rgba(1.0, 0.0, 0.0, 0.3)
cr.rectangle(140, 20, 120, 120)
cr.fill_preserve()
cr.set_source_rgba(0.0, 0.0, 1.0, 0.3)
cr.stroke()
cr.set_source_rgba(1.0, 1.0, 0.0, 0.3)
cr.arc(150, 150, 70, 0, 2 * 3.14)
cr.fill_preserve()
cr.set_source_rgba(0.0, 1.0, 1.0, 0.3)
cr.set_line_width(10)
cr.stroke()
MinimalCairoTest()
Gtk.main()
No very good. The problem is, the area filled and the border are superposed, because the path is defined by the middle of the stroke, and ignores the line width[1].
I tried use the stroke as a mask, to avoid filling the area defined by the width of the stroke [2]:
#!/usr/bin/python
from gi.repository import Gtk
import cairo
class MinimalCairoTest(Gtk.Window):
def __init__(self):
super(MinimalCairoTest, self).__init__()
self.set_size_request(300, 300)
self.connect("destroy", Gtk.main_quit)
darea = Gtk.DrawingArea()
darea.connect("draw", self.__draw_cb)
self.add(darea)
self.show_all()
def __draw_cb(self, widget, cr):
cr.set_line_width(10)
cr.rectangle(140, 20, 120, 120)
cr.set_source_rgba(1.0, 0.0, 0.0, 0.3)
cr.fill_preserve()
# use the border as a mask
cr.set_operator(cairo.OPERATOR_SOURCE)
cr.set_source_rgba(1.0, 1.0, 1.0, 1)
cr.stroke_preserve()
cr.set_operator(cairo.OPERATOR_OVER)
cr.set_source_rgba(0.0, 0.0, 1.0, 0.3)
cr.stroke()
cr.arc(150, 150, 70, 0, 2 * 3.14)
cr.set_source_rgba(1.0, 1.0, 0.0, 0.3)
cr.fill_preserve()
cr.set_operator(cairo.OPERATOR_SOURCE)
cr.set_source_rgba(1.0, 1.0, 1.0, 1)
cr.stroke_preserve()
cr.set_operator(cairo.OPERATOR_OVER)
cr.set_source_rgba(0.0, 1.0, 1.0, 0.3)
cr.stroke()
MinimalCairoTest()
Gtk.main()
There are a problem: the border looks like if is not transparent. The problem really is the cairo operator source, with white, clear all what is in the surface.
I tried different alternatives, and finally asked in #cairo irc channel. The solution was provided by Søren Sandmann itself:
#!/usr/bin/python
from gi.repository import Gtk
import cairo
class MinimalCairoTest(Gtk.Window):
def __init__(self):
super(MinimalCairoTest, self).__init__()
self.set_size_request(300, 300)
self.connect("destroy", Gtk.main_quit)
darea = Gtk.DrawingArea()
darea.connect("draw", self.__draw_cb)
self.add(darea)
self.show_all()
def __draw_cb(self, widget, cr):
cr.set_line_width(10)
cr.push_group()
cr.rectangle(140, 20, 120, 120)
cr.set_source_rgba(1.0, 0.0, 0.0, 1)
cr.fill_preserve()
cr.set_source_rgba(0.0, 0.0, 1.0, 1)
cr.stroke()
cr.pop_group_to_source()
cr.paint_with_alpha(0.3)
cr.push_group()
cr.arc(150, 150, 70, 0, 2 * 3.14)
cr.set_source_rgba(1.0, 1.0, 0.0, 1)
cr.fill_preserve()
cr.set_source_rgba(0.0, 1.0, 1.0, 1)
cr.stroke()
cr.pop_group_to_source()
cr.paint_with_alpha(0.3)
MinimalCairoTest()
Gtk.main()
Excelent!
And the code is even cleaner. push_group creates a temporary surface, and can be painted, with alpha, using pop_group_to_source and paint_with_alpha.
[1] http://cairographics.org/tutorial/
[2] http://cairographics.org/operators/