tag insertar img icon code javascript html5 canvas svg snap.svg

javascript - insertar - svg web



Convierta SVG a PNG con imágenes aplicadas como fondo a elementos svg (1)

Tengo un archivo SVG externo que contiene algunas etiquetas de imagen incrustadas en el patrón. Cada vez que convierto este SVG en PNG usando toDataURL() , las imágenes PNG generadas no contienen la imagen que he aplicado como patrón a algunas rutas SVG. ¿Hay alguna forma de resolver este problema?


Sí, hay: agregue el svg a su documento y codifique todas las imágenes incluidas en dataURIs.

Estoy escribiendo un script que hace esto y también algunas otras cosas como incluir hojas de estilo externas y alguna otra solución de dónde toDataURL fallará (por ejemplo, elementos externos a los que se hace referencia a través de xlink:href atributo xlink:href o <funciri> ).

Aquí está la función que escribí para analizar el contenido de las imágenes:

function parseImages(){ var xlinkNS = "http://www.w3.org/1999/xlink"; var total, encoded; // convert an external bitmap image to a dataURL var toDataURL = function (image) { var img = new Image(); // CORS workaround, this won''t work in IE<11 // If you are sure you don''t need it, remove the next line and the double onerror handler // First try with crossorigin set, it should fire an error if not needed img.crossOrigin = ''Anonymous''; img.onload = function () { // we should now be able to draw it without tainting the canvas var canvas = document.createElement(''canvas''); canvas.width = this.width; canvas.height = this.height; // draw the loaded image canvas.getContext(''2d'').drawImage(this, 0, 0); // set our <image>''s href attribute to the dataURL of our canvas image.setAttributeNS(xlinkNS, ''href'', canvas.toDataURL()); // that was the last one if (++encoded === total) exportDoc(); }; // No CORS set in the response img.onerror = function () { // save the src var oldSrc = this.src; // there is an other problem this.onerror = function () { console.warn(''failed to load an image at : '', this.src); if (--total === encoded && encoded > 0) exportDoc(); }; // remove the crossorigin attribute this.removeAttribute(''crossorigin''); // retry this.src = ''''; this.src = oldSrc; }; // load our external image into our img img.src = image.getAttributeNS(xlinkNS, ''href''); }; // get an external svg doc to data String var parseFromUrl = function(url, element){ var xhr = new XMLHttpRequest(); xhr.onload = function(){ if(this.status === 200){ var response = this.responseText || this.response; var dataUrl = ''data:image/svg+xml; charset=utf8, '' + encodeURIComponent(response); element.setAttributeNS(xlinkNS, ''href'', dataUrl); if(++encoded === total) exportDoc(); } // request failed with xhr, try as an <img> else{ toDataURL(element); } }; xhr.onerror = function(){toDataURL(element);}; xhr.open(''GET'', url); xhr.send(); }; var images = svg.querySelectorAll(''image''); total = images.length; encoded = 0; // loop through all our <images> elements for (var i = 0; i < images.length; i++) { var href = images[i].getAttributeNS(xlinkNS, ''href''); // check if the image is external if (href.indexOf(''data:image'') < 0){ // if it points to another svg element if(href.indexOf(''.svg'') > 0){ parseFromUrl(href, images[i]); } else // a pixel image toDataURL(images[i]); } // else increment our counter else if (++encoded === total) exportDoc(); } // if there were no <image> element if (total === 0) exportDoc(); }

Aquí el svgDoc se llama svg ,
y la función exportDoc() podría escribirse simplemente como:

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

Pero una vez más, primero deberá agregar su svg al documento (ya sea a través de xhr o en un elemento <iframe> o <object> , y deberá asegurarse de que todos sus recursos cumplan con CORS (o del mismo dominio ) para obtener estos renderizados.

var svg = document.querySelector(''svg''); var doSomethingWith = function(canvas) { document.body.appendChild(canvas) }; function parseImages() { var xlinkNS = "http://www.w3.org/1999/xlink"; var total, encoded; // convert an external bitmap image to a dataURL var toDataURL = function(image) { var img = new Image(); // CORS workaround, this won''t work in IE<11 // If you are sure you don''t need it, remove the next line and the double onerror handler // First try with crossorigin set, it should fire an error if not needed img.crossOrigin = ''anonymous''; img.onload = function() { // we should now be able to draw it without tainting the canvas var canvas = document.createElement(''canvas''); canvas.width = this.width; canvas.height = this.height; // draw the loaded image canvas.getContext(''2d'').drawImage(this, 0, 0); // set our <image>''s href attribute to the dataURL of our canvas image.setAttributeNS(xlinkNS, ''href'', canvas.toDataURL()); // that was the last one if (++encoded === total) exportDoc(); }; // No CORS set in the response img.onerror = function() { // save the src var oldSrc = this.src; // there is an other problem this.onerror = function() { console.warn(''failed to load an image at : '', this.src); if (--total === encoded && encoded > 0) exportDoc(); }; // remove the crossorigin attribute this.removeAttribute(''crossorigin''); // retry this.src = ''''; this.src = oldSrc; }; // load our external image into our img var href = image.getAttributeNS(xlinkNS, ''href''); // really weird bug that appeared since this answer was first posted // we need to force a no-cached request for the crossOrigin be applied img.src = href + (href.indexOf(''?'') > -1 ? + ''&1'': ''?1''); }; // get an external svg doc to data String var parseFromUrl = function(url, element) { var xhr = new XMLHttpRequest(); xhr.onload = function() { if (this.status === 200) { var response = this.responseText || this.response; var dataUrl = ''data:image/svg+xml; charset=utf8, '' + encodeURIComponent(response); element.setAttributeNS(xlinkNS, ''href'', dataUrl); if (++encoded === total) exportDoc(); } // request failed with xhr, try as an <img> else { toDataURL(element); } }; xhr.onerror = function() { toDataURL(element); }; xhr.open(''GET'', url); xhr.send(); }; var images = svg.querySelectorAll(''image''); total = images.length; encoded = 0; // loop through all our <images> elements for (var i = 0; i < images.length; i++) { var href = images[i].getAttributeNS(xlinkNS, ''href''); // check if the image is external if (href.indexOf(''data:image'') < 0) { // if it points to another svg element if (href.indexOf(''.svg'') > 0) { parseFromUrl(href, images[i]); } else // a pixel image toDataURL(images[i]); } // else increment our counter else if (++encoded === total) exportDoc(); } // if there were no <image> element if (total === 0) exportDoc(); } 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; }; window.onload = parseImages;

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

<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg" version="1.1"> <defs> <pattern id="Pattern" x="0" y="0" width=".25" height=".25"> <image xlink:href="https://dl.dropboxusercontent.com/s/1alt1303g9zpemd/UFBxY.png" width="100" height="100"/> </pattern> </defs> <rect fill="url(#Pattern)" x="0" y="0" width="200" height="200"/> </svg>