使用canvg脚本将Inline svg转换为canvas [英] Convert Inline svg to canvas using canvg script

查看:213
本文介绍了使用canvg脚本将Inline svg转换为canvas的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个网站: http://materialground.com/icon-maker



我的代码高于我的身体

 < symbol id =fa- flaticon-3viewBox =0 0 512 512> 
< path d =m512 247c0 118-87 216-200 233 1-5 2-11 1-16 0 0-1-6-2-14 41-6 77-25 105-51-1- 2-3-3-5-6-7-11 3-22 3-32 0-9-20-9-20-15-3-22 13-22 22-30 8-9-9-28-20- 27-11 1-41-5-39-28 4-29-36-27-42-40-8-19 6-43 24-49 25-7 51-28 49-52-3-26-14-50 -34-64-21-8-43-13-66-14-20 0-38 5-37 14 2 23 67 29 56 51-6 11-49 27-41 44 6 11 19 1 14 22-2 10- 11 28-24 29-13 1-24-34-60-35-17 0-41 27-21 46 12 12 36-14 42 6 5 14 0 44 22 56 9 5 21 9 34 15-19 4-42 11 -68 21l-23-6c10-8 25-13 21-30-6-26-50-16-80-46-9-10-29-40-29-77-15 28-23 61-23 95 0 11 0 21 2 32 0 0-1 0-1 0-10 0-19 2-28 5-1-12-2-24-2-37 0-129 105-235 235-235 129 0 235 106 235 235z m- 176 69l-58 26 1-12 37-17c-5 0-11-1-16-1-21 0-55 11-94 26l-123-32c-12-3-24-2-34 5l-6 4c- 6 3-6 12 0 16l74 48c-18 9-35 18-49 27l-38-20c-7-4-14-4-20-1l-4 1c-5 2-8 9-5 14l21 37 0 0c-8 7-12 12-12 16 0 12 14 15 27 15 22 0 321-69 321-130 0-13-9-19-22-22z m-126 121l65-23c3-1 6 1 7 4l6 49c1 12-6 24- 17 29l-6 3c-4 2-8 1-11-2l-46-53c-2-2-1-6 2-7z>< / path>
< / symbol>

以下我有这段代码:

 < svg viewBox =0 0 256 512xmlns:xlink =http://www.w3.org/1999/xlinkxmlns =http://www.w3 .org / 2000 / svgversion =1.1class =fa-youtube red draggablevbox =0 0 256 512id =imgwidth =341.3333333333333fill =#fffheight =512 style =width:512!important; height:512!important; padding:0; border-radius:10%> 
< use xlink:href =#fa-flaticon>< / use>
< / svg>

我希望root svg标签被填充颜色等用户修改。背景颜色,笔画,视图等等。



现在问题是如何使用canvg或任何其他脚本将svg保存到png。我也可以使用PHP脚本。



我已经使用了这段代码,但它无法正常工作

  function renderCanvas()
{
var oSerializer = new XMLSerializer();
var sXML = oSerializer.serializeToString(document.getElementById(svg));

canvg(document.getElementById('canvas'),sXML,{ignoreMouse:true,ignoreAnimation:true})
}

我还添加了空白画布。

 < canvas id = 画布 >< /画布> 


解决方案

大多数svg to canvas库都会在外部失败资源(图像,用途,符号和 xlink 名称空间中的任何其他属性或< funciri> url())进入他们的属性。



我正在写一个脚本,可以处理这些情况。



<它会搜索这样的外部资源,并将其附加到要转换的svg元素的克隆,然后使用canvas drawImage()来呈现svg。



它的使用非常简单,在不久的将来可能会更简单。



SVG2bitmap(SVGElement,[function([canvasElement],[dataURL])|| IMGElement || CanvasElement] [,Object {optional parameters}])



这是一个函数的转储,它用这样的外部att解析元素ributes:

  function parseXlinks(){
//某些浏览器不支持星号命名空间选择器(猜猜哪个那些...)
//创建一个测试元素
var test = document.createElementNS('http://www.w3.org/2000/svg','use');
//将其href属性设置为应该找到的值
test.setAttributeNS(xlinkNS,'href','__#__');
//将它附加到我们的文档
clone.appendChild(test);
//如果querySelector返回null则不支持选择器
var supported = !! clone.querySelector('[* | href * =#]'),
xl,
I;
//测试完成后,删除元素
clone.removeChild(test);
//如果不支持选择器
if(!supported){
// xl是数组
xl = [];
//遍历所有元素
var children = clone.querySelectorAll('*');
for(i = 0; i< children.length; i ++){
//搜索xlink:href属性
var xl_attr = children [i] .getAttributeNS(xlinkNS,'href );
//我们只想要那些引用元素
if(xl_attr&& xl_attr.indexOf('#')> -1){
xl.push(children [一世]);
}
}
} else {
//使用xlink获取所有元素:href属性
xl = clone.querySelectorAll('[* | href * = #]');
}
//可以包含< funciri>的所有属性的列表(url())作为值
var url_attrs = [clip-path,src,cursor,fill,filter,marker,marker-start,marker- mid,marker-end,mask,stroke];
//构建我们的选择器字符串
var urlSelector ='[* |'+ url_attrs.join('* =url],* [* |')+'* =url]' ;
//查询是魔术
var url = clone.querySelectorAll(urlSelector);

//我们发现
if(xl.length || url.length){
//创建一个< defs>或者获得svg的一个
getDef();
}
//没有这样的元素?
else {
//直接用图片继续
parseImages();
返回;
}

//为外部文档创建一个数组
var externals = [],
inDoc = [];
var getElements = function(arr){
for(var i = 0; i< inDoc.length; i ++){
var el = inDoc [i];
//不在我们的实际svg中?
if(!svg.getElementById(el)){
//在页面中的其他位置获取它
var ref = document.querySelector('#'+ el);
//失败
if(!ref){
console.warn('找不到这个元素:','#'+ el);
继续;
}
//我们得到它,为我们的svg
defs.appendChild添加一个克隆(ref.cloneNode(true));
}
}
};

//获取外部文件
var addFile = function(url){
var pushing = false;
for(var i = 0; i< externals.length; i ++){
//如果我们已经有了这个文件,只需推送元素
if(url [0] == = externals [i] .file_url){
pressed = true;
externals [i] .elements.push(url [1]);
checkParse();
}
}
//这是一个新的doc
if(!推){
//创建我们将用于此doc的对象
var that = {
file_url:url [0],
elements:[url [1]],
loading:null
};
//将它添加到我们的数组
externals.push(that);
//创建一个新请求
var xhr = new XMLHttpRequest();

xhr.onload = function(){
//我们不再加载
that.loading = false;
//一切都很好
if(this.status === 200){
that.response = this.responseText;
} else {
console.warn('无法加载此文档:',url [0],'\ n'+
'这些元素丢失:',that.elements .join(','));
}
//如果我们是最后一个
checkParse();
};
xhr.onerror = function(e){
that.loading = false;
console.warn('无法加载此文档',url [0]);
console.warn('那些元素丢失:',that.elements.join(','));
checkParse();
};
xhr.open('GET',that.file_url);
that.loading = true;
xhr.send();
}
};

var checkParse = function(){
//还有待处理的加载
if(externals.some(function(o){
return o.loading;
})){
return;
} else {
//遍历所有文件
for(var i = 0; i< externals.length; i ++){
//如果我们加载失败它是
如果(!externals [i] .response){
继续;
}
//从响应中创建一个新文档
var doc = new DOMParser()。parseFromString(externals [i] .response,'image / svg + xml');
//循环遍历我们在本文档中使用的元素
var els = externals [i] .elements;
for(var j = 0; j< els.length; j ++){
//获取我们将在svg文件中使用的新ID
var newId = externals [i] .file_url.replace('。svg','_')+ els [j];
//这个已经附加了
if(defs.querySelector('#'+ newId)){
continue;
}
//在响应文档中找到它
var elem = doc.documentElement.querySelector('#'+ els [j]);
if(elem){
//我们发现它是
var clone = elem.cloneNode(true);
clone.setAttribute('id',newId);
defs.appendChild(clone);
} else {
console.warn('找不到这个元素:',externals [i] .file_url +'#'+ els [j]);
}
}
}
//所有回复都已被解析
//我们可以继续使用图片
parseImages();
}
};

//获取包含< funciri>的属性
for(i = 0; i< url.length; i ++){
//获取我们所有节点的属性
var att = url [i] .attributes;
//将新数组存储到我们的节点
url [i] .external_attr = [];
for(var j = 0; j< att.length; j ++){
//它是否有< funciri> ?
if(att [j] .value.indexOf('url(')> -1){
//将它添加到数组
url [i] .external_attr.push( att [j]);
}
}
}
var split_attr = function(list,type){
//遍历我们的列表以获取外部元素
for(var i = 0; i< list.length; i ++){
var hrefs = [],
j;
if(type ==='xlink') {
//获取元素的href属性
hrefs.push(list [i] .getAttributeNS(xlinkNS,'href')。split('#'));
} else {
//遍历包含< funciri>
var attr = list [i] .external_attr;
for(j = 0; j< attr.length; j ++)的所有属性
hrefs.push(attr [j] .value.substring(4).slice(0,-1).split('#'));
}
for(j = 0 ; j< hrefs.length; j ++){
var href = hrefs [j];
//它确实指向外部doc
if(href) [0] .indexOf('。svg')> 0){
addFile(href);
//如果不同的外部文档使用相同的ID,则为新ID
var newId ='#'+ href [0] .replace('。svg','_')+ href [1];
//'xlink'case
if(type ==='xlink')
list [i] .setAttributeNS(xlinkNS,'href',newId);
//< funciri> case
else
list [i] .setAttribute(list [i] .external_attr [j] .name,'url('+ newId +')');
}
//它应该在页面内
else if(!href [0]){
//如果它已经没有$ b $将它推送到我们的数组b if(inDoc.indexOf(href [1]< 0)){
inDoc.push(href [1]);
}
}
}
}
if(inDoc.length){
getElements(inDoc);
}
};

split_attr(xl,'xlink');
split_attr(url,'funciri');

//所有都是同步完成或在我们完成解析之前完成(不确定是否会发生)
if(externals.length === 0 ||!externals.some(function(o) {
return o.loading;
})){
exportDoc();
}
}

实例:



  var svg = toPixel; var clone = svg.cloneNode(true); var doSomethingWith = function(canvas){document.body.appendChild(canvas)} ; var xlinkNS ='http://www.w3.org/1999/xlink';function parseXlinks(){//某些浏览器不支持星号命名空间选择器(猜猜哪些......)//创建测试element var test = document.createElementNS('http://www.w3.org/2000/svg','use'); //将其href属性设置为应该找到的内容test.setAttributeNS(xlinkNS,'href','__#__'); //将它附加到我们的文档clone.appendChild(test); //如果querySelector返回null,则不支持选择器var supported = !! clone.querySelector('[* | href * =#]'),xl,i; //测试完成后,删除元素clone.removeChild(test); //如果(!支持){// xl是数组xl = [],则不支持选择器; //遍历所有元素var children = clone.querySelectorAll('*'); for(i = 0; i< children.length; i ++){//搜索xlink:href属性var xl_attr = children [i] .getAttributeNS(xlinkNS,'href'); //我们只想要那些引用元素if(xl_attr&& xl_attr.indexOf('#')> -1){xl.push(children [i]); }}} else {//使用xlink获取所有元素:href属性xl = clone.querySelectorAll('[* | href * =#]'); } //可以包含< funciri>的所有属性的列表(url())as value var url_attrs = [clip-path,src,cursor,fill,filter,marker,marker-start,marker-mid, marker-end,mask,stroke]; //构建我们的选择器字符串var urlSelector ='[* |'+ url_attrs.join('* =url],* [* |')+'* =url]'; //查询是magic var url = clone.querySelectorAll(urlSelector); //我们发现了一些if(xl.length || url.length){//创建一个< defs>或获取svg的一个getDef(); } //没有这样的元素? else {//直接继续使用图片parseImages();返回; } //为外部文档创建一个数组var externals = [],inDoc = []; var getElements = function(arr){for(var i = 0; i< inDoc.length; i ++){var el = inDoc [i]; //不在我们的实际svg中? if(!svg.getElementById(el)){//将它放在页面中的其他地方var ref = document.querySelector('#'+ el); //失败如果(!ref){console.warn('找不到这个元素:','#'+ el);继续;我们得到它,为我们的svg defs.appendChild添加一个克隆(ref.cloneNode(true)); }}; //获取外部文件var addFile = function(url){var pushing = false; for(var i = 0; i< externals.length; i ++){//如果我们已经有了这个文档,只需按下元素if(url [0] === externals [i] .file_url){pushing = true ;的外部[I] .elements.push(URL [1]); checkParse();这是一个新的文档if(!推){//创建我们将用于此doc var的对象= {file_url:url [0],elements:[url [1]],loading:null }; //将它添加到我们的数组externals.push(that); //创建一个新请求var xhr = new XMLHttpRequest(); xhr.onload = function(){//我们不再加载that.loading = false; //如果(this.status === 200){that.response = this.responseText; } else {console.warn('无法加载此文档:',url [0],'\ n'+'这些元素丢失:',that.elements.join(',')); } //如果我们是最后一个checkParse(); }; xhr.onerror = function(e){that.loading = false; console.warn('无法加载此文档',url [0]); console.warn('那些元素丢失:',that.elements.join(',')); checkParse(); }; xhr.open('GET',that.file_url); that.loading = true; xhr.send(); }}; var checkParse = function(){//如果(externals.some(function(o){return o.loading;})){return仍有待处理的加载} } else {//循环遍历所有文档(var i = 0; i< externals.length; i ++){//如果我们无法加载它,如果(!externals [i] .response){continue; } //从响应中创建一个新文档var doc = new DOMParser()。parseFromString(externals [i] .response,'image / svg + xml'); //遍历我们在本文档中使用的元素var els = externals [i] .elements; for(var j = 0; j< els.length; j ++){//获取我们将在svg文件中使用的新id var newId = externals [i] .file_url.replace('。svg','_ ')+ els [j]; //如果(defs.querySelector('#'+ newId)){continue; } //在响应doc var elem = doc.documentElement.querySelector('#'+ els [j])中找到它; if(elem){//我们发现var clone = elem.cloneNode(true); clone.setAttribute('id',newId); defs.appendChild(克隆); } else {console.warn('找不到这个元素:',externals [i] .file_url +'#'+ els [j]); //已经解析了所有响应//我们可以继续使用图像parseImages(); }}; //获取包含< funciri>的属性for(i = 0; i< url.length; i ++){//得到我们节点的所有属性var att = url [i] .attributes; //将新数组存储到节点url [i] .external_attr = []; for(var j = 0; j< att.length; j ++){//它是否有< funciri> ? if(att [j] .value.indexOf('url(')> -1){//将其添加到数组url [i] .external_attr.push(att [j]);}}} var split_attr = function(list,type){//遍历我们的列表以获取外部元素(var i = 0; i< list.length; i ++){var hrefs = [],j; if(type ===' xlink'){//获取元素的href属性hrefs.push(list [i] .getAttributeNS(xlinkNS,'href')。split('#'));} else {//遍历包含a的所有属性< funciri> var attr = list [i] .external_attr; for(j = 0; j< attr.length; j ++)hrefs.push(attr [j] .value.substring(4).slice(0, - 1).split('#'));} for(j = 0; j< hrefs.length; j ++){var href = hrefs [j]; //它确实指向外部doc if(href [0 ] .indexOf('。svg')> 0){addFile(href); //如果不同的外部文档使用相同的id,则为新的id var newId ='# '+ href [0] .replace('。svg','_')+ href [1]; //'xlink'case if if(type ==='xlink')list [i] .setAttributeNS(xlinkNS,'href',newId); //< funciri> case else list [i] .setAttribute(list [i] .external_attr [j] .name,'url('+ newId +')');如果(!href [0]){//将它推送到我们的数组,如果它已经不在那里(inDoc.indexOf(href [1]< 0)){inDoc.push (HREF [1]); if(inDoc.length){getElements(inDoc); }}; split_attr(xl,'xlink'); split_attr(url,'funciri'); //所有都是同步完成的,或者在我们完成解析之前(不确定会发生这种情况)if(externals.length === 0 ||!externals.some(function(o){return o.loading;})){exportDoc( ); var defs; var getDef = function(){//我们有一个`< defs>`元素吗? defs = svg.querySelector('defs')|| document.createElementNS('http://www.w3.org/2000/svg','defs'); if(!defs.parentNode){svg.insertBefore(defs,svg.firstElementChild); var exportDoc = function(){//检查我们的svgNode是否将width和height属性设置为绝对值//否则,canvas将无法绘制它var bbox = svg.getBoundingClientRect(); if(svg.width.baseVal.unitType!== 1)svg.setAttribute('width',bbox.width); if(svg.height.baseVal.unitType!== 1)svg.setAttribute('height',bbox.height); //序列化我们的节点var svgData =(new XMLSerializer())。serializeToString(svg); //记得编码特殊字符var svgURL ='data:image / svg + xml; charset = utf8,'+ encodeURIComponent(svgData); var svgImg = new Image(); svgImg.onload = function(){var canvas = document.createElement('canvas'); // IE11没有在svg图像上设置宽度... canvas.width = this.width || bbox.width; canvas.height = this.height || bbox.height; canvas.getContext('2d')。drawImage(svgImg,0,0,canvas.width,canvas.height); doSomethingWith(canvas)}; svgImg.src = svgURL;}; parseXlinks();  

  canvas {border:1px solid green!important;}  

 < ; script src =https://rawgit.com/Kaiido/SVG2Bitmap/master/SVG2Bitmap.js>< / script>< svg style =display:none> < symbol id =sym01viewBox =0 0 150 110> < circle cx =50cy =50r =40stroke-width =8stroke =redfill =red/> < circle cx =90cy =60r =40stroke-width =8stroke =greenfill =white/> < / symbol>< / svg>< svg id =toPixel> < use xlink:href =#sym01/>< / svg>< br>画布版本:< br>  



或使用整个脚本:



  SVG2bitmap (toPixel,function(canvas){document.body.appendChild(canvas);});  

  canvas {border:1px solid green!important;}  

 < script src =https://rawgit.com/Kaiido/SVG2Bitmap/master/SVG2Bitmap.js>< / script>< svg style =display:none> < symbol id =sym01viewBox =0 0 150 110> < circle cx =50cy =50r =40stroke-width =8stroke =redfill =red/> < circle cx =90cy =60r =40stroke-width =8stroke =greenfill =white/> < / symbol>< / svg>< svg id =toPixel> < use xlink:href =#sym01/>< / svg>< br>画布版本:< br>  


I have this website: http://materialground.com/icon-maker

I have this code above my body

<symbol id="fa-flaticon-3" viewBox="0 0 512 512">
      <path d="m512 247c0 118-87 216-200 233 1-5 2-11 1-16 0 0-1-6-2-14 41-6 77-25 105-51-1-2-3-3-5-6-7-11 3-22 3-32 0-9-20-9-20-15-3-22 13-22 22-30 8-9-9-28-20-27-11 1-41-5-39-28 4-29-36-27-42-40-8-19 6-43 24-49 25-7 51-28 49-52-3-26-14-50-34-64-21-8-43-13-66-14-20 0-38 5-37 14 2 23 67 29 56 51-6 11-49 27-41 44 6 11 19 1 14 22-2 10-11 28-24 29-13 1-24-34-60-35-17 0-41 27-21 46 12 12 36-14 42 6 5 14 0 44 22 56 9 5 21 9 34 15-19 4-42 11-68 21l-23-6c10-8 25-13 21-30-6-26-50-16-80-46-9-10-29-40-29-77-15 28-23 61-23 95 0 11 0 21 2 32 0 0-1 0-1 0-10 0-19 2-28 5-1-12-2-24-2-37 0-129 105-235 235-235 129 0 235 106 235 235z m-176 69l-58 26 1-12 37-17c-5 0-11-1-16-1-21 0-55 11-94 26l-123-32c-12-3-24-2-34 5l-6 4c-6 3-6 12 0 16l74 48c-18 9-35 18-49 27l-38-20c-7-4-14-4-20-1l-4 1c-5 2-8 9-5 14l21 37 0 0c-8 7-12 12-12 16 0 12 14 15 27 15 22 0 321-69 321-130 0-13-9-19-22-22z m-126 121l65-23c3-1 6 1 7 4l6 49c1 12-6 24-17 29l-6 3c-4 2-8 1-11-2l-46-53c-2-2-1-6 2-7z"></path>
    </symbol>

And below i have this code :

<svg viewBox="0 0 256 512" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" version="1.1" class="fa-youtube red draggable" vbox="0 0 256 512" id="img" width="341.3333333333333" fill="#fff" height="512" style="width:512 !important; height:512 !important;  padding:0; border-radius:10%">
<use xlink:href="#fa-flaticon"></use>
</svg>

I want the root svg tag to be modified by users like fill color. background color, stroke, viewbox etc.

Now the question is how to save the svg to png using canvg or any other script. I can also use php script.

I have used this code but its not working

function renderCanvas()
{
    var oSerializer = new XMLSerializer();
    var sXML = oSerializer.serializeToString(document.getElementById("svg"));

    canvg(document.getElementById('canvas'), sXML,{ ignoreMouse: true, ignoreAnimation: true })
}

I also added blank canvas.

<canvas id="canvas"></canvas>

解决方案

Most of the svg to canvas libraries will fail on external resources (images, uses, symbols and any other attribute in the xlink name-space or with a <funciri>(url()) into their attribute.

I am writing a script that does handle those cases.

It does search for such external resources, and append it to a clone of the svg element to be converted, and then uses the canvas drawImage() ability to render svg.

Its usage is quite simple, and may be even simpler in a near future.

SVG2bitmap(SVGElement, [function([canvasElement],[dataURL]) || IMGElement || CanvasElement] [, Object{optional parameters}])

Here is a dump of the function that do parse elements with such external attributes :

function parseXlinks() {
  // some browsers don't support the asterisk namespace selector (guess which ones ...)
  // create a test element
  var test = document.createElementNS('http://www.w3.org/2000/svg', 'use');
  // set its href attribute to something that should be found
  test.setAttributeNS(xlinkNS, 'href', '__#__');
  // append it to our document
  clone.appendChild(test);
  // if querySelector returns null then the selector is not supported
  var supported = !!clone.querySelector('[*|href*="#"]'),
    xl,
    i;
  // the test is done, remove the element
  clone.removeChild(test);
  // if the selector is not supported
  if (!supported) {
    // xl is an array
    xl = [];
    // iterate through all our elements
    var children = clone.querySelectorAll('*');
    for (i = 0; i < children.length; i++) {
      // search the xlink:href attribute
      var xl_attr = children[i].getAttributeNS(xlinkNS, 'href');
      // we only want the ones that refer to elements
      if (xl_attr && xl_attr.indexOf('#') > -1) {
        xl.push(children[i]);
      }
    }
  } else {
    // get all our elements using an xlink:href attribute
    xl = clone.querySelectorAll('[*|href*="#"]');
  }
  // the list of all attributes that can have a <funciri> (url()) as value
  var url_attrs = ["clip-path", "src", "cursor", "fill", "filter", "marker", "marker-start", "marker-mid", "marker-end", "mask", "stroke"];
  // build our selector string
  var urlSelector = '[*|' + url_attrs.join('*="url"], *[*|') + '*="url"]';
  // query is magic
  var url = clone.querySelectorAll(urlSelector);

  // we found something
  if (xl.length || url.length) {
    // create a <defs> or get the svg's one
    getDef();
  }
  // there is no such elements ?
  else {
    // continue directly with images
    parseImages();
    return;
  }

  // create an array for external docs
  var externals = [],
    inDoc = [];
  var getElements = function(arr) {
    for (var i = 0; i < inDoc.length; i++) {
      var el = inDoc[i];
      // not in our actual svg ?
      if (!svg.getElementById(el)) {
        // get it somewhere else in the page
        var ref = document.querySelector('#' + el);
        // failed
        if (!ref) {
          console.warn('could not find this element : ', '#' + el);
          continue;
        }
        // we got it, add a clone to our svg
        defs.appendChild(ref.cloneNode(true));
      }
    }
  };

  // fetch the external documents
  var addFile = function(url) {
    var pushed = false;
    for (var i = 0; i < externals.length; i++) {
      // if we already have this document, just push the element
      if (url[0] === externals[i].file_url) {
        pushed = true;
        externals[i].elements.push(url[1]);
        checkParse();
      }
    }
    // that was a new doc
    if (!pushed) {
      // create the object we'll use for this doc
      var that = {
        file_url: url[0],
        elements: [url[1]],
        loading: null
      };
      // add it to our array
      externals.push(that);
      // create a new request
      var xhr = new XMLHttpRequest();

      xhr.onload = function() {
        // we're not loading anymore
        that.loading = false;
        // everything went fine
        if (this.status === 200) {
          that.response = this.responseText;
        } else {
          console.warn('could not load this document :', url[0], '\n' +
            'Those elements are lost : ', that.elements.join(' , '));
        }
        // In case we were the last one
        checkParse();
      };
      xhr.onerror = function(e) {
        that.loading = false;
        console.warn('could not load this document', url[0]);
        console.warn('Those elements are lost : ', that.elements.join(' , '));
        checkParse();
      };
      xhr.open('GET', that.file_url);
      that.loading = true;
      xhr.send();
    }
  };

  var checkParse = function() {
    // there are still pending loadings
    if (externals.some(function(o) {
      return o.loading;
    })) {
      return;
    } else {
      // loop through all our documents
      for (var i = 0; i < externals.length; i++) {
        // if we failed to load it
        if (!externals[i].response) {
          continue;
        }
        // create a new doc from the response
        var doc = new DOMParser().parseFromString(externals[i].response, 'image/svg+xml');
        // loop through the elements we use in this document
        var els = externals[i].elements;
        for (var j = 0; j < els.length; j++) {
          // get the new id we'll use in our svg file
          var newId = externals[i].file_url.replace('.svg', '_') + els[j];
          // this one was already appended
          if (defs.querySelector('#' + newId)) {
            continue;
          }
          // find it in the response doc
          var elem = doc.documentElement.querySelector('#' + els[j]);
          if (elem) {
            // we found it
            var clone = elem.cloneNode(true);
            clone.setAttribute('id', newId);
            defs.appendChild(clone);
          } else {
            console.warn('could not find this element : ', externals[i].file_url + '#' + els[j]);
          }
        }
      }
      // all responses have been parsed
      // we can continue with images
      parseImages();
    }
  };

  // get the attributes containing the <funciri>
  for (i = 0; i < url.length; i++) {
    // get all our node's attributes
    var att = url[i].attributes;
    // store a new array to our node
    url[i].external_attr = [];
    for (var j = 0; j < att.length; j++) {
      // does it have a <funciri> ?
      if (att[j].value.indexOf('url(') > -1) {
        // add it to the array
        url[i].external_attr.push(att[j]);
      }
    }
  }
  var split_attr = function(list, type) {
    // loop through our list to get the external elements
    for (var i = 0; i < list.length; i++) {
      var hrefs = [],
        j;
      if (type === 'xlink') {
        // get the href attribute of our element
        hrefs.push(list[i].getAttributeNS(xlinkNS, 'href').split('#'));
      } else {
        // loop through all attributes containing a <funciri>
        var attr = list[i].external_attr;
        for (j = 0; j < attr.length; j++)
          hrefs.push(attr[j].value.substring(4).slice(0, -1).split('#'));
      }
      for (j = 0; j < hrefs.length; j++) {
        var href = hrefs[j];
        // it does point to an external doc
        if (href[0].indexOf('.svg') > 0) {
          addFile(href);
          // a new id if different external docs uses the same ids
          var newId = '#' + href[0].replace('.svg', '_') + href[1];
          // 'xlink' case
          if (type === 'xlink')
            list[i].setAttributeNS(xlinkNS, 'href', newId);
          // <funciri> case
          else
            list[i].setAttribute(list[i].external_attr[j].name, 'url(' + newId + ')');
        }
        // it should be inside the page
        else if (!href[0]) {
          // push it to our array if it's not there already
          if (inDoc.indexOf(href[1] < 0)) {
            inDoc.push(href[1]);
          }
        }
      }
    }
    if (inDoc.length) {
      getElements(inDoc);
    }
  };

  split_attr(xl, 'xlink');
  split_attr(url, 'funciri');

  // all was done synchronously or before we finished parsing (not sure this can happen)
  if (externals.length === 0 || !externals.some(function(o) {
    return o.loading;
  })) {
    exportDoc();
  }
}

Live example :

var svg = toPixel;
var clone = svg.cloneNode(true);
var doSomethingWith = function(canvas) {
  document.body.appendChild(canvas)
};
var xlinkNS = 'http://www.w3.org/1999/xlink';

function parseXlinks() {
  // some browsers don't support the asterisk namespace selector (guess which ones ...)
  // create a test element
  var test = document.createElementNS('http://www.w3.org/2000/svg', 'use');
  // set its href attribute to something that should be found
  test.setAttributeNS(xlinkNS, 'href', '__#__');
  // append it to our document
  clone.appendChild(test);
  // if querySelector returns null then the selector is not supported
  var supported = !!clone.querySelector('[*|href*="#"]'),
    xl,
    i;
  // the test is done, remove the element
  clone.removeChild(test);
  // if the selector is not supported
  if (!supported) {
    // xl is an array
    xl = [];
    // iterate through all our elements
    var children = clone.querySelectorAll('*');
    for (i = 0; i < children.length; i++) {
      // search the xlink:href attribute
      var xl_attr = children[i].getAttributeNS(xlinkNS, 'href');
      // we only want the ones that refer to elements
      if (xl_attr && xl_attr.indexOf('#') > -1) {
        xl.push(children[i]);
      }
    }
  } else {
    // get all our elements using an xlink:href attribute
    xl = clone.querySelectorAll('[*|href*="#"]');
  }
  // the list of all attributes that can have a <funciri> (url()) as value
  var url_attrs = ["clip-path", "src", "cursor", "fill", "filter", "marker", "marker-start", "marker-mid", "marker-end", "mask", "stroke"];
  // build our selector string
  var urlSelector = '[*|' + url_attrs.join('*="url"], *[*|') + '*="url"]';
  // query is magic
  var url = clone.querySelectorAll(urlSelector);

  // we found something
  if (xl.length || url.length) {
    // create a <defs> or get the svg's one
    getDef();
  }
  // there is no such elements ?
  else {
    // continue directly with images
    parseImages();
    return;
  }

  // create an array for external docs
  var externals = [],
    inDoc = [];
  var getElements = function(arr) {
    for (var i = 0; i < inDoc.length; i++) {
      var el = inDoc[i];
      // not in our actual svg ?
      if (!svg.getElementById(el)) {
        // get it somewhere else in the page
        var ref = document.querySelector('#' + el);
        // failed
        if (!ref) {
          console.warn('could not find this element : ', '#' + el);
          continue;
        }
        // we got it, add a clone to our svg
        defs.appendChild(ref.cloneNode(true));
      }
    }
  };

  // fetch the external documents
  var addFile = function(url) {
    var pushed = false;
    for (var i = 0; i < externals.length; i++) {
      // if we already have this document, just push the element
      if (url[0] === externals[i].file_url) {
        pushed = true;
        externals[i].elements.push(url[1]);
        checkParse();
      }
    }
    // that was a new doc
    if (!pushed) {
      // create the object we'll use for this doc
      var that = {
        file_url: url[0],
        elements: [url[1]],
        loading: null
      };
      // add it to our array
      externals.push(that);
      // create a new request
      var xhr = new XMLHttpRequest();

      xhr.onload = function() {
        // we're not loading anymore
        that.loading = false;
        // everything went fine
        if (this.status === 200) {
          that.response = this.responseText;
        } else {
          console.warn('could not load this document :', url[0], '\n' +
            'Those elements are lost : ', that.elements.join(' , '));
        }
        // In case we were the last one
        checkParse();
      };
      xhr.onerror = function(e) {
        that.loading = false;
        console.warn('could not load this document', url[0]);
        console.warn('Those elements are lost : ', that.elements.join(' , '));
        checkParse();
      };
      xhr.open('GET', that.file_url);
      that.loading = true;
      xhr.send();
    }
  };

  var checkParse = function() {
    // there are still pending loadings
    if (externals.some(function(o) {
      return o.loading;
    })) {
      return;
    } else {
      // loop through all our documents
      for (var i = 0; i < externals.length; i++) {
        // if we failed to load it
        if (!externals[i].response) {
          continue;
        }
        // create a new doc from the response
        var doc = new DOMParser().parseFromString(externals[i].response, 'image/svg+xml');
        // loop through the elements we use in this document
        var els = externals[i].elements;
        for (var j = 0; j < els.length; j++) {
          // get the new id we'll use in our svg file
          var newId = externals[i].file_url.replace('.svg', '_') + els[j];
          // this one was already appended
          if (defs.querySelector('#' + newId)) {
            continue;
          }
          // find it in the response doc
          var elem = doc.documentElement.querySelector('#' + els[j]);
          if (elem) {
            // we found it
            var clone = elem.cloneNode(true);
            clone.setAttribute('id', newId);
            defs.appendChild(clone);
          } else {
            console.warn('could not find this element : ', externals[i].file_url + '#' + els[j]);
          }
        }
      }
      // all responses have been parsed
      // we can continue with images
      parseImages();
    }
  };

  // get the attributes containing the <funciri>
  for (i = 0; i < url.length; i++) {
    // get all our node's attributes
    var att = url[i].attributes;
    // store a new array to our node
    url[i].external_attr = [];
    for (var j = 0; j < att.length; j++) {
      // does it have a <funciri> ?
      if (att[j].value.indexOf('url(') > -1) {
        // add it to the array
        url[i].external_attr.push(att[j]);
      }
    }
  }
  var split_attr = function(list, type) {
    // loop through our list to get the external elements
    for (var i = 0; i < list.length; i++) {
      var hrefs = [],
        j;
      if (type === 'xlink') {
        // get the href attribute of our element
        hrefs.push(list[i].getAttributeNS(xlinkNS, 'href').split('#'));
      } else {
        // loop through all attributes containing a <funciri>
        var attr = list[i].external_attr;
        for (j = 0; j < attr.length; j++)
          hrefs.push(attr[j].value.substring(4).slice(0, -1).split('#'));
      }
      for (j = 0; j < hrefs.length; j++) {
        var href = hrefs[j];
        // it does point to an external doc
        if (href[0].indexOf('.svg') > 0) {
          addFile(href);
          // a new id if different external docs uses the same ids
          var newId = '#' + href[0].replace('.svg', '_') + href[1];
          // 'xlink' case
          if (type === 'xlink')
            list[i].setAttributeNS(xlinkNS, 'href', newId);
          // <funciri> case
          else
            list[i].setAttribute(list[i].external_attr[j].name, 'url(' + newId + ')');
        }
        // it should be inside the page
        else if (!href[0]) {
          // push it to our array if it's not there already
          if (inDoc.indexOf(href[1] < 0)) {
            inDoc.push(href[1]);
          }
        }
      }
    }
    if (inDoc.length) {
      getElements(inDoc);
    }
  };

  split_attr(xl, 'xlink');
  split_attr(url, 'funciri');

  // all was done synchronously or before we finished parsing (not sure this can happen)
  if (externals.length === 0 || !externals.some(function(o) {
    return o.loading;
  })) {
    exportDoc();
  }
}

var defs;
var getDef = function() {
  // Do we have a `<defs>` element already ?
  defs = svg.querySelector('defs') || document.createElementNS('http://www.w3.org/2000/svg', 'defs');
  if (!defs.parentNode) {
    svg.insertBefore(defs, svg.firstElementChild);
  }
};

var exportDoc = function() {
  // check if our svgNode has width and height properties set to absolute values
  // otherwise, canvas won't be able to draw it
  var bbox = svg.getBoundingClientRect();

  if (svg.width.baseVal.unitType !== 1) svg.setAttribute('width', bbox.width);
  if (svg.height.baseVal.unitType !== 1) svg.setAttribute('height', bbox.height);

  // serialize our node
  var svgData = (new XMLSerializer()).serializeToString(svg);
  // remember to encode special chars
  var svgURL = 'data:image/svg+xml; charset=utf8, ' + encodeURIComponent(svgData);

  var svgImg = new Image();

  svgImg.onload = function() {
    var canvas = document.createElement('canvas');
    // IE11 doesn't set a width on svg images...
    canvas.width = this.width || bbox.width;
    canvas.height = this.height || bbox.height;

    canvas.getContext('2d').drawImage(svgImg, 0, 0, canvas.width, canvas.height);
    doSomethingWith(canvas)
  };

  svgImg.src = svgURL;
};

parseXlinks();

canvas {
  border: 1px solid green !important;
}

<script src="https://rawgit.com/Kaiido/SVG2Bitmap/master/SVG2Bitmap.js"></script>

<svg style="display: none">
  <symbol id="sym01" viewBox="0 0 150 110">
    <circle cx="50" cy="50" r="40" stroke-width="8" stroke="red" fill="red" />
    <circle cx="90" cy="60" r="40" stroke-width="8" stroke="green" fill="white" />
  </symbol>
</svg>

<svg id="toPixel">
  <use xlink:href="#sym01" />
</svg>
<br>canvas version:
<br>

or using the entire script :

SVG2bitmap(toPixel, function(canvas){
  document.body.appendChild(canvas);
  });

canvas { border: 1px solid green !important;}

<script src="https://rawgit.com/Kaiido/SVG2Bitmap/master/SVG2Bitmap.js"></script>

<svg style="display: none">
  <symbol id="sym01" viewBox="0 0 150 110">
    <circle cx="50" cy="50" r="40" stroke-width="8" stroke="red" fill="red" />
    <circle cx="90" cy="60" r="40" stroke-width="8" stroke="green" fill="white" />
  </symbol>
</svg>

<svg id="toPixel">
  <use xlink:href="#sym01" />
</svg>
<br>canvas version:
<br>

这篇关于使用canvg脚本将Inline svg转换为canvas的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆