Home  Contents

Painting with Cairo

In this part of the PHP GTK tutorial, we will do some painting with the Cairo library. Currently, Seed supports only a small portion of the Cairo library.

Cairo is a library for creating 2D vector graphics. We can use it to draw our own widgets, charts or various effects or animations.

Cairo for PHP is a separate project from PHP GTK. In addition to PHP GTK, we need to install Cairo too. Prior to building the library, we must have libcairo2-dev package installed on our system.

svn co http://svn.php.net/repository/pecl/cairo/trunk cairo
cd cairo/
$ phpize5
$ ./configure 
$ make
$ make install

The above commands were used to install Cairo for PHP at the time of the creation of this tutorial.

Finally, after we have installed Cairo, we need to enable Cairo library for our PHP scripts.

$ sudo vi /etc/php5/cli/php.ini 

;;;;;;;;;;;;;;;;;;;;;;
; Dynamic Extensions ;
;;;;;;;;;;;;;;;;;;;;;;

;
extension=php_gtk2.so
extension=cairo.so

We edit the php.ini file and add the Cairo dynamic extension.

Colors

In the first example, we will work with colors. A color is an object representing a combination of Red, Green, and Blue (RGB) intensity values. Cairo valid RGB values are in the range 0 to 1.

<?php
 
/* 
ZetCode PHP GTK tutorial

In this program, we will draw three
colored rectangles on the drawing area
using Cairo.

author: Jan Bodnar
website: www.zetcode.com
last modified: August 2011
*/

class Example extends GtkWindow { 
     

    public function __construct() { 

        parent::__construct(); 
         
        $this->init_ui();

    } 

    public function init_ui() {

        $this->set_title('Colors');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $darea = new GtkDrawingArea();
        $darea->connect('expose_event', array($this, 'on_expose')); 
        
        $this->add($darea);    

        $this->set_default_size(360, 100); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }

    public function on_expose($darea, $event) {

            $cr = $darea->window->cairo_create();
            $this->draw_colors($cr);        
   
    }

    public function draw_colors($cr) {
    
        $cr->setSourceRgb(0.2, 0.23, 0.9);
        $cr->rectangle(10, 15, 90, 60);
        $cr->fill();
        
        $cr->setSourceRgb(0.9, 0.1, 0.1);
        $cr->rectangle(130, 15, 90, 60);
        $cr->fill();

        $cr->setSourceRgb(0.4, 0.9, 0.4);
        $cr->rectangle(250, 15, 90, 60);
        $cr->fill();            
    }   
} 
     
new Example(); 
Gtk::main();
 
?>

In our example, we will draw three rectangles and fill them with three different colors.

$darea = new GtkDrawingArea();

We will be doing our drawing operations on the GtkDrawingArea widget.

$darea->connect('expose_event', array($this, 'on_expose')); 

When the window needs to be redrawn, the the expose_event is triggered. In response to this event, we call the on_expose() method.

$cr = $darea->window->cairo_create();

We create the cairo context object from the GdkWindow of the drawing area. The context is an object onto which we do all our drawings.

$this->draw_colors($cr);   

The actual drawing is delegated to the draw_colors() method.

$cr->setSourceRgb(0.2, 0.23, 0.9);

The setSourceRgb() method sets a color for the cairo context. The three parameters of the method are the color intensity values.

$cr->rectangle(10, 15, 90, 60);

We draw a rectangle. The first two parameters are the x, y coordinates of the top left corner of the rectangle. The last two parameters are the width and height of the rectangle.

$cr->fill();

We fill the inside of the rectangle with the current color.

Colors
Figure: Colors

Basic shapes

The next example draws some basic shapes onto the window.

<?php
 
/* 
ZetCode PHP GTK tutorial

This code example draws basic shapes
with the Cairo library.

author: Jan Bodnar
website: www.zetcode.com
last modified: August 2011
*/

class Example extends GtkWindow { 
     

    public function __construct() { 

        parent::__construct(); 
         
        $this->init_ui();

    } 

    public function init_ui() {

        $this->set_title('Basic shapes');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $darea = new GtkDrawingArea();
        $darea->connect('expose_event', array($this, 'on_expose')); 
        
        $this->add($darea);    

        $this->set_default_size(390, 240); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }

    public function on_expose($darea, $event) {

        $cr = $darea->window->cairo_create();
        $this->draw_shapes($cr);        

    }

    public function draw_shapes($cr) {
    
        $cr->SetSourceRgb(0.6, 0.6, 0.6);

        $cr->rectangle(20, 20, 120, 80);
        $cr->rectangle(180, 20, 80, 80);
        $cr->fill();

        $cr->arc(330, 60, 40, 0, 2*M_PI);
        $cr->fill();
        
        $cr->arc(90, 160, 40, M_PI/4, M_PI);
        $cr->fill();

        $cr->translate(220, 180);
        $cr->scale(1, 0.7);
        $cr->arc(0, 0, 50, 0, 2*M_PI);
        $cr->fill();          
    }   
} 
     
new Example(); 
Gtk::main();
 
?>

In this example, we will create a rectangle, a square, a circle, an arc and an ellipse. We draw outlines in blue color, insides in white.

$cr->rectangle(20, 20, 120, 80);
$cr->rectangle(180, 20, 80, 80);
$cr->fill();

These lines draw a rectangle and a square.

$cr->arc(330, 60, 40, 0, 2*M_PI);
$cr->fill();

Here the arc() method draws a full circle.

$cr->translate(220, 180);
$cr->scale(1, 0.7);
$cr->arc(0, 0, 50, 0, 2*M_PI);
$cr->fill();  

The translate() method moves the object to a specific point. If we want to draw an oval, we do some scaling first. Here the scale() method shrinks the y axis.

Basic shapes
Figure: Basic shapes

Transparent rectangles

Transparency is the quality of being able to see through a material. The easiest way to understand transparency is to imagine a piece of glass or water. Technically, the rays of light can go through the glass and this way we can see objects behind the glass.

In computer graphics, we can achieve transparency effects using alpha compositing. Alpha compositing is the process of combining an image with a background to create the appearance of partial transparency. The composition process uses an alpha channel. (wikipedia.org, answers.com)

<?php
 
/* 
ZetCode PHP GTK tutorial

This code example draws nine rectangles
with different levels of transparency.

author: Jan Bodnar
website: www.zetcode.com
last modified: August 2011
*/

class Example extends GtkWindow { 
     

    public function __construct() { 

        parent::__construct(); 
         
        $this->init_ui();

    } 

    public function init_ui() {

        $this->set_title('Transparent rectangles');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $darea = new GtkDrawingArea();
        $darea->connect('expose_event', array($this, 'on_expose')); 
        
        $this->add($darea);    

        $this->set_default_size(590, 90); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }

    public function on_expose($darea, $event) {

        $cr = $darea->window->cairo_create();
        $this->draw_recs($cr);        

    }

    public function draw_recs($cr) {

        for ($i=1; $i<=10; $i++) {
            $cr->SetSourceRgba(0, 0, 1, $i*0.1);
            $cr->rectangle(50*$i, 20, 40, 40);
            $cr->fill();
        }     
    }   
} 
     
new Example(); 
Gtk::main();
 
?>

In the example we will draw ten rectangles with different levels of transparency.

$cr->SetSourceRgba(0, 0, 1, $i*0.1);

The last parameter of the set_source_rgba() method is the alpha transparency.

Transparent rectangles
Figure: Transparent rectangles

Donut

In the following example we create a complex shape by rotating a bunch of ellipses.

 
<?php
 
/* 
ZetCode PHP GTK tutorial

In this program, we draw a donut shape
by rotating a bunch of ellipses. 

author: Jan Bodnar
website: www.zetcode.com
last modified: August 2011
*/

class Example extends GtkWindow { 
     

    public function __construct() { 

        parent::__construct(); 
         
        $this->init_ui();

    } 

    public function init_ui() {

        $this->set_title('Donut');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $darea = new GtkDrawingArea();
        $darea->connect('expose_event', array($this, 'on_expose')); 
        
        $this->add($darea);    

        $this->set_default_size(350, 250); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }

    public function on_expose($darea, $event) {

            $cr = $darea->window->cairo_create();
            $this->draw_donut($cr);        
   
    }

    public function draw_donut($cr) {
    
        $cr->SetLineWidth(0.5);

        $w = $this->get_allocation()->width;
        $h = $this->get_allocation()->height;
       
        $cr->translate($w/2, $h/2);
        $cr->arc(0, 0, 120, 0, 2*M_PI);
        $cr->stroke();
         
        for ($i=1; $i<=36; $i++) {
            $cr->save();
            $cr->rotate($i*M_PI/36);
            $cr->scale(0.3, 1);
            $cr->arc(0, 0, 120, 0, 2*M_PI);
            $cr->restore();
            $cr->stroke();
        }
    }   
} 
     
new Example(); 
Gtk::main();
 
?>

In this example, we create a donut. The shape resembles a cookie, hence the name donut.

$cr->translate($w/2, $h/2);
$cr->arc(0, 0, 120, 0, 2*M_PI);
$cr->stroke();

In the beginning there is an ellipse.

for ($i=1; $i<=36; $i++) {
    $cr->save();
    $cr->rotate($i*M_PI/36);
    $cr->scale(0.3, 1);
    $cr->arc(0, 0, 120, 0, 2*M_PI);
    $cr->restore();
    $cr->stroke();
}

After several rotations, there is a donut.

Drawing text

In the next example, we draw some text on the window.

<?php
 
/* 
ZetCode PHP GTK tutorial

In this program, we draw text on the
window. 

author: Jan Bodnar
website: www.zetcode.com
last modified: August 2011
*/

class Example extends GtkWindow { 
     

    public function __construct() { 

        parent::__construct(); 
         
        $this->init_ui();

    } 

    public function init_ui() {

        $this->set_title('Soulmate');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $darea = new GtkDrawingArea();
        $darea->connect('expose_event', array($this, 'on_expose')); 
        
        $this->add($darea);    

        $this->set_default_size(350, 250); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }

    public function on_expose($darea, $event) {

            $cr = $darea->window->cairo_create();
            $this->draw_text($cr);        
   
    }

    public function draw_text($cr) {
    
        $cr->SetSourceRgb(0.1, 0.1, 0.1);
         
        $cr->SelectFontFace("Purisa", CairoFontSlant::NORMAL, 
            CairoFontWeight::NORMAL);
        $cr->SetFontSize(13);
       
        $cr->MoveTo(20, 30);
        $cr->ShowText("Most relationships seem so transitory");
        $cr->MoveTo(20, 60);
        $cr->ShowText("They're all good but not the permanent one");
        $cr->MoveTo(20, 120);
        $cr->ShowText("Who doesn't long for someone to hold");
        $cr->MoveTo(20, 150);
        $cr->ShowText("Who knows how to love without being told");
        $cr->MoveTo(20, 180);
        $cr->ShowText("Somebody tell me why I'm on my own");
        $cr->MoveTo(20, 210);
        $cr->ShowText("If there's a soulmate for everyone");
    }   
} 
     
new Example(); 
Gtk::main();
 
?>

We display part of the lyrics from the Natasha Bedingfields Soulmate song.

$cr->SelectFontFace("Purisa", CairoFontSlant::NORMAL, 
    CairoFontWeight::NORMAL);

Here we specify the font that we use. Purisa normal.

$cr->SetFontSize(13);

We specify the size of the font.

$cr->MoveTo(20, 30);

We move to the point, where we will draw the text.

$cr->ShowText("Most relationships seem so transitory");

The ShowText() method draws text onto the window.

Soulmate
Figure: Soulmate

In this chapter of the PHP GTK tutorial, we were painting with Cairo library.