Search code examples
pythoncairopycairo

How to combine two ImageSurface objects into one


Based on this answer, I have two cairo.ImageSurface objects generated at runtime. Both are RGBA of equal dimensions. I'd like to combine / stack them before saving them to disk:

new_surface = surface1 + surface2 # pseudo-code

(How) does this work?


Solution

  • Going through PIL (pillow) actually gives pretty decent and relatively performant results. The following works for me:

    import cairo
    from PIL import Image
    
    def surface_to_pil(surface):
        return Image.frombuffer(
            mode = 'RGBA',
            size = (surface.get_width(), surface.get_height()),
            data = surface.get_data(),
        )
    
    def pil_to_surface(image):
        return cairo.ImageSurface.create_for_data(
            bytearray(image.tobytes('raw', 'BGRa')),
            cairo.FORMAT_ARGB32,
            image.width,
            image.height,
            )
    
    def add_surfaces(a, b):
        assert a.get_width() == b.get_width() and a.get_height() == b.get_height()
        result_pil = Image.new(
            mode = 'RGBA',
            size = (a.get_width(), a.get_height()),
            color = (0.0, 0.0, 0.0, 0.0),
            )
        for surface in (a, b):
            surface_pil = surface_to_pil(surface)
            result_pil.paste(im = surface_pil, mask = surface_pil)
        return pil_to_surface(result_pil)
    
    new_surface = add_surfaces(surface1, surface2)