quickest way to get started with cairo
Asked Answered
A

2

6

I have taken passing shots at learning Cairo in the past, but always moved on in favor of some other graphics library. My problem is that I can't find a good tutorial that gives me a simple display for my surface. I have always ended up digging through GTK or QT documentation about things that have nothing to do with what I want to do. I want to learn Cairo, not a massive OO architecture.

What is a bare bones wrapper to give me a cross-platform window with a Cairo canvas to draw on?

Antisthenes answered 7/4, 2011 at 4:25 Comment(0)
Q
11

I have used cairo for virtually anything involving drawing. I work at a medical software company, so I prototype scientific data visualization and other things.

I have usually three ways to display my drawings:

  1. A GTK drawing area created with a Python script and GTK;
  2. A PNG image displayed directly on screen using Python Image Library show() method;
  3. A PNG image saved to disk, also via Python Image Library.

A simple script derived from cairographics examples, which actually I use as a template for any new project, is:

import gtk

class Canvas(gtk.DrawingArea):
    def __init__(self):
        super(Canvas, self).__init__()
        self.connect("expose_event", self.expose)
        self.set_size_request(800,500)

    def expose(self, widget, event):
        cr = widget.window.cairo_create()
        rect = self.get_allocation()

        # you can use w and h to calculate relative positions which
        # also change dynamically if window gets resized
        w = rect.width
        h = rect.height

        # here is the part where you actually draw
        cr.move_to(0,0)
        cr.line_to(w/2, h/2)
        cr.stroke()

window = gtk.Window()
canvas = Canvas()
window.add(canvas)
window.set_position(gtk.WIN_POS_CENTER)
window.show_all()
gtk.main()

Or if you prefer not to deal with GUI toolkits, you can create and display an image on screen, and optionally save it to file:

import cairo, Image

width = 800
height = 600

surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
cr = cairo.Context(surface)

# optional conversion from screen to cartesian coordinates:
cr.translate(0, height)
cr.scale(1, -1)

# something very similar to Japanese flag:
cr.set_source_rgb(1,1,1)
cr.rectangle(0, 0, width, height)
cr.fill()
cr.arc(width/2, height/2, 150, 0, 6.28)
cr.set_source_rgb(1,0,0)
cr.fill()

im = Image.frombuffer("RGBA",
                       (width, height),
                       surface.get_data(),
                       "raw",
                       "BGRA",
                       0,1) # don't ask me what these are!
im.show()
# im.save('filename', 'png')
Quotient answered 15/7, 2011 at 3:0 Comment(4)
Thanks for this. I just jumped through a ton of hoops to get this working (including the fully broken install process for PIL on OS X). I'm afraid this is fully unsuitable for novices users. (Also shouldn't it be: from PIL import Image ?)Sexagenary
That sort of thing made me change to browser-based solutions (HTML Canvas or javascript-based SVG), and also Processing for quick'n'dirty drawings. But the fact is: Cairo is still much more powerful than any other solution so far :D .Quotient
Also: python is a far more decent way to do this stuff than bloody javascript.Sexagenary
That's debatable. Once you are "into" a drawing context, the operations are quite similar: move to that point, draw this, change line thickness, etc. It's just a matter of syntax. Except of course for the ultra-verbose DOM manipulation needed to create SVG programmatically (although it might worth it, because browsers are getting better and better at rendering SVG).Quotient
A
1

An answer to a related question demonstrates a very simple setup in Gtk2HS to draw on a drawingArea with Cairo.

import Graphics.UI.Gtk
import Graphics.Rendering.Cairo

main :: IO ()
main = do
    initGUI
    window      <- windowNew
    drawingArea <- drawingAreaNew
    containerAdd window drawingArea

    drawingArea `onExpose` (\_ -> renderScene drawingArea)
    window `onDestroy` mainQuit

    windowSetDefaultSize window 640 480
    widgetShowAll window
    mainGUI

renderScene :: DrawingArea -> IO Bool
renderScene da = do
    dw <- widgetGetDrawWindow da
    renderWithDrawable dw $ do setSourceRGBA 0.5 0.5 0.5 1.0
                               moveTo 100.0 100.0
                               showText "HelloWorld"

    return True

Simply pass your Cairo animation routine to renderWithDrawable dw in renderScene.

Antisthenes answered 8/4, 2011 at 3:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.