如何将两个 ImageSurface 对象合并为一个

How to combine two ImageSurface objects into one

基于this answer,我在运行时生成了两个cairo.ImageSurface对象。两者都是相同维度的 RGBA。我想在将它们保存到磁盘之前组合/堆叠它们:

new_surface = surface1 + surface2 # pseudo-code

(如何)这是有效的?

Cairo 允许您将 ImageSurface 转换为 Numpy 数组:

import numpy
import cairo

width, height = 255, 255
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
buf = surface.get_data()
data = numpy.ndarray(shape=(width, height),
                     dtype=numpy.uint32,
                     buffer=buf)

转换两个 ImageSurface 后,您可以使用“+”或 numpy.add() 对它们求和(根据您的情况选择求和函数)

(How) does this work?

您创建一个更大尺寸的新 cairo 图像表面并将您的原始图像绘制到该表面。

未经测试的伪代码(使用 C API 而不是 pycairo):

cairo_surface_t *merged = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height * 2);
cairo_t *cr = cairo_create(merged);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);

cairo_set_source_surface(cr, surface1, 0, 0);
cairo_paint(cr);

cairo_set_source_surface(cr, surface2, 0, height);
cairo_rectangle(cr, 0, height, width, height);
cairo_fill(cr);

cairo_destroy(cr);

通过 PIL(pillow)实际上给出了相当不错且相对高效的结果。以下对我有用:

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)