zoukankan      html  css  js  c++  java
  • FireFox下Canvas使用图像合成绘制SVG的Bug

    本文适合适合对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>>

    如何解决

    找到问题的原因了,解决方法其实简单。
    事情往往就是这样,很多时候,找到问题所在往往比解决问题要难。
    解决方案其实很简单

    1. 代码中加入判断,判断浏浏览器是否是FireFox。
    2. 如果是,则先把svg图片绘制到临时的canvas上面。
    3. 后续绘制用临时的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);
            }

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

    ITman彪叔公众号ITman彪叔公众号

  • 相关阅读:
    HTML+CSS笔记 CSS进阶续集
    HTML+CSS笔记 CSS进阶
    HTML+CSS笔记 CSS入门续集
    HTML+CSS笔记 CSS入门
    test
    Python Paramiko模块安装和使用
    RedHat升级Python到2.7.6
    python数据库操作常用功能使用详解(创建表/插入数据/获取数据)
    5、使用EF对后台SysSample数据增删改查
    4、创建SQL数据库,添加EF实体数据模型
  • 原文地址:https://www.cnblogs.com/flyfox1982/p/11163746.html
Copyright © 2011-2022 走看看