Server Side d3 – Codificación de SVG como una imagen Base64

Estoy tratando de codificar un gráfico D3 como una imagen base64 para usar en correos electrónicos HTML

Hasta ahora tengo:

var express = require('express'); var app = express(); var jsdom = require('jsdom'); app.get('/chart', function (request, response) { try { jsdom.env( "", ['http://d3js.org/d3.v3.min.js'], function (err, window) { var svg = window.d3.select("svg") .attr("width", 100) .attr("height", 100); svg.append("rect") .attr("x", 10) .attr("y", 10) .attr("width", 80) .attr("height", 80) .style("fill", "orange"); var encoded = ...; // How do I now encode this? response.send({ "html": window.d3.select("body").html(), "encoded": encoded }); } ); } catch (err) { console.error(err); } }); // Run Server var port = process.env.PORT || 8305; var server = app.listen(port, function () { var host = server.address().address; console.log('App listening at http://%s:%s', host, port); }); 

Esto genera el html SVG que es útil, sin embargo, también me gustaría un segundo campo de respuesta encoded que debería contener algo como lo siguiente que puedo usar en mi correo electrónico HTML:

 "encoded": "data:image/png;base64,iVBORw0KGgoAAAANSUhEU...etc" 

¿Cómo puedo codificar este SVG? Me gustaría evitar la escritura de archivos si es posible y pasar directamente de SVG a la imagen codificada. Además, soy consciente de que puede usar SVG en correos electrónicos, pero preferiría que fuera en un formato de imagen codificada. ¡Gracias!

Establezca el atributo "xmlns" en el nodo raíz en "http://www.w3.org/2000/svg" en el nodo dentro del document o con .attr() .

El esquema de data URI consiste en

 data:[][;base64], 

Como sabemos que será image/svg+xml y que queremos una representación base64 de los datos resultantes, podemos definir una variable a la que concatenaremos la representación base64 de .

 let data = "data:image/svg+xml;base64,"; 

Luego obtenemos el elemento .outerHTML de

 // optionally preceded by `XML` declaration `` let svgString = svg[0][0].outerHTML; 

Llame a btoa() con svgString como parámetro

El btoa(data ) debe lanzar una excepción de DOM ” InvalidCharacterError ” si los datos contienen cualquier carácter cuyo punto de código sea mayor que U + 00FF. De lo contrario, el agente de usuario debe convertir los datos en una secuencia de octetos cuyo octeto n es la representación de ocho bits del punto de código del carácter n de datos , y luego debe aplicar el algoritmo base64 a esa secuencia de octetos y devolver el resultado. [RFC4648]

 let base64 = window.btoa(svgString); // concatenate `data` and `base64` let dataURI = data + base64; response.send({ "html": window.d3.select("body").html(), "encoded": dataURI }); 
 let svg = window.d3.select("svg") .attr("xmlns", "http://www.w3.org/2000/svg") .attr("width", 100) .attr("height", 100); svg.append("rect") .attr("x", 10) .attr("y", 10) .attr("width", 80) .attr("height", 80) .style("fill", "orange"); let data = "data:image/svg+xml;base64,"; let svgString = svg[0][0].outerHTML; let base64 = window.btoa(svgString); let dataURI = data + base64; console.log(dataURI); document.querySelector("iframe").src = dataURI; 
    

Solución completa que crea un gráfico d3 con NodeJS y lo convierte en un PNG codificado sin usar el almacenamiento de archivos (necesario para la mayoría de los servidores de nube)

 let express = require('express'); let app = express(); let jsdom = require('jsdom'); let Buffer = require('buffer').Buffer; let svg2png = require('svg2png'); app.post('/chart', function (request, response) { try { jsdom.env( "", ['http://d3js.org/d3.v3.min.js'], function (err, window) { let svg = window.d3.select("svg") .attr("width", 100) .attr("height", 100) .attr("xmlns", "http://www.w3.org/2000/svg"); svg.append("rect") .attr("x", 10) .attr("y", 10) .attr("width", 80) .attr("height", 80) .style("fill", "orange"); let data = "data:image/png;base64,"; let svgString = svg[0][0].outerHTML; let buffer = new Buffer("" + svgString); let promise = svg2png(buffer, {width: 300, height: 400}); // This options block is optional but height and width should be specified on the SVG HTML otherwise promise.then(buffer => { let dataURI = data + buffer.toString('base64'); response.set('Content-Type', 'application/json'); response.send({ "html": svgString, "encoded": dataURI }); }); } ); } catch (err) { console.warn(err); } }); // Run Server let port = process.env.PORT || 8305; let server = app.listen(port, function () { let host = server.address().address || 'localhost'; console.log('Example app listening at http://%s:%s', host, port); }); 

El campo encoded en la respuesta se puede usar en un correo electrónico HTML usando:

  

p.ej

  

Para enviarlo como una imagen png, primero tendría que rasterizar el svg, que es el problema real. Esto se ha respondido en varios lugares, pero este contiene una serie de buenas soluciones. Probablemente deberías usar imagemgick para la conversión. Ya que desea evitar escribir en un archivo intermedio, esa respuesta sugiere que puede canalizar el contenido svg a la entrada estándar del convertidor.

El búfer recibido probablemente podría codificarse directamente a base64 .