跳到主要内容

clip遮罩与合成层

clip()当前 path(或 Path2D) 交进裁剪区,之后所有绘制(含 drawImage)都被卡住。裁剪区只能变小,扩大必须 restore。这和 globalCompositeOperation 不是一回事:clip 改后续绘制的可写区域,GCO 改与 已有像素 的混合公式。

1. clip 的正确用法

export function withClip(
ctx: CanvasRenderingContext2D,
path: Path2D,
fillRule: CanvasFillRule,
paint: () => void,
): void {
ctx.save();
ctx.clip(path, fillRule);
paint();
ctx.restore();
}

头像圆裁、地图圆角窗口、刮刮卡未刮开区域,用 clip。
evenodd 做环状窗口。忘记 closePath 的当前路径去 clip,缺口行为按规范「连到起点」,不要靠它。

clip 与 CTM:path 仍乘当前矩阵。先 setTransform(world) 再 clip 局部 path。

2. 不要用 clip 模拟图层

一棵场景树每个节点 clip 一次,状态栈深度和光栅成本一起涨。矩形窗口优先 clear + 不画窗外;复杂遮罩烘焙成一张 alpha ImageBitmap,用 destination-in 一次

export function applyAlphaMask(
ctx: CanvasRenderingContext2D,
mask: CanvasImageSource,
): void {
ctx.save();
ctx.globalCompositeOperation = "destination-in";
ctx.drawImage(mask, 0, 0);
ctx.restore();
}

这要求内容已经在当前表面上。通常在离屏完成:先画内容,再 destination-in mask,再 blit 回视图。

source-in / destination-out 做橡皮、开洞。每次 GCO 都只影响 下一笔。连画三笔中间忘了设回 source-over,洞会越挖越怪。

3. 遮罩从哪来

  • 矢量:Path2D fill 到离屏 alpha
  • 位图:灰度图当 alpha(自己 getImageData 填 A,或 drawImage + destination-in
  • 文字挖空:fillText 到 mask 表面

软边遮罩(羽毛)= 对 mask 做 blur 再 destination-in,成本在 blur,不在 clip。

可编辑、可导出的矢量挖洞,不要停在这一层,见 路径布尔运算

4. 失败形态

症状原因
后面所有东西消失clip 未 restore
圆角外仍画出clip 用了错误 CTM / 错 fillRule
开洞失败GCO 只作用在下一笔,clearRect 在 source-over
越 clip 越慢每节点 clip 深栈

权威资料

核对日期:2026-08-26