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

使用Cairo的CAIRO_OPERATOR_CLEAR裁剪图形出现黑块的问题求助

Cairo绘制半透明层挖洞显示原始图像问题解决

问题原因

出现黑块是因为你使用的Xlib surface不支持透明通道,CAIRO_OPERATOR_CLEAR会将目标区域的像素置为完全透明,但X服务器无法处理透明像素时,会用黑色填充该区域,而非显示底层的原始图像。你误以为CLEAR会“删除”下方图形,但实际上Cairo的操作符是作用于当前绘制目标的——你的Xlib surface本身是不透明的,CLEAR只是修改这块像素的透明度,无法让底层内容透出来。

解决方案

方法一:剪切路径实现“挖洞”

先绘制原始图像,创建一个全屏路径并减去要保留的矩形区域,将其设为剪切区域,最后绘制半透明黑色层,这样半透明层只会出现在剪切区域内(即除挖洞外的区域)。

修改后的代码:

if (xevent.type == MotionNotify && isPressed == true)
{
  int tmp_x = xevent.xmotion.x_root;
  int tmp_y = xevent.xmotion.y_root;

  cairo_save(cr);

  // 绘制原始图像,修正之前的1,1偏移问题
  cairo_set_source_surface(cr, surfaceTmp, 0, 0);
  cairo_paint(cr);

  // 创建剪切路径:全屏区域减去目标矩形
  cairo_rectangle(cr, 0, 0, DisplayWidth(xdisplay, scr), DisplayHeight(xdisplay, scr));
  cairo_rectangle(cr, init_x, init_y, tmp_x - init_x, tmp_y - init_y);
  cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); // 奇偶填充规则实现区域相减
  cairo_clip(cr);

  // 绘制半透明黑色层,仅在剪切区域内显示
  cairo_set_source_rgba(cr, 0, 0, 0, 0.2);
  cairo_paint(cr);

  cairo_restore(cr);
}

方法二:SOURCE操作符替换区域

先绘制原始图像和半透明层,再将原始图像作为源,在目标区域用CAIRO_OPERATOR_SOURCE覆盖,直接替换该区域的像素为原始图像内容。

修改后的代码:

if (xevent.type == MotionNotify && isPressed == true)
{
  int tmp_x = xevent.xmotion.x_root;
  int tmp_y = xevent.xmotion.y_root;

  cairo_save(cr);

  // 绘制原始图像
  cairo_set_source_surface(cr, surfaceTmp, 0, 0);
  cairo_paint(cr);

  // 绘制全屏半透明黑色
  cairo_set_source_rgba(cr, 0, 0, 0, 0.2);
  cairo_paint(cr);

  // 用原始图像覆盖目标区域
  cairo_set_source_surface(cr, surfaceTmp, 0, 0);
  cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
  cairo_rectangle(cr, init_x, init_y, tmp_x - init_x, tmp_y - init_y);
  cairo_fill(cr);

  cairo_restore(cr);
}

额外优化建议

你之前将surface保存为PNG再读取的操作可以简化,直接使用cairo_surface_copy或者在绘制时复用原始surface即可,无需磁盘IO,提升效率。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 12:57:16