2017-04-08 95 views
0

我想一個D3圖表編碼爲在HTML電子郵件服務器端D3 - SVG編碼爲Base64編碼的圖像

使用一個base64形象到目前爲止,我有:

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這是有用的,但是我也想第二個響應字段encoded它應該包含這樣象下面這樣我可以在我的HTML電子郵件使用:

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

如何編碼這個SVG?如果可能,我想避免任何文件寫入,並從SVG直接進入編碼圖像。另外,我知道你可以在電子郵件中使用SVG,但我更願意使用編碼的圖像格式。謝謝!

回答

3

使用的NodeJS它建立一個D3圖表並將其轉換爲編碼的PNG不使用文件存儲(neccessary對於大多數雲託管)

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); 
}); 
全部溶液

encoded字段在respo NSE可以在HTML電子郵件使用可用於:

<img src="{encoded-value}"/> 

e.g

<img src="data:image/png;base64,iVBORw0KGgoAAA..."/> 
1

爲了將它作爲PNG圖像發送,您首先必須柵格化svg,這是實際的問題。這已經在幾個地方得到了解答,但this one包含了一些很好的解決方案。您應該可以使用imagemagick進行轉換。既然你想避免寫入一箇中間文件,那麼這個答案建議你可以將svg的內容傳遞給轉換器的stdin。

接收到的緩衝區可能可能是directly encoded to base64

+0

謝謝,這會使事情變得不同,如果我允許寫入文件系統? – Edd

+0

在這種情況下,您不會將svg傳輸到轉換器,而是將svg保存到文件中,然後將文件名傳遞給轉換器。所以,不太不同。查看imagemagick文檔以獲取一些提示。 – RecencyEffect

6

設定爲根<svg>節點在<svg>節點"xmlns"屬性"http://www.w3.org/2000/svg"document.attr()

data URI方案包括

data:[<media type>][;base64],<data> 

既然我們知道,<media type>image/svg+xml和我們想要得到的數據的base64表示,我們可以定義到我們將串聯的<svg>base64表示的變量。

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

然後我們得到.outerHTML<svg>的元素

// optionally preceded by `XML` declaration `<?xml version="1.0" standalone="yes"?>` 
let svgString = svg[0][0].outerHTML; 

呼叫btoa()svgString作爲參數

btoa(data)方法必須拋出一個 「InvalidCharacterErrorDOMException如果數據包含代碼點爲 大於U + 00FF的任何字符。否則,用戶代理必須轉換數據 八位位組,其第n個八位字節的一個序列是數據Ñ個字符的碼點的八位表示 ,然後必須 應用BASE64算法到該八位字節序列,並返回 結果。[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;
<script src="https://d3js.org/d3.v3.min.js"></script> 
 
<svg></svg> 
 
<iframe></iframe>

+0

非常感謝,我不認爲我可以在HTML電子郵件中使用腳本標記,但不幸的是。在img上使用iframe有什麼好處? – Edd

+0

@ Ed0906'