114 lines
3.1 KiB
Org Mode
114 lines
3.1 KiB
Org Mode
|
#+title: Combining PyGame and PyCairo
|
||
|
#&summary
|
||
|
How to combine two Pythonic graphical frameworks
|
||
|
#&
|
||
|
#+license: wtf
|
||
|
|
||
|
* Combining PyGame and PyCairo
|
||
|
|
||
|
#&+classes=note
|
||
|
See [[http://pygame.org/wiki/CairoPygame]] for other examples.
|
||
|
#&
|
||
|
|
||
|
This piece of code allows you to convert a Cairo surface to a PyGame
|
||
|
surface. It also includes a small example on how to make SVG loading work. It
|
||
|
works with Python 2.5+ and requires relatively recent versions of pygame,
|
||
|
pycairo and NumPy to work. For the SVG example to work, you must also have rsvg
|
||
|
installed.
|
||
|
|
||
|
#+BEGIN_SRC python2
|
||
|
#!/usr/bin/env python
|
||
|
# Copyleft 2010 Niels Serup, WTFPL 2.0. Free software.
|
||
|
|
||
|
### Imports ###
|
||
|
import math
|
||
|
import pygame
|
||
|
import cairo
|
||
|
import numpy
|
||
|
import Image
|
||
|
|
||
|
### Constants ###
|
||
|
width, height = 640, 480
|
||
|
|
||
|
|
||
|
### Functions ###
|
||
|
def draw(ctx):
|
||
|
ctx.set_line_width(15)
|
||
|
ctx.arc(320, 240, 200, 0, 2 * math.pi)
|
||
|
|
||
|
# r g b a
|
||
|
ctx.set_source_rgba(0.6, 0, 0.4, 1)
|
||
|
ctx.fill_preserve()
|
||
|
|
||
|
# r g b a
|
||
|
ctx.set_source_rgba(0, 0.84, 0.2, 0.5)
|
||
|
ctx.stroke()
|
||
|
|
||
|
def bgra_surf_to_rgba_string(cairo_surface):
|
||
|
# We use PIL to do this
|
||
|
img = Image.frombuffer(
|
||
|
'RGBA', (cairo_surface.get_width(),
|
||
|
cairo_surface.get_height()),
|
||
|
cairo_surface.get_data(), 'raw', 'BGRA', 0, 1)
|
||
|
|
||
|
return img.tostring('raw', 'RGBA', 0, 1)
|
||
|
|
||
|
|
||
|
### Body ###
|
||
|
# Init PyGame
|
||
|
pygame.display.init()
|
||
|
screen = pygame.display.set_mode((width, height), 0, 32)
|
||
|
|
||
|
# Create raw surface data (could also be done with something else than
|
||
|
# NumPy)
|
||
|
data = numpy.empty(width * height * 4, dtype=numpy.int8)
|
||
|
|
||
|
# Create Cairo surface
|
||
|
cairo_surface = cairo.ImageSurface.create_for_data(
|
||
|
data, cairo.FORMAT_ARGB32, width, height, width * 4)
|
||
|
|
||
|
# Draw with Cairo on the surface
|
||
|
ctx = cairo.Context(cairo_surface)
|
||
|
draw(ctx)
|
||
|
|
||
|
|
||
|
##### SVG LOADING EXAMPLE #####
|
||
|
# Using rsvg it is possible to render an SVG file onto a Cairo
|
||
|
# surface. Uncomment the following lines to make it work.
|
||
|
#import rsvg # This will probably not work in Windows. As far as I
|
||
|
# know, only GNU/Linux distibutions package this Python
|
||
|
# module. Nevertheless, it should be easy to create a small wrapper;
|
||
|
# see http://www.cairographics.org/cairo_rsvg_and_python_in_windows/
|
||
|
|
||
|
# Load the file
|
||
|
#svg_graphics = rsvg.Handle('path/to/file.svg')
|
||
|
|
||
|
# Render the graphics onto your Cairo context
|
||
|
#svg_graphics.render_cairo(ctx)
|
||
|
|
||
|
# To get the SVG file's dimensions before you create a Cairo surface,
|
||
|
# use the following function:
|
||
|
#print svg_graphics.get_dimension_data()
|
||
|
###############################
|
||
|
|
||
|
# On little-endian machines (and perhaps big-endian, who knows?),
|
||
|
# Cairo's ARGB format becomes a BGRA format. PyGame does not accept
|
||
|
# BGRA, but it does accept RGBA, which is why we have to convert the
|
||
|
# surface data. You can check what endian-type you have by printing
|
||
|
# out sys.byteorder
|
||
|
data_string = bgra_surf_to_rgba_string(cairo_surface)
|
||
|
|
||
|
# Create PyGame surface
|
||
|
pygame_surface = pygame.image.frombuffer(
|
||
|
data_string, (width, height), 'RGBA')
|
||
|
|
||
|
# Show PyGame surface
|
||
|
screen.blit(pygame_surface, (0,0))
|
||
|
pygame.display.flip()
|
||
|
|
||
|
clock = pygame.time.Clock()
|
||
|
while not pygame.QUIT in [e.type for e in pygame.event.get()]:
|
||
|
clock.tick(30)
|
||
|
#+END_SRC
|
||
|
|