使用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
相关产品推荐
相关产品推荐

