SVG转PNG服务器端 - 使用Node.js

25
我试图按照这个教程将一个d3.js的SVG可视化图表转换成PNG格式并在服务器端(使用Node.js)进行操作。 http://eng.wealthfront.com/2011/12/converting-dynamic-svg-to-png-with.html 完整代码链接: https://gist.github.com/1509145 但是,每当我尝试请求加载我的页面时,就会收到这个错误信息。
    /Users/me/Node/node_modules/jsdom/lib/jsdom.js:171
        features   = JSON.parse(JSON.stringify(window.document.implementation._fea
                                                              ^
    TypeError: Cannot read property 'implementation' of undefined
        at exports.env.exports.jsdom.env.processHTML (/Users/dereklo/Node/node_modules/jsdom/lib/jsdom.js:171:59)
        at Object.exports.env.exports.jsdom.env (/Users/dereklo/Node/node_modules/jsdom/lib/jsdom.js:262:5)
        at Server.<anonymous> (/Users/dereklo/Node/Pie/pie_serv.js:26:9)
        at Server.EventEmitter.emit (events.js:91:17)
        at HTTPParser.parser.onIncoming (http.js:1785:12)
        at HTTPParser.parserOnHeadersComplete [as onHeadersComplete] (http.js:111:23)
        at Socket.socket.ondata (http.

有人知道这可能是为什么吗?我已经成功安装了jsdom模块,所以我不知道是什么原因导致这些问题...提前感谢。

编辑

这是我用来实现node.js服务器的代码。我的最新问题在此源代码下方...

var http = require('http'),
    url = require('url'),
    jsdom = require('jsdom'),
    child_proc = require('child_process'),
    w = 400,
    h = 400,
    __dirname = "Users/dereklo/Node/pie/"

   scripts = ["/Users/dereklo/Node/pie/d3.min.js",
               "/Users/dereklo/Node/pie/d3.layout.min.js",
               "/Users/dereklo/Node/pie/pie.js"],
      //scripts = ["./d3.v2.js",
        //         "./d3.layout.min.js",
          //       "./pie.js"]

    htmlStub = '<!DOCTYPE html><div id="pie" style="width:'+w+'px;height:'+h+'px;"></div>';

http.createServer(function (req, res) {

  res.writeHead(200, {'Content-Type': 'image/png'});
  var convert = child_proc.spawn("convert", ["svg:", "png:-"]),
      values = (url.parse(req.url, true).query['values'] || ".5,.5")
        .split(",")
        .map(function(v){return parseFloat(v)});

  convert.stdout.on('data', function (data) {
    res.write(data);
  });
  convert.on('exit', function(code) {
    res.end();
  });

  jsdom.env({features:{QuerySelector:true}, html:htmlStub, scripts:scripts, done:function(errors, window) {
    var svgsrc = window.insertPie("#pie", w, h, values).innerHTML;

  console.log("svgsrc",svgsrc);

    //jsdom's domToHTML will lowercase element names
    svgsrc = svgsrc.replace(/radialgradient/g,'radialGradient');
    convert.stdin.write(svgsrc);
    convert.stdin.end();
  }});
}).listen(8888, "127.0.0.1");

console.log('Pie SVG server running at http://127.0.0.1:8888/');
console.log('ex. http://127.0.0.1:8888/?values=.4,.3,.2,.1');

最新问题

    events.js:66
        throw arguments[1]; // Unhandled 'error' event
                       ^
Error: This socket is closed.
    at Socket._write (net.js:519:19)
    at Socket.write (net.js:511:15)
    at http.createServer.jsdom.env.done (/Users/dereklo/Node/Pie/pie_serv.js:38:19)
    at exports.env.exports.jsdom.env.scriptComplete (/Users/dereklo/Node/node_modules/jsdom/lib/jsdom.js:199:39)

也许你可以给我们展示一些代码? :-) - Florian Margaine
1
我只是简单地复制粘贴了教程中的代码... - Apollo
@FlorianMargaine,我添加了教程要点的链接。你愿意试一试吗,Florian? - Apollo
1
这似乎与JSDOM有关,你在Google上搜索过这个错误吗?我在这里看到一个已经开放的bug:https://github.com/tmpvar/jsdom/issues/436 - Matt Baker
@MattBaker 点击了你的链接,我遇到了一个 contextify 的问题(没有安装它)。我已经有所进展,但最新的问题是:events.js:66 throw arguments[1]; // 未处理的 'error' 事件。 - Apollo
1个回答

50
这可能是一个有用的答案,如果你把 "使用node.js" 的限制去掉的话。如果它对你没有帮助,也许后来的访问者会觉得它很有趣。
我已经花了一些时间来解决同样的问题(服务器端的d3光栅化),我发现PhantomJS是最好的解决方案。

server.js:

var page = require('webpage').create(),
    renderElement = require('./renderElement.js'),
    Routes = require('./Routes.js'),
    app = new Routes();

page.viewportSize = {width: 1000, height: 1000};
page.open('./d3shell.html');

app.post('/', function(req, res) {
    page.evaluate(new Function(req.post.d3));
    var pic = renderElement(page, '#Viewport');
    res.send(pic);
});

app.listen(8000);

console.log('Listening on port 8000.');

Routes.js: https://gist.github.com/3061477
renderElement.js: https://gist.github.com/3176500

d3shell.html应该长这样:

<!DOCTYPE HTML>
<html>
<head>
    <title>Shell</title>
</head>
<body>
    <div id="Viewport" style="display: inline-block"></div>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/d3/2.8.1/d3.v2.min.js" type="text/javascript"></script>
</body>
</html>

你可以使用phantomjs server.js启动服务器,并POST d3=[d3代码,渲染到#Viewport],服务器将响应一个base64编码的png。(需要PhantomJS 1.7或更高版本。)

无法使用 Phantom,因为它是 BSD-2 许可证,但这篇文章看起来很棒,你花了很多时间写。我希望它能帮助到其他人...... - Apollo
2
你能否提供一个完整的可工作示例?我不确定应该如何或者应该“发布”什么。 - reubano
我也想使用这个示例,但是像@reubano一样,我不知道如何按照您所提到的方式发布。我是phantomJS的新手。谢谢。 - zed
我能够在这个 github 项目 中拼凑出一些东西。它涉及到了更多的内容,因为它会排队所有的图像请求,并且旨在用于 heroku,这意味着您必须将生成的图像上传到 s3。相关文件是 server.coffeegraph-view.coffee - reubano
@Trevor Dixon,你可以详细说明一下如何(以及什么方式)发布吗? - Tobi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接