H5 Canvas
是 HTML5
中的一个元素,它拥有丰富的 API
,允许开发人员通过 JS
在网页上绘制图形、动画和复杂的视觉效果-比如笔者之前的文章引力粒子特效 - 归为尘埃。
本文,我们来讲讲 globalCompositeOperation
这个重要的属性。
globalCompositeOperaton 是什么
globalCompositeOperation
顾名思义,为合成操作,用于设置新绘制的图形如何和已有图形进行合成。 这个属性接受一个字符串值,该值决定了合成的方式。
context.globalCompositeOperation = "source-over"
是其默认值,表示新图形会覆盖在已有图形之上。
合成操作方式
合成的方式有以下,我们结合案例,逐一来体验。
假设我们有素材如下:

该素材的尺寸为 548px * 452px ,包含透明的地方和红色不透明的地方。该图片作为已有图片。

笔者头像作为新图,尺寸为 90px * 90px。
html
<canvas id="canvas" width="548" height="452"></canvas>
javascript
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const imgOrigin = new Image();
imgOrigin.src = "path/to/orignal-image.png";
imgOrigin.onload = () => {
ctx.drawImage(imgOrigin, 0, 0, 548, 452);
// 设置 globalCompositeOperation 为 source-over
ctx.globalCompositeOperation = "source-over";
const imgTarget = new Image();
imgTarget.src = "path/to/target-image.png";
imgTarget.onload = () => {
ctx.drawImage(imgTarget, 0, 0);
}
}
source-over
:默认值,新图形绘制在已有图形上。
如上代码,得到的结果如图:

source-in
:新图形仅在与已有图形重叠的地方显示
我们更改下目标绘制的尺寸 ctx.drawImage(imgTarget, 0, 0, 300, 300);
注意:以下案例新图的绘制尺寸均为
300px * 300px

source-out
:新图形仅在不与已有图形重叠的地方显示。

source-atop
:新图形仅在与已有图形重叠的地方显示,且在已有图形之上。

destination-over
:新图形绘制在已有图形之下

destination-in
:已有图形仅在与新图形重叠的地方显示。

destination-out
:已有图形仅在不与新图形重叠的地方显示

destination-atop
:已有图形仅在与新图形重叠的地方显示,且在新图形之上

lighter
:新图形和已经有的图形颜色值相加

copy
:新图形完成替换已有图形

xor
:新图形和已有图形进行抑或操作
CSS
body {
// 方便比较,这里更改下背景颜色
background-color: blue;
}

案例
我们在合成图像的时候,针对不同形状的图层,比如开题给出的图👇

那么我们可以通过 source-atop
将需要的图绘制在红色的区间。
如果,我们需要将蒙层的边框和上面的蒙层进行叠加,获取到新的蒙层内容。我们可以使用 destination-out
:
typescript
// 创建图层背景图片-这里统一没有重叠的地方,以原图的为标准,保留其原图不重叠的部分
async function createModelLayerBgImage(params: Params, backgroundImage?: string): Promise<string> {
const croppedFrame = await createCroppedCanvas(params);
// 没有背景图则取相框
if (!backgroundImage) {
return croppedFrame || whiteBgBase64;
}
const modelLayerWidth: number = params.modelLayerInfo.size.width;
const modelLayerHeight: number = params.modelLayerInfo.size.height;
const generateCanvas: HTMLCanvasElement | null = document.createElement("canvas");
generateCanvas.width = modelLayerWidth;
generateCanvas.height = modelLayerHeight;
const generateCtx = generateCanvas.getContext("2d");
if (!generateCtx) {
console.error("Failed to get 2D context from generate canvas");
return backgroundImage;
}
const bgImage = await loadImage(backgroundImage);
generateCtx.drawImage(bgImage, 0, 0, modelLayerWidth, modelLayerHeight);
// 先变成白色背景
generateCtx.globalCompositeOperation = "source-in";
generateCtx.fillStyle = "#FFFFFF";
generateCtx.fillRect(0, 0, modelLayerWidth, modelLayerHeight);
generateCtx.globalCompositeOperation = "destination-out";
// 加载剪切的图层的边框背景图
const croppedFrameImage = await loadImage(croppedFrame);
generateCtx.drawImage(croppedFrameImage, 0, 0, modelLayerWidth, modelLayerHeight);
// 返回base64编码的图片 - 变成白色背景图
const base64Image = generateCanvas.toDataURL("image/png");
return base64Image;
}