详解FireFox下Canvas使用图像合成绘制SVG的Bug


Posted in HTML / CSS onJuly 10, 2019

本文适合适合对canvas绘制、图形学、前端可视化感兴趣的读者阅读。

楔子

所有的事情都会有一个起因。

最近产品上需要做一个这样的功能:给一些图形进行染色处理。想想这还不是顺手拈来的事情,早就研究过图形染色的技术。于是我把之前写好的两种算法发给了小伙伴,让他参照实现,第一种算法是操纵像素、第二种使用了图像合成:globalCompositeOperation。

所有的事情都可能会有意外,写程序更是如此了。

没多久,小伙伴说,第二种算法在firefox下不起作用。

探索原因

听说有bug,心中一惊。我测试过了的,FireFox下面也测试过的。于是我打开火狐浏览器,启动示例,发现是好的,没有问题。

但是小伙伴集成到产品中就有问题。 差别在哪儿呢? 通过一起排查,最终发现我的示例代码和产品中代码的一个区别是:示例代码用的是png图片,而产品中用的是svg图片。

难道是svg图片的问题,拿一个svg图片放到示例代码中,果然不对。结论已经明显:

FireFox浏览器下,用Canvas下绘制绘制SVG图的时候,globalCompositeOperation的设置将不生效。

下面是一段用于测试的代码,ctx.globalCompositeOperation = 'destination-out' 表示用源图像的形状去挖空目标图像。

在其他浏览器中,以下代码中是生效的,又挖空的效果。但是在

在FireFox 下不生效:

<html>
<head>
    <script>
        function init() {
            var canvas = document.getElementById('c');
            var ctx = canvas.getContext('2d');
            var img = new Image();
            img.onload = function () {
                ctx.drawImage(img, 0, 0, img.width * 2, img.height * 2);
                ctx.globalCompositeOperation = 'destination-out';
            }
            img.src = 'diffuse.png';
            var svg = new Image;
            svg.src = "./d.svg";
                    
            function drawPoint(pointX, pointY) {
                ctx.drawImage(svg, pointX - svg.width / 4, pointY - svg.height / 4, svg.width / 2, svg.height / 2);
            }
            canvas.addEventListener('click', function (e) {
                drawPoint(e.clientX, e.clientY);
            }, false);
        }
    </script>
</head>
<body onload="init();" style="background: red">
    <div>
        <canvas id="c" width="1000" height="1000"></canvas>
    </div>
</body>
</html>

如何解决

找到问题的原因了,解决方法其实简单。

事情往往就是这样,很多时候,找到问题所在往往比解决问题要难。

解决方案其实很简单

代码中加入判断,判断浏浏览器是否是FireFox。

如果是,则先把svg图片绘制到临时的canvas上面。

后续绘制用临时的canvas替代svg图片。

比如上面代码可以改进如下:

function init() {
            var canvas = document.getElementById('c');
            var ctx = canvas.getContext('2d');
            var img = new Image();
            img.onload = function () {
                ctx.drawImage(img, 0, 0, img.width * 2, img.height * 2);
                ctx.globalCompositeOperation = 'destination-out';
            }
            img.src = 'diffuse.png';
            var svg = new Image;
            svg.src = "./d.svg";
                      
        var tempCanvas = svg;  
                         if(isFirefox){
                             svg.onload = function(){
                                  tempCanvas = document.createElement('canvas');
                                tempCanvas.width = svg.width;
                                tempCanvas.height = svg.height;
                                var tempCtx = tempCanvas.getContext('2d');
                                tempCtx.drawImage(svg,0,0,svg.width,svg.height);
                             }           
                         }
                      
            function drawPoint(pointX, pointY) {
                            
                ctx.drawImage(tempCanvas, pointX - svg.width / 4, pointY - svg.height / 4, svg.width / 2, svg.height / 2);
            }
            canvas.addEventListener('click', function (e) {
                drawPoint(e.clientX, e.clientY);
            }, false);
        }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

HTML / CSS 相关文章推荐
全面解析CSS Media媒体查询使用操作(推荐)
Aug 15 HTML / CSS
CSS3属性background-size使用指南
Dec 09 HTML / CSS
Css3圆角边框制作代码
Nov 18 HTML / CSS
老生常谈CSS中的长度单位
Jun 27 HTML / CSS
html5 sessionStorage会话存储_动力节点Java学院整理
Jul 06 HTML / CSS
html5 Canvas绘制线条 closePath()实例代码
May 10 HTML / CSS
HTML5 canvas基本绘图之绘制线条
Jun 27 HTML / CSS
SVG实现多彩圆环倒计时效果的示例代码
Nov 21 HTML / CSS
HTML5 常见面试题之PC端和移动端区别介绍
Jan 22 HTML / CSS
HTML5 source标签:媒介元素定义媒介资源
Jan 29 HTML / CSS
html5 canvas简单封装一个echarts实现不了的饼图
Jun 12 HTML / CSS
简单介绍 http请求响应参数、无连接无状态、MIME、状态码、端口、telnet、curl
Mar 31 HTML / CSS
canvas实现有递增动画的环形进度条的实现方法
Jul 10 #HTML / CSS
Html5新增标签与样式及让元素水平垂直居中
Jul 11 #HTML / CSS
解决H5的a标签的download属性下载service上的文件出现跨域问题
Jul 16 #HTML / CSS
html通过canvas转成base64的方法
Jul 18 #HTML / CSS
基于Canvas+Vue的弹幕组件的实现
Jul 23 #HTML / CSS
HTML5 WebGL 实现民航客机飞行监控系统
Jul 25 #HTML / CSS
关于前端上传文件全面基础扫盲贴(入门)
Aug 01 #HTML / CSS
You might like
星际争霸 Starcraft 发展史
2020/03/14 星际争霸
php下关于中英数字混排的字符串分割问题
2010/04/06 PHP
PHP设计模式之装饰者模式
2012/02/29 PHP
PHP用星号隐藏部份用户名、身份证、IP、手机号等实例
2014/04/08 PHP
php上传文件问题汇总
2015/01/30 PHP
laravel 5异常错误:FatalErrorException in Handler.php line 38的解决
2017/10/12 PHP
Laravel5.5+ 使用API Resources快速输出自定义JSON方法详解
2020/04/06 PHP
学习ExtJS table布局
2009/10/08 Javascript
js 创建书签小工具之理论
2011/02/25 Javascript
javascript仿qq界面的折叠菜单实现代码
2012/12/12 Javascript
JQuery判断子iframe何时加载完成解决方案
2013/08/20 Javascript
浅析jQuery EasyUI中的tree使用指南
2014/12/18 Javascript
javascript汉字拼音互转的简单实例
2016/10/09 Javascript
Vue.js 2.0 移动端拍照压缩图片预览及上传实例
2017/04/27 Javascript
js实现图片旋转 js滚动鼠标中间对图片放大缩小
2017/07/05 Javascript
vue cli webpack中使用sass的方法
2018/02/24 Javascript
mpvue小程序仿qq左滑置顶删除组件
2018/08/03 Javascript
vue的列表交错过渡实现代码示例
2019/05/05 Javascript
常见的浏览器存储方式(cookie、localStorage、sessionStorage)
2019/05/07 Javascript
Vue事件修饰符native、self示例详解
2019/07/09 Javascript
微信小程序点餐系统开发常见问题汇总
2019/08/06 Javascript
微信小程序自定义顶部组件customHeader的示例代码
2020/06/03 Javascript
[01:32]dota2拉比克至宝(222)
2018/12/20 DOTA
用python + hadoop streaming 分布式编程(一) -- 原理介绍,样例程序与本地调试
2014/07/14 Python
《Python之禅》中对于Python编程过程中的一些建议
2015/04/03 Python
Python中有趣在__call__函数
2015/06/21 Python
基于Django的python验证码(实例讲解)
2017/10/23 Python
python使用代理ip访问网站的实例
2018/05/07 Python
详解利用django中间件django.middleware.csrf.CsrfViewMiddleware防止csrf攻击
2018/10/09 Python
[机器视觉]使用python自动识别验证码详解
2019/05/16 Python
澳大利亚网上玩具商店:Mr Toys Toyworld
2018/03/25 全球购物
意大利在线药房:Farmacia Loreto Gallo
2019/08/09 全球购物
Linux如何命名文件--使用文件名时应注意
2014/05/29 面试题
电钳专业个人求职信
2014/01/04 职场文书
Nginx 过滤静态资源文件的访问日志的实现
2021/03/31 Servers
Js类的构建与继承案例详解
2021/09/15 Javascript