【问题标题】:Change svg fill color and then draw to canvas更改 svg 填充颜色,然后绘制到画布
【发布时间】:2018-03-29 21:32:37
【问题描述】:

我想要做的是加载一个 svg,将其填充颜色更改为随机值,然后将其绘制在画布上。事实证明,这比我想象的要困难得多。这是我目前拥有的代码。

var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");

//images
var bottomLeftTop = new Image();
var bottomRightTop = new Image();
var fullTop= new Image();
var leftMidSide = new Image();
var leftSide = new Image();
var rightMidSide = new Image();
var rightSide = new Image();
var topLeftTop = new Image();
var topRightTop = new Image();

bottomLeftTop.src = "img/bottomLeftTop.svg";
bottomRightTop.src = "img/bottomRightTop.svg";
fullTop.src = "img/fullTop.svg";
leftMidSide.src = "img/leftMidSide.svg";
leftSide.src = "img/leftSide.svg";
rightMidSide.src = "img/rightMidSide.svg";
rightSide.src = "img/rightSide.svg";
topLeftTop.src = "img/topLeftTop.svg";
topRightTop.src = "img/topRightTop.svg";

//draw
context.drawImage(fullTop,50,50);

我目前正在将我的 svg 加载为 Image 对象,这对于绘图来说效果很好,但不允许我更改填充颜色。

我确实尝试将我的 svg 转换为画布命令,这允许我更改填充,但需要大量工作才能正确缩放和定位,而且对于我正在处理的大量图像来说是不可行的。

在使用画布的同时还有其他方法可以做到这一点吗?

【问题讨论】:

    标签: javascript html canvas svg


    【解决方案1】:

    诀窍是通过 XHR 将您的 svg 加载为 XML 并以您想要的任何方式对其进行操作,然后使用 data:image 格式创建您的图像。

    例如

    $.get('img/bottomLeftTop.svg', function(svgXml) {
      var img = new Image();
      var coloredSvgXml = svgXml.replace(/#3080d0/g,'#e05030');
      img.src = "data:image/svg+xml;charset=utf-8,"+coloredSvgXml;
      context.drawImage(img,0,0);
    });
    

    这是我创建的一个 sn-p 来演示操作原理。它使用 in-html 隐藏的 svg 节点在 2d 画布上绘制,然后通过正则表达式更改颜色并再次在同一画布上绘制:

    var canvas = document.getElementById("canvas");
    var context = canvas.getContext("2d");
    
    
    
    var svg = document.getElementById('tmpSvg')
    var blueCircle = (new XMLSerializer).serializeToString(svg);
    var img = new Image();
    img.src = "data:image/svg+xml;charset=utf-8," + blueCircle;
    context.drawImage(img, 0, 0);
    
    redCircle = blueCircle.replace(/#3080d0/g, '#e05030');
    img = new Image();
    img.src = "data:image/svg+xml;charset=utf-8," + redCircle;
    context.drawImage(img, 10, 10);
    .wrapper {
      display: none;
    }
    #canvas {
      width: 400px;
      height: 300px;
    }
    <canvas id="canvas"></canvas>
    
    <div class="wrapper">
      <svg id="tmpSvg" version="1.1" xmlns="http://www.w3.org/2000/svg" width="200" height="200">
        <style>
          circle {
            fill-opacity: 0.5;
            stroke-width: 4;
            fill: #3080d0;
            stroke: #3080d0;
          }
        </style>
        <circle id="my-circle" cx="50" cy="50" r="30" />
      </svg>
    </div>

    当然,没有什么能阻止您使用 JavaScript 内置的 XML 解析器和基于 XPath 的节点操作。但在这种特殊情况下,对于特定颜色,正则表达式可能更有效。

    【讨论】:

    • 如果 SVG 不包含指定的颜色怎么办? (而默认使用黑色)
    • @Valentin,有效点。我猜 SVG XML 操作的复杂性是这样的,在这种情况下,我会事先操作图像以制作黑色 #000001。
    【解决方案2】:

    一种方法是为每个图像创建一个临时画布,获取图像数据并循环遍历它。在循环中,如果像素有颜色数据,则将其更改为所需的值。

    var canvas = document.getElementById("c");
    var ctx = canvas.getContext("2d");
    
    canvas.width = 600;
    canvas.height = 400;
    
    var svg = new Image();
    
    svg.onload = function () {
        canvas.width = svg.width;
        canvas.height = svg.height;
        // create temporary canvas
        var svgCanvas = document.createElement("canvas");
        var svgCtx = svgCanvas.getContext("2d");
        svgCanvas.width = svg.width;
        svgCanvas.height = svg.height;
        // draw the actual svg image to temporary canvas
        svgCtx.drawImage(svg, 0, 0);
        // get ImageData object
        var svgData = svgCtx.getImageData(0, 0, svgCanvas.width, svgCanvas.height);
        // get pixel data
        var data = svgData.data;
        // loop through data
        for (var i = 0; i < data.length; i += 4) {
            // check if pixel alpha value is not 0, then change the data
            if (data[i + 3] !== 0) {
                data[i] = 255; // pixel red value
                data[i + 1] = 0; // pixel green value
                data[i + 2] = 0; // pixel blue value
            }
        }
        // put the data back to the temporary svg canvas
        svgCtx.putImageData(svgData, 0, 0);
        // draw temporary canvas to the real canvas
        ctx.drawImage(svgCanvas, 0, 0);
    }
    // look out for CORS, the svg needs to be on the same origin.
    svg.src = "https://upload.wikimedia.org/wikipedia/commons/thumb/3/38/Maki-alcohol-shop-15.svg/1024px-Maki-alcohol-shop-15.svg.png"; 
    

    参考Pixel manipulation with canvas

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-10-20
      • 2017-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-03
      • 2020-07-22
      相关资源
      最近更新 更多