详解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 相关文章推荐
css3绘制百度的小度熊
Oct 29 HTML / CSS
使用Filters滤镜弥补CSS3的跨浏览器问题以及兼容低版本IE
Jan 23 HTML / CSS
css3制作彩色边线3d立体按钮的示例(css3按钮)
May 06 HTML / CSS
非常震撼的纯CSS3人物行走动画
Feb 24 HTML / CSS
CSS3之transition实现下划线的示例代码
May 30 HTML / CSS
html5 Canvas画图教程(11)—使用lineTo/arc/bezierCurveTo画椭圆形
Jan 09 HTML / CSS
HTML5 Canvas自定义圆角矩形与虚线示例代码
Aug 02 HTML / CSS
HTML5标签使用方法详解
Nov 27 HTML / CSS
Html5百叶窗效果的示例代码
Dec 11 HTML / CSS
HTML5 input新增type属性color颜色拾取器的实例代码
Aug 27 HTML / CSS
H5 video poster属性设置视频封面的方法
May 25 HTML / CSS
使用canvas对video视频某一刻截图功能
Sep 25 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
php使用str_replace实现输入框回车替换br的方法
2014/11/24 PHP
PHP中curl_setopt函数用法实例分析
2015/04/16 PHP
php解析url并得到url中的参数及获取url参数的四种方式
2015/10/26 PHP
Zend Framework实现Zend_View集成Smarty模板系统的方法
2016/03/05 PHP
浅析PHP开发规范
2018/02/05 PHP
解决jQuery插件tipswindown与hintbox冲突
2010/11/05 Javascript
关于COOKIE个数与大小的问题
2011/01/17 Javascript
document.getElementById介绍
2011/09/13 Javascript
Knockoutjs快速入门(经典)
2012/12/24 Javascript
BootStrap中Datepicker控件带中文的js文件
2016/08/10 Javascript
JS实现队列的先进先出功能示例
2017/05/10 Javascript
AngularJS实现单一页面内设置跳转路由的方法
2017/06/28 Javascript
vue登录路由验证的实现
2017/12/13 Javascript
微信小程序图片轮播组件gallery slider使用方法详解
2018/01/31 Javascript
angularJs中$http获取后台数据的实例讲解
2018/08/08 Javascript
vue element upload实现图片本地预览
2019/08/20 Javascript
使用p5.js临摹动态图形
2019/10/23 Javascript
Taro UI框架开发小程序实现左滑喜欢右滑不喜欢效果的示例代码
2020/05/18 Javascript
Javascript实现秒表计时游戏
2020/05/27 Javascript
vue项目接口管理,所有接口都在apis文件夹中统一管理操作
2020/08/13 Javascript
微信小程序基于ColorUI构建皮皮虾短视频去水印组件
2020/11/04 Javascript
[01:09]DOTA2次级职业联赛 - 99战队宣传片
2014/12/01 DOTA
[01:32]DOTA2上海特锦赛现场采访:最想COS的英雄
2016/03/25 DOTA
python函数参数*args**kwargs用法实例
2013/12/04 Python
基于python的多进程共享变量正确打开方式
2018/04/28 Python
对python中的控制条件、循环和跳出详解
2019/06/24 Python
Python return语句如何实现结果返回调用
2020/10/15 Python
python+selenium自动化实战携带cookies模拟登陆微博
2021/01/19 Python
入党转预备思想汇报
2014/01/07 职场文书
2014年计划生育协会工作总结
2014/11/14 职场文书
劳动纠纷调解协议书格式
2014/11/30 职场文书
公司年会开场白
2015/06/01 职场文书
jupyter notebook保存文件默认路径更改方法汇总(亲测可以)
2021/06/09 Python
新手初学Java List 接口
2021/07/07 Java/Android
Python编程中Python与GIL互斥锁关系作用分析
2021/09/15 Python
Redis实现分布式锁的五种方法详解
2022/06/14 Redis