H5 Canvas 中 globalCompositeOperation 的理解和应用

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;

}

参考

相关推荐
仿生狮子3 小时前
OpenAI 攻下千禧年难题之后,开发者似乎无动于衷
前端·数学·vibecoding
夏幻灵7 小时前
JavaScript this 面试:五种绑定规则、优先级与常见面试陷阱
开发语言·javascript·面试
Lvan的前端笔记7 小时前
docker:每个前端项目一个 Nginx 容器还是只有一个Nginx容器
前端·nginx·docker
三天不学习7 小时前
Egg.js 4 突然爆火,原因是否归结于AI 原生落地需求爆发?
前端·javascript·全栈·egg.js
xcs194058 小时前
前端 vue 的前端页面debugger 进不去
前端·javascript·vue.js
明月_清风9 小时前
Deno 终局来了:从挑战 Node 到被 Cloudflare 收编
前端·后端·node.js
Csvn10 小时前
框架性能优化
前端
回眸&啤酒鸭11 小时前
【回眸】OpenSwarm 多智能体协作系统实战指南
大数据·前端·人工智能
用户693717500138411 小时前
2026,程序员的时代拐点到了
android·前端·后端
大龄秃头程序员12 小时前
一次 iBeacon + BLE 无感解锁方案的实现记录
前端