有没有办法将图像剪切为带有CanvasRenderingContext2D
的SVG形状?
我尝试使用不同的SVG形状来按需显示图像的各个部分。
例如 - 带有<ellipse>
元素(或等效<path>
)的SVG允许我显示图像的圆形部分。
CanvasRenderingContext2D.clip()似乎与我的需求接近,但我无法找到有关如何将其与SVG一起使用的信息,或者如何将SVG绘制为路径。
我想到的另一个方向是将剪裁区域保存为<path>
元素并手动将其转换为CanvasRenderingContext2D
等效方法,例如lineTo
和arc
答案 0 :(得分:1)
将SVG绘制到画布&amp;使用globalCompositeOperation而不是剪辑。但Firefox有一个将gCO直接应用于svg图像的错误,这会迫使你首先在第二个画布上绘制你的svg;并且在绘制svg之后,Edge之前的IE将会污染画布。
首先解析你的svg,然后使用画布API绘制这些形状(路径命令非常相似,所以它并不那么难,像fabricjs这样的库甚至可以很好地处理它)
另一种选择是将SVG图形转换为.png格式,并使用该图像+ globalCompositeOperation在.png形状内剪切图像。这避免了SVG的跨浏览器问题。
但是,如果剪裁形状只是简单的SVG路径(椭圆等),那么您可能会忘记SVG并使用画布路径命令绘制路径。
我将重新发布之前的SO Q&A来说明画布路径内的剪辑:
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;
答案 1 :(得分:1)
三个步骤:
context.globalCompositeOperation = 'source-in';
只会在SVG已经用彩色像素填充的地方绘制图像,有效地将图像剪切为已经绘制的图像。
您可以将globalCompositeOperation
设置回'source-over'
(默认设置),或者之前使用context.save()
,然后使用context.restore()
将画布重新设置为“正常”绘图模式。
答案 2 :(得分:0)
你不能直接这样做。你可以:
以下是如何为SVG构建简单解析器的示例。它不能用于通用,但假设您知道有问题的SVG。您可以在此基础上构建以支持不同的单位,转换列表等。
提取的路径可以存储在Path2D对象上,而不是直接存储在下面(Path2D在某些浏览器中可能需要poly-fill),或存储自定义对象/数组等。这完全取决于您。
这个例子更像是一个概念验证。
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;