Server Side d3 - Encoding SVG as a Base64 Image
我正在尝试将d3图表编码为base64图像,以便在HTML电子邮件中使用。
到目前为止,我有:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | var express = require('express'); var app = express(); var jsdom = require('jsdom'); app.get('/chart', function (request, response) { try { jsdom.env( "<html><body><svg id="svg"></svg></body></html>", ['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); }); |
这将输出SVG HTML,这很有用,但我也希望有第二个响应字段
1 | "encoded":"data:image/png;base64,iVBORw0KGgoAAAANSUhEU...etc" |
如何编码这个SVG?如果可能的话,我希望避免任何文件写入,直接从SVG到编码图像。另外,我知道你可以在电子邮件中使用SVG,但我更希望它是一种编码的图像格式。谢谢!
将根
1 | data:[<media type>][;base64],<data> |
因为我们知道
1 | let data ="data:image/svg+xml;base64,"; |
然后得到
1 2 | // optionally preceded by `XML` declaration `<?xml version="1.0" standalone="yes"?>` let svgString = svg[0][0].outerHTML; |
调用
The
btoa(data ) method must throw an"InvalidCharacterError"
DOMException if data contains any character whose code point is
greater than U+00FF. Otherwise, the user agent must convert data to
a sequence of octets whose nth octet is the eight-bit representation
of the code point of the n th character of data, and then must
apply the base64 algorithm to that sequence of octets, and return the
result. [RFC4648]
1 2 3 4 5 6 7 8 | let base64 = window.btoa(svgString); // concatenate `data` and `base64` let dataURI = data + base64; response.send({ "html": window.d3.select("body").html(), "encoded": dataURI }); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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; |
1 2 3 | <script src="https://d3js.org/d3.v3.min.js"> <svg></svg> <iframe></iframe> |
完整的解决方案,它使用nodejs构建一个d3图表,并将其转换为编码的png,而不使用文件存储(对于大多数云主机来说是必要的)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | 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( "<svg id="svg"></svg>", ['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("<?xml version="1.0" encoding="UTF-8" standalone="yes"?>" + 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); }); |
回复中的
1 | <img src="{encoded-value}"/> |
例如
1 | <img src="data:image/png;base64,iVBORw0KGgoAAA..."/> |
为了将其作为PNG图像发送,首先必须对SVG进行栅格化,这是实际问题。有好几个地方已经回答了这个问题,但这个问题包含了许多好的解决方案。您可能应该使用ImageMagick进行转换。由于您希望避免写入中间文件,该答案建议您可以将SVG内容通过管道传输到转换器的stdin。
接收的缓冲区可能直接编码为base64。