Ruby and Graphics

GNOME, GTK+, Cairo and Pango

My burning question

by Brian DeLacey, March 30, 2007; revised April 9, 2007

What if you wanted to create really nice looking graphics? And you wanted a lot of fine-grained, programmatic control over charts and text? Of course, you would want to run it on any platform - Mac, Windows, Linux or maybe even OLPC? Could you render and distribute these images anywhere in the world? Do you want to use paper one day but blast the images over the net in standard formats like PDF, PNG or SVG? Could your browser - any browser - view these?

I thought about these dreams of nice, platform-free, power graphics and weighed a range of alternatives. I knew the kind of thing I wanted to build and what it might look like , the question was how.

This learning journal recaps my work with an interesting set of technologies for graphics imaging and rendering. The big pieces of the technology we'll explore go by the names of GNOME, GTK+, Cairo, and Pango. Hold on as we take a colorful multi-platform ride - it will be a wild trip.

GTK+ and GNOME

Source: Graphics on this page adapted from Ruby-GNOME2 samples.

If you don't like reading documentation and directions, especially after seeing what you can do with this stuff, I can't blame you. So here is a braindead simple way to get going fast on Windows - just make sure you have a recent version of Ruby running () and then install ruby-gnome2-0.16.0-1-i386-mswin32.exe ! Run all the examples. If you get stuck, there are additional installation instructions specifically for Windows. We'll get to Linux, Mac and other platforms in due course.

Things sure would be good if I could do all that in a way that was freely produced, creatively customized, and easily distributed. Well, it looks like mabye I can. In fact, there is an excellent example of this in the form of a graphics editing tool called GIMP

In the beginning, there was GIMP

I did a little bit of Innovation Diving (my term for finding out what is at the bottom of technological innovations) to trace back to some of the original innovators and creators who made this possible.

Like many innovations, GIMP started with an itch needing to be scratched. Salon ran a story on it : "The impetus for creating the Unix-based image-manipulation program was partly necessity." The article quoted Peter Mattis, one of GIMP's original authors: "I wanted to make a Web page at the time, and I couldn't ... It was that simple." [source] Mattis and Spencer Kimball began work on GIMP around August 1995 and released a beta in February 1996. That initial beta relied on Motif, a widget toolkit for building graphical interfaces. Initially, Motif required a commercial license, so the developers of GIMP created GTK as an open source alternative for the future. [source]

The authors were already receiving praiseful comparsions to commercial products in 1997. However, when they graduate that spring of 1997, they largely left GIMP behind. [A good summary of that time is captured in an interview with Stig Hackvan.] It took a while for others to follow in their footsteps and pick up the remaining codebase, but eventually GIMP would come alive again. (GIMP was originally named the General Image Manipulation Program and later renamed to have the "G" represent GNU.)

XCF

GIMP was born into a wizardly corner of the software universe known as the Berkeley eXperimental Computing Facility (XCF) . There have been some good articles written on this bit of digital history (like in Salon and Engineering News) but a book needs to be written to convey the significance of this one project to the open source movement.

Another branch sprouting from this family tree was the GIMP Tool Kit (aka GTK) . This was largely created from code that was refactored by the GIMP developers into libraries for helping to build user interfaces. The three main APIs: GLIB (see the API and manual for descriptions of these commonly used pieces of code), Pango (for text handling) and ATK as the Accessibility Toolkit.

Since GIMP was geered towards bitmap manipulation, the underlying libraries did not include functionality to handle vector graphics (such as draing circles and rectangles.) The authors addressed this point in a January 1, 1997 interview in the GIMP Gazette:

Interviewer: Are you going to implement any drawing primitives at all, like lines and circles and things like that? Why/why not?

Kimball & Mattis: We probably won't implement them for version 1.0. We're a little resistant because our original design specified the GIMP as an image manipulation program and not a painting program. However, they would be fairly easy and it's likely they'll be added sometime simply because we get so much demand for them.

Vector graphics, an important part of a rich graphical user interface, would be added later by a project called Cairo. (There were other graphics technologies and applications developing independently but largely in parallel, such as ImageMagick, with it's elegant Ruby binding called RMagick, but I've settled on tracking Cairo for a variety of personal and technical reasons.)

GIMP was originally written for Unix, but it was ported to Windows by a talented developer named Tor Lillqvist. Each of the key components would be ported over a period of time by a myriad of developers too numerous to mention. In effect, the open source activity took on a life of its own.

Porting GIMP and GDK to different platforms had an interesting side effect, this code became the cross-platform foundation for the libraries and toolkits which now lie beneath the powerful open source operating environments of Ubuntu.

The Hunt for a Graphical Desktop

Along came Miguel de Icaza looking for a way to help Linux applications to co-exist and interoperate more easily. He also was looking for a better graphical desktop. After scanning a few exisitng open source projects, Miguel decided to start a new project he called GNOME (TBD - circa ? August 1997.) His goal was to develop a free GNU/Linux graphical desktop.

Who were the key innovators in the early days of GNOME? You can read de Icaza's beginning history and find out hat this first collaborator was Federico Mena, the maintainer of the GIMP project. Spencer Kimball and Peter Mathis were in the first small group of people Miguel notified of his plans. About two years later, a press release dated March 3, 1999 announced that GNOME 1.0 shipped.

de Icaza won the GNU free software award in 1999, beating out Donald Knuth! An interesting interview, Using the ECMA Standards: An Interview with Miguel de Icaza, captured some of his forward looking thinking of the time. He was recognized by Time as a web pioneer and "Evangelist for Free Software.". A Slashdot article added some revealing insights into the world of free software development. Eventually, after his initial work on GNOME, Miguel started a company called Ximian and a project called Mono (but that is a long, long story with many seemingly foggy sidepaths showing the complexities of blending open source and commercial initiatives .)

The GNOME Foundation was established in August 2000. Eventually, Red Hat Linux had a very positive impact on GNOME's progress by dedicating funded developers to make contributions. (The original Cairo spec and architecture was developed by a Red Hat employee, Carl Worth.) Other corporate supporters of the GNOME foundationi included Sun, HP, and IBM.

An overview of GNOME can be found online as part of the Gnome Documentation Project. If you want to write programs in C, try The Official GNOME 2 Developer's Guide by Matthias Warkus.

For those who are more graphically inclined, there is a good slideshare overview of Gnome on the Gnome Korea website. A PDF of the Gnome presentation is also available. Here's a concise and elegant graphic that shows the major architecture of GNOME today::

Source: gnome.or.kr

Wikipedia provides nice, quick descriptions of Bonobo, GLIB, XLIB, GDK and GTK+.

NOTE: " The GDK library provides a layer of abstraction that sits between GTK+ widgets and applications and the underlying windowing system. Instead of making calls directly to the X window system, applications call GDK when they need to draw to the screen or handle events." [source]

Progress

There has been a steady progression of GNOME Releases which are intertwined with the parallel progress of other open source projects, such as GDK+ and Cairo. A summary of the release history for GNOME, GTK, and Cairo is provided here.

If you want to see the kinds of things you can build with Gnome, just look at some of the available sample code. You can see some cool graphic power in action by clicking on these PNG files:

image patterns,

user interface elements

widgets.

Take a second look. This stuff is impressive and there is more in stock! There were a lot of nice developers and designers who shared these as open source. Hooray!.

But if you want to get the straight scoop from the foundations behind these technologies, check out the GTK website and also the Gnome Foundation website. GTK+ and all of Gnome is developed in the C language, which makes it highly portable. It also has been developed in an object oriented way. (This is where the Ruby story fits in nicely. We'll cover a little more ground and get to Ruby shortly.)

The Big Release...

In the life cycle of every software product I've worked on, there have been a few big, momentous, groundbreaking releases. Although I'm new to Gnome, it seems like Gnome 2.8 Desktop was a big one. The release date was September 15, 2004, according to the foundation's press release. The functionality of that release is captured in the user documentation published by Sun. The Gnome Journal did a nice job walking through the major changes in functionality.

Support for Cairo was building through that year. In July 2005, one blogger noted the trend: "The big news at the conference was the integration of GNOME/librsvg and cairo. Several people were experimenting with use of cairo for rendering the desktop widgets and such. ... Cairo seems to have reached a point where it is a viable replacement for the libart-based rendering code in librsvg, and work is progressing with that goal in mind." That blogger was also a technically savvy contributor to Inkscape and wrote about the technical merits of Cairo: "The good news is that Cairo itself is designed as a dynamic drawing library. It does not hold state on the items being drawn, and depends on higher level code to track the drawing elements. ... I think this will touch a LOT of the Inkscape code, but on the plus side by replacing the rendering code it should really cut down the amount of code we will have to maintain inside Inkscape." [source]

But the even bigger 2.8 announcement might have been almost a year later, when GTK+2.8 shipped.

GTK+ 2.8 was released in August 2005, and there is a good description along with that press release. (This is well worth reading if you want to understand the technology- where else but in an open source press release would you also get an excellent technical treatise!)

Traveling through Cairo

This transition to Cairo ushered in a new, better future for rendering on Gnome.

GTK+ 2.8 required Cairo, according to release notes, and would be used to render most of its widgets. With Cairo technology, application imagings start to get really interesting.

According to the website for Cairo, it "is a 2D graphics library with support for multiple output devices." What this means to me is that it can serve as the underlying graphics engine for all the work that is done in computers - and this is particularly valuable when it comes to creating documents for output in varied formats. The functionality should be familiar to most computer users:

"The cairo API provides operations similar to the drawing operators of PostScript and PDF. Operations in cairo including stroking and filling cubic Bézier splines, transforming and compositing translucent images, and antialiased text rendering. All drawing operations can be transformed by any affine transformation (scale, rotation, shear, etc.)" [source]

Cairo is free, open source and multi-platform. It makes a very interesting graphics story. Mozilla has picked up Cairo as the underpinning of Gecko and its <canvas> tag. If you really want to learn about more of the internal design and architecture of Cairo, you can read some of the papers and presentations prepared by the Cairo's main original architect, Carl D. Worth. You can find an exellent tutorial on how to work with Cairo, but it is written for Python Programmers. Any volunteers willing to translate it into Ruby?

There's one other aspect of all this rendering and imaging that is really important - and that would be the internationalization considerations. Gnome has surely been smart about this, as is evident in Gnome's choice of technologies and covered in their documentation on internationalization. In particular, there is a wonderful library called Pango that helps you can read all about it at RedHat's website, in a presentation by Owen Taylor.

Pango version 1.0 was released in March 2002. (The detailed features and an overview from thta time can be found in the release notes.) Wikipedia provides a starting point to learn a bit about this library. You might also want to visit Pango's own homepage, or this two-part article at IBM's always-informative developerWorks site.

You can find more technical reference on Pango and a whole lot more at the Gnome developer platform libraries website. There is also a technical reference manual for Cairo.

GNOME2, Ruby, and Cairo

So where does Ruby fit in?

I like working in Ruby. It's such a great language. But it's a little lacking in its graphical talents. Or is it? For instance, did you know that Matz was the first person to release a build of Ruby-GTK way back on January 14, 1998? Maybe Ruby's graphical garden was planted long ago and is just takin time to grow..

August 1999 was the independent kick-off of Ruby-GNOME. Eventually, GNOME grew into GNOME2, with Ruby-GNOME2 (by Masao Mutoh and Kubo Takehiro) appearing in 2002.

What is Ruby-GNOME2?

According to the creators: "Ruby-GNOME2 is a binding for the Ruby language to use the GTK library, as well as some of the GNOME libraries. Ruby-GNOME2 provides a way to create a GUI frontend for anything you can write in Ruby." [source]

Gnome and GTK+ et. al. are written in an object-oriented way. This makes it nice - very nice - and amenable to working with object-oriented Ruby. The RCairo bindings give you access to the full power of Cairo in a very elegant and Ruby-beautiful wayl. So I ventured off in this direction - a nice mix of open source, cross platform, free wares I thought. I couldn't ask for much more than that!

The collection of Ruby bindings to GTK+ are also known as Ruby-Gnome2. GNOME2 currently requires Cairo, and thus to make GNOME2 accessible by Ruby you need bindings, which are called RCairo - which has had the following major public releases:

[1.4.1 (2007-03-10)] [1.4.0 (2007-03-06)] [1.2.0 (2006-07-01)] [1.0.0 (2005-10-16)]

These bindings give you access to the inner workings of GTK+, in general, and Cairo in particular.

Installation Gets Better and Easier All The Time

It's a great time to get involved with Ruby-GNOME2. The News for the February 12, 2007 release of the Win32 GUI installer reported a number of improvements to make life a whole lot easier!

What do you actually get when you install Ruby-GNOME2? Well, you get a lot of access to the GNOME developer environment accessible through Ruby bindings. Here's the list as of 3/30/2007 and you can visit the Ruby-GNOME2 API Reference for added detail::

Libraries
---------
  - Ruby/GLib2
  - Ruby/ATK
  - Ruby/Pango
  - Ruby/GdkPixbuf2
  - Ruby/GTK2
  - Ruby/Libglade2
  - Ruby/GtkGLExt
  - Ruby/Libart2
  - Ruby/GnomeCanvas2
  - Ruby/GnomePrint2
  - Ruby/GnomePrintUI2
  - Ruby/GtkSourceView
  - Ruby/RSVG2

  External libraries
  - rcairo-1.2.6

You can also see the list of all the files and libraries in the installation release notes here. Try to install \ Ruby-GNOME2 and see if it works! (I've now done it successfully on Windows and Ubuntu. I had a few problems on Windows, but that's because I made it more complex than it actually is. I originally thought I needed to install all the individual libraries separately. I went looking for GDK and GTK+ and Cairo/Rcairo and Glade and GNOME, and the GDK developer kit. I found a lot and insatlled a lot. In retrospect, that wasn't a very good idea! I knew I needed to retrace my steps when I couldn't see any fonts in one of the GTK+ programs, but it was a learning experience.

The fix was pretty simple: I uninstalled all these new pieces, and read up the documentation enough to get a better handle on this. I also took the opportuinty to upgrade to the latest version of Ruby:

Ruby 1.8.6 (2007-03-13 patchlevel 0) [i386-mswin32]

All I needed for Ruby-Gnome2 on Windows was one very simple install: ruby-gnome2-0.16.0-1-i386-mswin32.exe ! You can add ruby-gnome2 to Ubuntu as you would any new software.

It's easy to test the integraity of your installation with the following console commands:

C:\>ruby -v

C:\>ruby -e "require 'gtk2'"

C:\>ruby -rgtk2 -e "Gtk::Window.new.show;Gtk.main

If you get a bunch of error messages, you have install problems to fix. Otherwise, have fun!

There are additional installation instructions at the Ruby-Gnome2 project site, with details of components posted here, there are also installation instructions specifically for Windows.

After I correctly completed the installation, everything has worked very smoothly. The incredible collection of sample programs, which are written in pure, elegant Ruby and included in the default installation files, is enormous. And if you somehow manage to go through that collection and not find what you need, there is a huge world of Gnome2 code in Python ready for your interpretation.

Starter's Guide for using Cairo and Pango

The definitive reference manual for Cairo: A Vector Graphics Library is located at the software's website. It will take some mental manipulations to translate this C into Ruby.

Kou has created a repository for online rcairo documentation and there is also a mailing list. The documentation will be written in the Ruby Document (RD) markup language. You can dowlnload the RDtool for converting documents written in RD into HTML. I am running RDtool on Ubuntu.

Using RD is very easy, as described in this helpful README - I have also posted a document describing the RD markup language- Both of these documents are included in the RDtool distribution - as far as I know these are available under the same Ruby license as the software and I assume was created by MoonWolf. I have posted these because it is quite hard to find information on this easy-to-use mark-up format via the usual Google'ing methods. (The README and rd-draft files I posted here are part of the documentation you get along with a download of RDtool.)

There is little written up on RD in the available books on Ruby. There is a comparison of RDtool vs RDoc at the RDoc website. Some of the features that RDoc has built in, such as extracting class, module, method and other information can also be nicely achieved with RDtool, as shown in the script used by Kou for producing RD extracts for rcairo. RD is quite good for handling Ruby-friendly international project activities. A good way to quickly learn RD is to consider an RD document alongside it's resulting HTML document. Here are three pairs:

  1. RD Readme in RD format and the same Readme in HTML
  2. RD markup language spec in RD and the same markup lanague spec in HTML
  3. My simple sample document in RD and also in HTML

From time to time, I may edit / update interim, supplemental documents in my Ruby Cairo Toolbox.

The Cairo developers have done a nice job planning for bindings by other languages, stating " While cairo is implemented and C, and has a C API, it is expected that many users of cairo will be using it from languages other than C. The glue that connects the core cairo library to another language is known as a language binding. " You can check out their guidelines and explicit documentation on how to create bindings .

With the supporting encouragement of Michael Urman, we'll be translating his excellent Cairo Tutorial for Python Programmers into Ruby-speak. In the meantime, here are some very high level the generic steps for creating graphics/text with Cairo/Pango:

Some examples are available in Python, like this Ars Technica article when 2.8 was released

What makes all this magical software run so smoothly?

There are a lot of generous people behind the efforts to develop Ruby-GNOME2 - geniuses who make code like Cairo sing across multiple platforms. And a small handful of this team crafts the elegant connections with Ruby . Evan Marin did some early work with Ruby and Cairo:

"I was a GTK enthusiast and developer so I heard about Cairo pretty early on in the development of the project (GTK before version 2.8 or so didn't use Cairo).  And then I was a Ruby enthusiast and noticed nobody had written code to use Cairo from Ruby, so I thought I'd contribute a little bit there. I announced some very preliminary but working code on the Cairo mailing list and they immediately gave me access to commit it to the Cairo repository."

Evan noted, in good spirited fashion, that all of his early contribution have been scrapped and rewritten by now. My view here is that systems evolves and good code gets better. On Friday, November 26, 2004, MenTaLguy posted this message to a Cairo list at freedesktop.org list:

"Has anyone else done a Ruby binding for Cairo yet? I have a fairly complete one finished at this point, but I'm not sure what to do with it..."

Less than a day later, on Saturday, November 27, 2004, Øyvind Kolås wrote a reply:

"There is also one in the Cairo CVS, in the rcairo module.

http://cvs.freedesktop.org/cairo/rcairo

Is your binding available somewhere on the net? There shouldn't be much problems incorporating code from one to the other, hopefully there haven't been too much duplication of effort."

The two got together, taking most of what MenTaLguy had written as the more complete binding and merging in what Øyvind Kolås had written.

If you look through the binding-related code, you'll see lots of copyrights by MenTaLguy beginning in 2004. Visit MenTaLguy's web presence at Moonbase website for more on his latest happenings - his Ruby knowledge is deep, as evidenced by his online Ruby-related posts.

Øyvind Kolås has some fascinating work on the "Generic Graphics Library" (e.g. GEGL) that is a nice blend of photography, image processing and art. You can visit his a blog and website for more.

To this day, http://webcvs.freedesktop.org/cairo/rcairo/ hosts the cairo project and has the latest released sources of rcairo. The forces behind rcairo grew stronger with the addition of Kou.

Kouhei Sutou appears in rcairo's header files starting in 2005. Kou had been working on Ruby-GNOME2 and other extension libraries when he got interested in rcairo. Since then, Kou has been a prolific contributor and leads rcairo development today. I asked Kou about rcairo's architecture:

"rcairo is just bindings of cairo. Yes, I added some Ruby-ish interfaces (e.g. block notation, optional arguments, using Hash/Array instead of cairo's data type and so on) but there are big functional changes. Ah, I'll add some high level APIs to rcairo."

I dug into the source code a bit to see what I could learn. (The following is my best understanding thus far, but I expect to revise it with corrections and a better understanding in the future.)

Consider the binding for Cairo's cr_arc routine as defined in rb_cairo_contexts:

static VALUE
cr_arc (VALUE self, VALUE xc, VALUE yc, VALUE radius,
        VALUE angle1, VALUE angle2)
{
  cairo_arc (_SELF, NUM2DBL (xc), NUM2DBL (yc), NUM2DBL (radius),
             NUM2DBL (angle1), NUM2DBL (angle2));
  cr_check_status (_SELF);
  return self;
}

Further down in this file we see how the ruby method name for arc is eventually defined:

rb_define_method (rb_cCairo_Context, "arc", cr_arc, 5);

How does Kou extend Cairo for Ruby? Kou pointed me to the rcairo directory where new functionality can be added in the comfort of modules and classes: src/lib/cairo/context/*.rb Consider, for example, the file src/lib/cairo/context/circle.rb. This contains the following code:

      def circle(x, y, radius)
        arc(x, y, radius, 0, 2 * Math::PI)
      end

Here you can see an extension, where Kou adds code to define a circle, something that isn't native to Cairo but is used frequently in graphics applications. If I want to make circles, in a high level language, across all the major platforms, circle(x, y, radius) seems like a terrific way to do it! Kou also addes a more involved method for creating rectangles with rounder corners, building on Cairo's native definition of rectangle. I'll leave it to you to find that one in the source code.

Kou takes time to keep the Ruby bindings in synch with new developments by the Cairo team. He reads through the committed changes being made to Cairo and, whenever interesting APIs have been added, Kou will implement those for rcairo. But he does more than simply transfer C APIs. Instead, he applies his extensive Ruby knowledge to craft hand-tailored Ruby-ish interfaces (e.g. block notation, optional arguments using Hash/Array instead of cairo's data type.) Each new release of cairo is followed by a new release of rcairo. Kou has a number of great ideas for future releases.

Kou's responsivness and help across multiple mailing lists is all the more remarkable given his expansive list of project activities. In addition to rcairo, Kou is involved with Rabbit, Ruby/RSVG, Ruby/Poppler (for rendering PDFs), Ruby/VTE, RSS Parser (including in Ruby standard distribution), Ruby/Subversion, RAA:gdchart, RAA:gallery, ActiveLdap, ActiveSambaLdap, RWiki, and some libraries/applications for Ruby, C and Gauche (a Scheme interpreter.)

Sometimes, just knowing what needs to be done is all it takes to welcome in a new volunteer.

I asked Kou how the community might help and here are some ideas:

Here's your chance to help out on a very signficant open source project that has the potential for a huge impact on the computing industry.

This brings to a close our little tour from GNOME2, with Ruby, through Cairo. Hope you had fun!

Appendix

Some links you might be interested in:

Sample Code

You will find samples in both rcairo-1.2.0 and rcairo-1.4.1 - note that the version of rcairo you use must correspond to the version of Cairo that you are using.

An interesting side note is Gnome's Code of Conduct - which seems like a pretty good set of guidelines for any community and cooperative effort.