Using the Cairo Graphics library with Delphi
Written by Jens Christian Rodi Hansen, October 27th 2008
I've been investigating the possibility of using the Cairo Graphics library with Delphi for some time now. Though it has bindings for a lot of programming languages, there doesn't seem to exist an official Delphi binding. It is of course possible to port a C binding to Pascal but given the extend of the library API, that's a rather big job to do and to maintain when new release are released. This made me initially drop the idea.
Recently I discovered that Free Pascal has pascal interfaces for GTK+. This also includes bindings for the Cairo Graphics library and given it's written for Free Pascal, the work required to port it to Delphi is very small and hence supporting future updates is not that big a deal. With little work I came up with a set of Delphi bindings interfacing to the standard Cairo library (libcairo-2.dll), the Win32 support functions and the FreeType functions.
Cairo Graphics Delphi Bindings
Version 1.0 for Cairo Graphics Version 1.8
Cairo Graphics Delphi Example
These bindings will add a few requirements to the final program. The main Cairo DLL (libcairo-2.dll) and support DLL's (libpng12-0.dll and zlib1.dll) must be present for the basic library to work, all available for download from the GTK+ site. FreeType support will add the FreeType DLL (freetype-6.dll) which is available at the FreeType site.
Getting started with Cairo Graphics is rather easy. Extract the pascal bindings and DLL's to the application folder and add "Cairo" and "CairoWin32" to the uses clause. Here is a simple example of drawing with Cairo functions:
procedure DrawWithCairo(pb:TPaintBox); var cr : Pcairo_t; surface : Pcairo_surface_t; begin surface := cairo_win32_surface_create(pb.Canvas.Handle); cr := cairo_create(surface); cairo_scale(cr,pb.Height,pb.Height); // Draw the entire context white cairo_set_source_rgba(cr,1,1,1,1); cairo_paint(cr); // Translate to the center and draw a black clock outline cairo_set_source_rgba(cr,0,0,0,1); cairo_translate(cr,0.5,0.5); cairo_arc(cr,0,0,0.4,0,pi*2); cairo_stroke(cr); cairo_destroy(cr); cairo_surface_destroy(surface); end;
One of the problems with code above is that it flickers when repainted. I've not yet been able to find any official Cairo way of selecting double-buffering, which would remove this flickering. But an alternate and easy solution is to render onto a bitmap surface and then, at the end, copy that to the Windows device context. First create a bitmap surface instead:
surface := cairo_win32_surface_create_with_dib(CAIRO_FORMAT_ARGB32,pb.Width,pb.Height);
Then, before destroying the surface, copy it to the Windows device context to display it:
cairo_destroy(cr); BitBlt(pb.Canvas.Handle,0,0,pb.Width,pb.Height,cairo_win32_surface_get_dc(surface),0,0,SRCCOPY); cairo_surface_destroy(surface);