You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cairo图形库如何在两个Xlib surface间拷贝传输区域数据

Cairo实现X11窗口区域拷贝的方案

首选方案:纯Cairo直接拷贝(无中转,性能最优)

不需要借助image surface做中转,Cairo原生支持直接在两个Xlib surface之间做区域拷贝,会优先走X11的硬件加速拷贝路径,没有CPU侧像素搬运的开销:

  1. 基于目标Xlib surface创建Cairo绘图上下文
  2. 设置源surface为待拷贝的源Xlib surface,通过坐标偏移对齐源和目标的拷贝位置
  3. 限定绘制区域为需要拷贝的矩形,执行填充完成拷贝
  4. 提交绘制指令确保内容显示
    参考代码:
// 为目标surface创建绘图上下文
cairo_t *cr = cairo_create(target_xlib_surface);

// 配置源和坐标偏移:让源的(xs, ys)点对齐目标的(xd, yd)点
cairo_set_source_surface(cr, source_xlib_surface, xd - xs, yd - ys);
// 仅绘制目标位置、指定尺寸的矩形,避免多余拷贝
cairo_rectangle(cr, xd, yd, ws, hs);
cairo_fill(cr);

// 提交绘制指令到X服务,确保内容可见
cairo_surface_flush(target_xlib_surface);
// 释放上下文
cairo_destroy(cr);

方案二:手动创建image surface中转

如果需要在拷贝过程中对像素做CPU侧处理(比如读取像素值、添加特效),可以通过image surface做中转,流程分为两步:

  1. 将源surface的指定区域绘制到临时image surface
  2. 将image surface的内容绘制到目标surface的指定位置
    参考代码:
// 创建和待拷贝区域同尺寸的临时image surface
cairo_surface_t *tmp_img = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, ws, hs);
cairo_t *cr = cairo_create(tmp_img);
// 偏移坐标,让源的(xs, ys)对齐临时surface的(0,0)原点
cairo_set_source_surface(cr, source_xlib_surface, -xs, -ys);
cairo_paint(cr);
cairo_destroy(cr);
cairo_surface_flush(tmp_img);

// 此处可以对tmp_img的像素数据做自定义CPU处理
// unsigned char *pixel_data = cairo_image_surface_get_data(tmp_img);

// 将临时surface绘制到目标位置
cr = cairo_create(target_xlib_surface);
cairo_set_source_surface(cr, tmp_img, xd, yd);
cairo_paint(cr);
cairo_destroy(cr);
cairo_surface_flush(target_xlib_surface);

// 释放临时资源
cairo_surface_destroy(tmp_img);

该方案会触发X服务端到CPU内存、CPU内存到X服务端两次像素拷贝,性能远低于直接拷贝方案,无特殊像素处理需求不建议使用。

方案三:通过cairo_surface_map_to_image()映射拷贝

该接口可以直接将Xlib surface的指定区域映射为可读写的image surface,不需要手动创建临时surface,本质还是CPU侧拷贝,性能和方案二接近,适合需要临时读写surface像素的场景:
参考代码:

// 定义源、目标的待操作区域
cairo_rectangle_int_t src_region = {.x = xs, .y = ys, .width = ws, .height = hs};
cairo_rectangle_int_t dst_region = {.x = xd, .y = yd, .width = ws, .height = hs};

// 映射两个区域为image surface
cairo_surface_t *mapped_src = cairo_surface_map_to_image(source_xlib_surface, &src_region);
cairo_surface_t *mapped_dst = cairo_surface_map_to_image(target_xlib_surface, &dst_region);

// 在两个映射出的image surface之间完成拷贝
cairo_t *cr = cairo_create(mapped_dst);
cairo_set_source_surface(cr, mapped_src, 0, 0);
cairo_paint(cr);
cairo_destroy(cr);

// 必须执行unmap,修改才会同步回原Xlib surface
cairo_surface_unmap_image(target_xlib_surface, mapped_dst);
cairo_surface_unmap_image(source_xlib_surface, mapped_src);
cairo_surface_flush(target_xlib_surface);

关于X11原生接口的选择

如果你的业务逻辑完全不涉及Cairo绘制,只需要做窗口内容拷贝,直接调用X11原生的XCopyArea()性能最高。但如果你已经基于Cairo实现了其他绘制逻辑,优先选第一种纯Cairo直接拷贝方案即可,混用X11原生接口可能导致Cairo和X服务的状态不同步,出现显示异常。

注意:X11默认不保存窗口被遮挡区域的像素内容,如果源窗口被其他窗口遮挡、或者超出屏幕边界,拷贝得到的内容会是未定义的无效数据,这是X11的窗口机制决定的,和Cairo无关。

内容的提问来源于stack exchange,提问作者Ralf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 15:18:15