javascript — конвертирование встроенного svg в canvas с использованием сценария canvg

У меня есть этот сайт: http://materialground.com/icon-maker

У меня есть этот код выше моего тела

<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>

И ниже у меня есть этот код:

<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>

Я хочу, чтобы корневой тег svg был изменен пользователями, такими как цвет заливки. цвет фона, обводка, окно просмотра и т. д.

Теперь вопрос заключается в том, как сохранить SVG в PNG, используя Canvg или любой другой скрипт. Я также могу использовать скрипт 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="canvas"></canvas>

3

Решение

Большинство библиотек svg to canvas будут сбои на внешних ресурсах (изображения, использование, символы и любые другие атрибуты в xlink пространство имен или с <funciri>(url()) в их атрибут.

я сейчас пишу сценарий это обрабатывает те случаи.

Он выполняет поиск таких внешних ресурсов и добавляет его к клону элемента svg для преобразования, а затем использует canvas drawImage() способность оказывать SVG.

Его использование довольно просто, и может быть еще проще в ближайшем будущем.

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

Вот дамп функции, которая выполняет синтаксический анализ элементов с такими внешними атрибутами:

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 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>
3

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector