将图片剪切为svg

时间:2016-05-14 11:01:00

标签: javascript canvas svg clip

有没有办法将图像剪切为带有CanvasRenderingContext2D的SVG形状?
我尝试使用不同的SVG形状来按需显示图像的各个部分。

例如 - 带有<ellipse>元素(或等效<path>)的SVG允许我显示图像的圆形部分。

CanvasRenderingContext2D.clip()似乎与我的需求接近,但我无法找到有关如何将其与SVG一起使用的信息,或者如何将SVG绘制为路径。

我想到的另一个方向是将剪裁区域保存为<path>元素并手动将其转换为CanvasRenderingContext2D等效方法,例如lineToarc

3 个答案:

答案 0 :(得分:1)

@Kaiido对你有一些很好的建议(见他对这个问题的评论)。

  • 将SVG绘制到画布&amp;使用globalCompositeOperation而不是剪辑。但Firefox有一个将gCO直接应用于svg图像的错误,这会迫使你首先在第二个画布上绘制你的svg;并且在绘制svg之后,Edge之前的IE将会污染画布。

  • 首先解析你的svg,然后使用画布API绘制这些形状(路径命令非常相似,所以它并不那么难,像fabricjs这样的库甚至可以很好地处理它)

另一种选择是将SVG图形转换为.png格式,并使用该图像+ globalCompositeOperation在.png形状内剪切图像。这避免了SVG的跨浏览器问题。

但是,如果剪裁形状只是简单的SVG路径(椭圆等),那么您可能会忘记SVG并使用画布路径命令绘制路径。

enter image description here enter image description here

我将重新发布之前的SO Q&A来说明画布路径内的剪辑:

&#13;
&#13;
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;

var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/kidwallpaper.jpg";
function start(){

  // resize the canvas to equal the image size
  var iw=img.width;
  var ih=img.height;
  cw=canvas.width=iw;
  ch=canvas.height=ih;

  // calculate the scaling needed to max the display of the image
  // inside the oval
  if(iw>ih){
    var scaleX=iw/ih
    var scaleY=1;
    var r=ih/2;
  }else{
    var scaleX=1;
    var scaleY=ih/iw;
    var r=iw/2;
  }

  // scale so the circle (arc) becomes an oval
  ctx.scale(scaleX,scaleY);
  ctx.arc(cw/scaleX/2,ch/scaleY/2,r,0,Math.PI*2);
  ctx.fill();

  // undo the scaling
  ctx.scale(1/scaleX,1/scaleY);

  // draw the image centered inside the oval using compositing
  ctx.globalCompositeOperation='source-atop';
  ctx.drawImage(img,cw/2-img.width/2,ch/2-img.height/2);
  ctx.globalCompositeOperation='source-atop';
}
&#13;
body{ background-color: black; }
#canvas{border:1px solid red; margin:0 auto; }
&#13;
<canvas id="canvas" width=300 height=300></canvas>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

三个步骤:

  1. 将SVG绘制到画布上。
  2. 设置context.globalCompositeOperation = 'source-in';
  3. 绘制图像。
  4. 只会在SVG已经用彩色像素填充的地方绘制图像,有效地将图像剪切为已经绘制的图像。

    您可以将globalCompositeOperation设置回'source-over'(默认设置),或者之前使用context.save(),然后使用context.restore()将画布重新设置为“正常”绘图模式。

答案 2 :(得分:0)

你不能直接这样做。你可以:

  • 将SVG绘制到画布中并使用它进行合成剪辑。缺点是由于安全性(外部链接,污染画布等),某些浏览器的支持有限。
  • 手动解析SVG

以下是如何为SVG构建简单解析器的示例。它不能用于通用,但假设您知道有问题的SVG。您可以在此基础上构建以支持不同的单位,转换列表等。

提取的路径可以存储在Path2D对象上,而不是直接存储在下面(Path2D在某些浏览器中可能需要poly-fill),或存储自定义对象/数组等。这完全取决于您。

这个例子更像是一个概念验证。

示例SVG解析器到画布Path2D

&#13;
&#13;
var ctx = c.getContext("2d"),
    mask = document.getElementById("mask");  // get a SVG element

// some random graphics
for(var i=30,r=Math.random;i--;) {
  ctx.fillStyle = "hsl(" + (360*r()) + ",50%,50%)";ctx.fillRect(280*r(),120*r(),50,50)}

// parse SVG element
if (mask.localName) {
  switch(mask.localName) {
    case "rect":
      ctx.rect(v("x"), v("y"), v("width"), v("height"));
      break;
    case "ellipse":
      // need polyfill in some browsers
      ctx.ellipse(v("cx"), v("cy"), v("rx"), v("ry"), 0, 6.28);
      break;
    // more cases here
  }

  // use path from SVG to clip
  ctx.globalCompositeOperation = "destination-in";
  ctx.fill();
}

// helper - obtains a numeric value for SVG element property
function v(name) {return mask[name].baseVal.value}
&#13;
#c, svg {border:1px solid #777}
&#13;
<h4>SVG (showing mask)</h4>
<svg xmlns="http://www.w3.org/2000/svg" 
     width="300" height="150">
  <rect id="mask" x="50" y="30" width="200" height="100" />
</svg>

<h4>Canvas (mask applied from SVG)</h4>
<canvas id=c></canvas>
&#13;
&#13;
&#13;