tclcairo

tclcairo

DDG - 2012-03-07: Swig based binding for tcl for the cairo library. Can be used to produce, png, pdf, ps and svg files using the same API. Provided as a starkit for Tclkit 8.4, 8.5 and 8.6 with compiled binaries for Win32-x86 and Linux-x86

DDG - 2020-04-19: Updates for 64bit and Cairo 1.16 and snit wrapper widget added

Example session:

[email protected](7:1441):mytcl$ tclkit-8.4.19
% source tclcairo1.10.2.kit
% package require cairo
0.1
% glob tclcairo1.10.2.kit/lib/*
tclcairo1.10.2.kit/lib/tclcairo1.10.2
glob tclcairo1.10.2.kit/lib/*/*
tclcairo1.10.2.kit/lib/tclcairo1.10.2/cairo-test.tcl tclcairo1.10.2.kit/lib/tclcairo1.10.2/cairo.i 
tclcairo1.10.2.kit/lib/tclcairo1.10.2/libcairo.dll tclcairo1.10.2.kit/lib/tclcairo1.10.2/libcairo.so  
tclcairo1.10.2.kit/lib/tclcairo1.10.2/pkgIndex.tcl 
% lrange [lsort [info commands cairo::*]] 0 10
::cairo::_cairo_path_data_t ::cairo::_cairo_path_data_t_header ::cairo::_cairo_path_data_t_header_get 
::cairo::_cairo_path_data_t_header_length_get ::cairo::_cairo_path_data_t_header_length_set 
::cairo::_cairo_path_data_t_header_type_get ::cairo::_cairo_path_data_t_header_type_set 
::cairo::_cairo_path_data_t_point ::cairo::_cairo_path_data_t_point_get ::cairo::_cairo_path_data_t_point_x_get 
::cairo::_cairo_path_data_t_point_x_set

% source tclcairo1.10.2.kit/lib/tclcairo1.10.2/cairo-test.tcl
% exit
[email protected](7:1442):mytcl$ ls -lt | head
insgesamt 55828
-rw-r--r-- 1 usern users      254  7. Mär 15:07 cairo-test2.png
-rw-r--r-- 1 usern users      929  7. Mär 15:07 test.pdf
-rw-r--r-- 1 usern users     2503  7. Mär 15:07 test.ps
-rw-r--r-- 1 usern users      484  7. Mär 15:07 test.svg

If the library loading on windows fails try the larger windows starkit which contains as well cairo, zip and png shared libs.

Ok let's create a PDF-file having a red rectangle:

package require cairo
set surface [::cairo::cairo_pdf_surface_create test.pdf 300 300]
set cr [::cairo::cairo_create $surface]
::cairo::cairo_rectangle $cr 10 10 40 40
::cairo::cairo_set_source_rgb $cr 1 1 1
::cairo::cairo_fill $cr
::cairo::cairo_rectangle $cr 20 20 20 20
::cairo::cairo_set_source_rgb $cr 1 0 0
::cairo::cairo_fill $cr
::cairo::cairo_show_page $cr
::cairo::cairo_surface_flush $surface
::cairo::cairo_surface_destroy $surface
::cairo::cairo_destroy $cr

If you would like to create the same as svg just a replacemment of the first line is needed:

set surface [::cairo::cairo_svg_surface_create test.svg 300 300]
set cr [::cairo::cairo_create $surface]
::cairo::cairo_rectangle $cr 10 10 40 40
::cairo::cairo_set_source_rgb $cr 1 1 1
::cairo::cairo_fill $cr
::cairo::cairo_rectangle $cr 20 20 20 20
::cairo::cairo_set_source_rgb $cr 1 0 0
::cairo::cairo_fill $cr
::cairo::cairo_show_page $cr
::cairo::cairo_surface_flush $surface
::cairo::cairo_surface_destroy $surface
::cairo::cairo_destroy $cr

You have to use the C-API documentation provided here: http://cairographics.org/manual/ A tcl wrapper using an OO-framework like Snit or Itcl would be greet in making it more Tcl-ish.

Swig wrapper

file: cairo.i

%module cairo
%{
#include <cairo-features.h>    
#include <cairo.h>   
#include <cairo-version.h>
#include <cairo-pdf.h>    
#include <cairo-ps.h>        
#include <cairo-svg.h>    
%}
%include "/usr/include/cairo/cairo-features.h"
%include "/usr/include/cairo/cairo.h"
%include "/usr/include/cairo/cairo-version.h"
%include "/usr/include/cairo/cairo-pdf.h"
%include "/usr/include/cairo/cairo-svg.h"
%include "/usr/include/cairo/cairo-ps.h"

This file is translated into c-code using swig and compiled using gcc and compressed using upx:

$ swig -tcl -namespace cairo.i
$ gcc -shared -fPIC -DUSE_TCL_STUBS \
-I/usr/include/cairo -I/opt/tcl/include cairo_wrap.c -o libcairo.so \
-lcairo -L/opt/tcl/lib -ltclstub8.4
$ upx libcairo.so

As I could not compile cairo on OSX-X the starkit does not contain libraries for OS-X.

Snit Widget

DDG - 2020-04-19: Here a snit wrapper widget for display dynamically the commands in a ttk::label.

package require snit
snit::widget cimage {
    option -width 100
    option -height 100
    variable surface
    variable history [list]
    variable cr
    variable pngfile
    constructor {args} {
        $self configurelist $args
        pack [ttk::label $win.img -text "Hello"] ;#  -in $win -width $options(-width) -height $options(-height)
        set surface [::cairo::cairo_image_surface_create 0 $options(-width) $options(-height)]
        set cr [::cairo::cairo_create $surface]
        set pngfile [file tempfile].png
        ::cairo::cairo_rectangle $cr 1 1 [expr {$options(-width)-2}] [expr {$options(-height)-2}]
        ::cairo::cairo_set_source_rgb $cr 1 1 1
        ::cairo::cairo_fill $cr
        $self cairo update

    }
    method cairo {cmd args} {
        # these lists must be updated with more commands
        # doing automatic updates
        if {[lsearch [list update fill show_text] $cmd] >= 0} {
            if {[lsearch [list fill show_text] $cmd] >= 0} {
                ::cairo::cairo_$cmd $cr {*}$args
                lappend history [list $cmd $args]
            }
            ::cairo::cairo_show_page $cr
            ::cairo::cairo_surface_write_to_png $surface $pngfile
            catch rename imgPng ""
            image create photo imgPng -file $pngfile
            $win.img configure -image imgPng
        } else {
            
            ::cairo::cairo_$cmd $cr {*}$args
            lappend history [list $cmd $args]
        }
    }
    method save {filename} {
        set ext [string range [file extension $filename] 1 end]
        set isurface [::cairo::cairo_${ext}_surface_create $filename $options(-width) $options(-height)]
        set icr [::cairo::cairo_create $isurface]
        foreach h $history {
            foreach {cmd args} $h break
            ::cairo::cairo_$cmd $icr {*}$args
        }
        ::cairo::cairo_show_page $icr
        ::cairo::cairo_surface_flush $isurface
        ::cairo::cairo_surface_destroy $isurface
        ::cairo::cairo_destroy $icr
    }
}

The *save* function allows to save the image which is displayed in the ttk::label as well as pdf, postscript (ps) or svg file. Below is an example:

pack [cimage .img]
.img cairo rectangle 20 20 20 20
.img cairo set_source_rgb 1 0 0
.img cairo fill
.img cairo rectangle 50 20 20 20
.img cairo fill
.img cairo move_to 20 60
.img cairo set_source_rgb 0 0 0
.img cairo show_text "Hello World!"
.img save test.svg
.img save test.pdf

tclcairo-image

Todo

  • extend lists for automatic updates
  • use xrender extension to direct display as Tk widget(?)
  • snit::type in addition to snit::widget to work as well without Tk
  • check for device specific commands such as outlines for pdf to only execute those commands in the save method

See also

Discussion

Please discuss here ...