改变 SVG 填充颜色然后绘制到画布上。

12
我想做的是加载 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作为图像对象加载,这样可以正常绘制,但无法更改填充颜色。

我尝试将我的svg转换为canvas命令,这样可以更改填充颜色,但需要大量的工作来正确缩放和定位,而且在处理大量图像时不可行。

是否有其他方法可以在仍然使用canvas的情况下完成这项任务?

2个回答

13
诀窍是通过XHR将您的SVG加载为XML,并以任何您想要的方式进行操作,然后使用"data:image"格式创建图像。例如:
$.get('img/bottomLeftTop.svg', function(svgXml) {
  var img = new Image();
  var coloredSvgXml = svgXml.replace(/#3080d0/g,'#e05030');
  img.onload = () => context.drawImage(img,0,0);
  img.src = "data:image/svg+xml;charset=utf-8,"+coloredSvgXml;    
});

这是我创建的一个片段,用来演示操作原理。它使用在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.onload = () => context.drawImage(img, 0, 0, 160, 120);
img.src = "data:image/svg+xml;charset=utf-8;base64, " + btoa(blueCircle);

redCircle = blueCircle.replace(/#3080d0/g, '#e05030');
var img2 = new Image();
img2.onload = () => context.drawImage(img2, 10, 10, 160, 120);
img2.src = "data:image/svg+xml;charset=utf-8;base64, " + btoa(redCircle);
.wrapper {
  display: none;
}
#canvas {
  width: 400px;
  height: 300px;
}
<canvas id="canvas"></canvas>

<div class="wrapper">
  <svg id="tmpSvg" 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的节点操作。但在这种特定情况下,对于特定的颜色,正则表达式可能更高效。

1
如果SVG文件中没有指定的颜色,会怎样呢?(默认情况下使用黑色) - vallentin
1
@Valentin,说得好。我想SVG XML操作的复杂性是这样的,在这种情况下,我会事先操纵图像,使黑色变为#000001。 - Alex Pakka

1
一种方法是为每个图像创建一个临时画布,获取图像数据并循环遍历它。在循环中,如果像素具有颜色数据,则将其更改为所需值。
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"; 

参考使用Canvas进行像素操作


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接