I am using pyCairo for drawing moving elements on a surface. In order to get better perfomance i tried to use "clip" function to redraw only the changed parts of a bigger image . Unfortunately it creates unwanted edges on the image. The edges of the cliping can be seen. Is it possible to avoid this kind of behaviour?
import math
import cairo
def draw_stuff(ctx):
""" clears background with solid black and then draws a circle"""
ctx.set_source_rgb (0, 0, 0) # Solid color
ctx.paint()
ctx.arc (0.5, 0.5, 0.5, 0, 2*math.pi)
ctx.set_source_rgb (0, 123, 0)
ctx.fill()
WIDTH, HEIGHT = 256, 256
surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, WIDTH, HEIGHT)
ctx = cairo.Context (surface)
ctx.scale (WIDTH, HEIGHT) # Normalizing the canvas
draw_stuff(ctx)
#Let's draw stuff again, this time only redrawing a small part of the image
ctx.save()
ctx.rectangle(0.2,0.2,0.2,0.2)
ctx.clip()
draw_stuff(ctx)
ctx.restore()
surface.write_to_png ("example.png") # Output to PNG
You should round your cliping coordinates to integers (in device space). See http://cairographics.org/FAQ/#clipping_performance
I don't know the Python API and I am just guessing how it might work like from the C API, but it is something like this:
def snap_to_pixels(ctx, x, y):
x, y = ctx.user_to_device(x, y)
# No idea how to round an integer in python,
# this would be round() in C
# (Oh and perhaps you don't want this rounding, but
# instead want to round the top-left corner of your
# rectangle towards negative infinity and the bottom-right
# corner towards positive infinity. That way the rectangle
# would never become smaller to the rounding. But hopefully
# this example is enough to get the idea.
x = int(x + 0.5)
y = int(x + 0.5)
return ctx.device_to_user(x, y)
# Calculate the top-left and bottom-right corners of our rectangle
x1, y1 = 0.2, 0.2
x2, y2 = x1 + 0.2, y1 + 0.2
x1, y1 = snap_to_pixels(ctx, x1, y1)
x2, y2 = snap_to_pixels(ctx, x2, y2)
# Clip for this rectangle
ctx.rectangle(x1, y1, x2 - x1, y2 - y1)
ctx.clip()