我们都知道在canvas 可以通过clip来实现剪裁功能,其步骤一般是先设置要裁剪的区域(路径),然后通过ctx.clip()的实现裁剪,裁剪之后,后续的绘制只能在裁剪的区域显示效果,比如如下一段代码,实现了一个圆形裁剪:

ctx.beginPath();
ctx.arc(100,100,50,0,Math.PI*2);
ctx.clip(); ctx.rect(0,0,200,200);
ctx.fillStyle='red';
ctx.fill();

最终效果如下:

 
裁剪

有的时候,我们希望能够实现反向裁剪,比如上面例子中,我们希望是圆圈外面是裁剪区域,而不是圆圈内部是裁剪区域。这就是标题所说的反向裁剪。效果如下图所示:

 
反向裁剪

如何实现反向裁剪呢?
笔者通过实践,发现有以下几种思路。

使用合成模式globalCompositeOperation

通过设置globalCompositeOperation的值,可以实现类似的反向裁剪的效果。大致思路是:

  • 首先绘制一个图形(比如圆形),该图形外部的区域将会是裁剪区域
  • 设置globalCompositeOperation的值为source-out
  • 然后绘制想要绘制的图形(比如矩形)

示例代码如下:

 ctx.beginPath();

ctx.arc(100, 100, 50, 0, Math.PI * 2);
ctx.fillStyle = 'red';
ctx.fill(); ctx.beginPath();
ctx.globalCompositeOperation = 'source-out';
ctx.rect(0, 0, 200, 200);
ctx.fillStyle = 'red';
ctx.fill();

最终效果参考上面的图形“反向裁剪”。

使用clip + clearRect方法

另外一种思路是使用clip + clearRect方法,大概的思路如下:

  • 首先绘制要绘制的图形(比如矩形)
  • 然后设置要反向裁剪的图形的路径(比如圆形)
  • 然后调用clip ,再调用clearRect方法清除圆形区域的像素。

示例代码如下:

   ctx.beginPath();
ctx.rect(0, 0, 200, 200);
ctx.fillStyle = 'red';
ctx.fill(); ctx.beginPath();
ctx.arc(100, 100, 50, 0, Math.PI * 2);
ctx.clip();
ctx.clearRect(0, 0, 200, 200);

最终效果参考上面的图形“反向裁剪”。

利用非零环绕原则

我们知道非零环绕原则,可以通过调整路径的方向(顺时针和逆时针),来实现挖空的效果,大致思路如下:

  • 首先构建一个大的区域路径(顺时针方向),比如矩形
  • 然后构建一个小的区域路径(逆时针方向),比如圆形
  • 调用clip裁剪,然后绘制图形

示例代码如下:

ctx.beginPath();
ctx.rect(0, 0, 200, 200); //顺时针方向
ctx.arc(100, 100, 50, 0, Math.PI * 2, true); // 逆时针方向
ctx.clip(); ctx.beginPath();
ctx.rect(0, 0, 200, 200);
ctx.fillStyle = 'red';
ctx.fill();

arc方法的最后一个参数可以控制顺时针(false)和逆时针(true),而rect方法没有,可以通过moveTo,lineTo,自己构建逆时针的rect方法,如下代码所示:

function counterclockwiseRect(ctx, x, y, w, h) {
ctx.moveTo(x, y);
ctx.lineTo(x, y + h);
ctx.lineTo(x + w, y + h);
ctx.lineTo(x + w, y);
ctx.lineTo(x, y);
}

最终效果参考上面的图形“反向裁剪”。

参考文档

https://stackoverflow.com/questions/22168619/reverse-clipping-in-canvas
https://stackoverflow.com/questions/18988118/how-can-i-clip-inside-a-shape-in-html5-canvas
http://caibaojian.com/canvas/21.html(非零环绕原则 )

欢迎关注公众号“ITman彪叔”。彪叔,拥有10多年开发经验,现任公司系统架构师、技术总监、技术培训师、职业规划师。熟悉Java、JavaScript、Python语言,熟悉数据库。熟悉java、nodejs应用系统架构,大数据高并发、高可用、分布式架构。在计算机图形学、WebGL、前端可视化方面有深入研究。对程序员思维能力训练和培训、程序员职业规划有浓厚兴趣。

 
ITman彪叔公众号

canvas反向裁剪技巧的更多相关文章

  1. HTML canvas图像裁剪

    canvas drawImage方法的图像裁剪理解可能会比较耗时,记录一下,以便供人翻阅! context.drawImage(img,sx,sy,swidth,sheight,x,y,width,h ...

  2. 【开源】canvas图像裁剪、压缩、旋转

    前言 前段时间遇到了一个移动端对图像进行裁剪.压缩.旋转的需求. 考虑到已有各轮子的契合度都不高,于是自己重新造了一个轮子. 关于图像裁剪.压缩 在HTML5时代,canvas的功能已经非常强大了,可 ...

  3. canvas图像裁剪、压缩、旋转

    转载于:http://www.cnblogs.com/dailc/p/7843204.html 前言 前段时间遇到了一个移动端对图像进行裁剪.压缩.旋转的需求.考虑到已有各轮子的契合度都不高,于是自己 ...

  4. canvas 绘制双线技巧

    楔子 最近一个项目,需要绘制双线的效果,双线效果表示的是轨道(类似铁轨之类的),如下图所示: 负责这块功能开发的小伙,姑且称之为L吧,最开始是通过数学计算的方式来实现这种双线,也就是在原来的路径的基础 ...

  5. (H5)canvas实现裁剪图片和马赛克功能,以及又拍云上传图片

    1.核心功能 此组件功能包含: 图片裁剪(裁剪框拖动,裁剪框改变大小): 图片马赛克(绘制马赛克,清除马赛克): 图片预览.图片还原(返回原图.返回处理图): 图片上传(获取签名.上传图片). 2.核 ...

  6. 提高HTML5 Canvas性能的技巧

    详细内容请点击 一:使用缓存技术实现预绘制,减少重复绘制Canvs内容 很多时候我们在Canvas上绘制与更新,总是会保留一些不变的内容,对于这些内容 应该预先绘制缓存,而不是每次刷新. 直接绘制代码 ...

  7. Android 2D Graphics学习 Region和Canvas裁剪

    1.首先介绍Region类 Region,中文意思即区域的意思,它表示的是canvas图层上的某一块封闭的区域. /**构造方法*/ public Region()  //创建一个空的区域 publi ...

  8. 从web图片裁剪出发:了解H5中的canvas

    本篇内容不针对canvas文档对每个api进行逐个的详解! 本篇内容不针对canvas文档对每个api进行逐个的详解! 本篇内容不针对canvas文档对每个api进行逐个的详解! 重说三,好了,现在进 ...

  9. 【Web】前端裁剪图片,并上传到服务器(Jcrop+canvas)

    web网站中常常有的功能:上传头像.上传封面等:一般图片都有一定的比例限制,所以需要前端在上传图片时,进行裁剪,并把裁剪后的图片进行上传. 本例采用Jcrop插件实现裁剪效果,canvas裁剪图片,并 ...

随机推荐

  1. ubuntu修改用户环境变量解决音乐播放器Rhythmbox乱码问题

    先打开主文件夹 cd /home/user #user是你的用户名 然后编辑用户环境 sudo gedit .profile在打开的文件中添加: export GST_ID3_TAG_ENCODING ...

  2. php5.5.* mysqlnd驱动安装

    1.什么是mysqlnd驱动? PHP手册上的描述: MySQL Native Driver is a replacement for the MySQL Client Library (libmys ...

  3. BZOJ1434:[ZJOI2009]染色游戏(博弈论)

    Description 一共n×m个硬币,摆成n×m的长方形.dongdong和xixi玩一个游戏,每次可以选择一个连通块,并把其中的硬币全部翻转,但是需要满足存在一个硬币属于这个连通块并且所有其他硬 ...

  4. 【node.js】GET/POST请求、Web 模块

    获取GET请求内容 node.js 中 url 模块中的 parse 函数提供了这个功能. var http = require('http'); var url = require('url'); ...

  5. 【node.js】全局变量、常用工具、文件系统

    学习链接:http://www.runoob.com/nodejs/nodejs-global-object.html 在 JavaScript 中,通常 window 是全局对象, 而 Node.j ...

  6. [IDE123] Intellij Idea 快捷键

    Ctrl+Shift+N,可以快速打开文件 Ctrl+Shift + Enter,语句完成“!”,否定完成,输入表达式时按 “!”键Ctrl+E,最近的文件Ctrl+Shift+E,最近更改的文件Sh ...

  7. BI之报表测试总结

    报表测试总结: 1.测试准备工作: 数据准备 保证足够多的有效数据 清楚报表中涉及到的算法.公式 清楚业务功能接口 2.报表测试点 基本测试点:界面.控件.格式.布局.明显的数据错误.js报错.报表标 ...

  8. VMware Tools安装方法及解决无法全屏显示问题

    环境:VMware8.0虚拟机        ubuntu:12.04 在刚安装完ubuntu后,屏幕不能全屏显示,此时: 1.安装VMware Tools 步骤: 1.1     进入ubuntu系 ...

  9. Java序列化反序列化对象流ObjectInputStream、ObjectOutputStream

    使用Person类作为Object进行示范 注意:Object要能被写入流需要实现Serializable接口 存储的文件后缀名为.ser 示范Person类 import java.io.Seria ...

  10. OpenGL 混合功能

    一.概念:简言之,即在颜色缓存区和深度缓存区中,新旧颜色的覆盖和替换问题:已经存在于缓存区的为目标颜色,即将进入缓存区的为源颜色: 二.应用场景:在不透明的图形前绘制一个透明的图形: 三.主要代码实现 ...