An update on my latest cairo adventures...
When cairo 1.10 comes out we'll get a RecordingSurface so you can record commands and play them back to another surface, but how to do something similar now ?
Skip to the end if you just want the code, explanation of how I got there ahead:
My first advice was to try using PDFSurface, and set the file object to None.
```
Record a red rectangle onto a surface.
Create another surface and draw a background on it
Draw the first surface onto this surface
from cairo import PDFSurface, ImageSurface, FORMAT_ARGB32, Context
recording = PDFSurface(None, 200, 200) target = ImageSurface(FORMAT_ARGB32, 200, 200)
Record a red rectangle
cr = Context(recording) cr.set_source_rgb(1.0, 0.0, 1.0) cr.rectangle(20, 20, 10, 10)
cr.fill_preserve() cr.set_source_rgb(0.0, 0.0, 1.0) cr.stroke()
target_context = Context(target)
Draw background
target_context.set_source_rgb(1.0, 1.0, 0) target_context.paint()
Replay recording to target
target_context.set_source_surface(recording) target_context.paint()
target.write_to_png('output.png') ```
That seems to work, except when I tried in Windows, when it complained that the file object was wrong.
OK, we can work round that:
{: .brush:python}
def RecordingSurface(w, h):
if os.name == 'nt':
fobj = 'nul'
else:
fobj = None
return PDFSurface(fobj, w, h)
This seems to be working, but my animation seemed slow... time for some
benchmarking; I rendered 1000 frames and got a rough wall clock time:
1m48.
Hmm... perhaps SVGSurface will be quicker:
1m28
This is much better, 20 seconds difference just by changing what kind of surface is returned!
Animation not smooth though
The animation still seemed jerky it occured to me that when the surfaces are disposed they will attempt to out their content to the file object !
Luckily, get_similar_surface() comes to the rescue; it returns a surface not associated with a file object. Using this the original surface can be kept around forever, and never output.
Wallclock time:
50 seconds!
And here it is:
``` {: .brush:python} _svg_surface = None def RecordingSurface(*size): ''' We don't have RecordingSurfaces until cairo 1.10, so this kludge is used
SVGSurfaces are created, but to stop them ever attempting to output, they
are kept in a dict.
When a surface is needed, create_similar is called to get a Surface from
the SVGSurface of the same size
'''
global _svg_surface
if os.name == 'nt':
fobj = 'nul'
else:
fobj = None
if _svg_surface is None:
_svg_surface = SVGSurface(fobj, 0, 0)
return _svg_surface.create_similar(cairo.CONTENT_COLOR_ALPHA, *size)
```
This is really useful, you can record commands and play them back to other surfaces.