Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SVG to PNG Server side - using node.js

Tags:

I'm trying to follow this tutorial on converting a d3.js SVG Vis to a PNG server-side (using Node.js) http://eng.wealthfront.com/2011/12/converting-dynamic-svg-to-png-with.html

Link to full code: https://gist.github.com/1509145

However, I keep getting this error whenever I attempt to make a request to load my page

    /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. 

Does anybody know why this might be? I've installed the jsdom module fine, so I don't really know what's causing these issues...thanks in advance.

EDIT

This is the code I'm using to implement the node.js server. My latest issue is below this source...

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'); 

Latest Issue

    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) 
like image 688
Apollo Avatar asked Jul 24 '12 14:07

Apollo


People also ask

How do I convert a SVG File to PNG?

Navigate to an . svg file, right click on it and click on the context menu item 'Save SVG as PNG. Lets you click on the extension icon or right click on an . svg file and choose Save SVG as PNG.

CAN node run client side?

Being able to run a node module on the browser is extremely beneficial. Users can use already existing modules on the client side JavaScript application without having to use a server.

Is node JS good for image processing?

Node. js has an ecosystem of libraries you can use to process images, such as sharp, jimp, and gm module.


1 Answers

This may prove to be a useful answer to your question if you take out that "using node.js" stipulation. If it doesn't help you, maybe later visitors will find it interesting.

I've been working for some time to solve this same problem (server-side d3 rasterizing), and I've found PhantomJS to be the best solution.

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 should look something like:

<!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> 

You can then start the server with phantomjs server.js and POST d3=[d3 code that renders to #Viewport], and the server will respond with a base64-encoded png.

(Requires PhantomJS 1.7 or higher.)

like image 141
Trevor Dixon Avatar answered Sep 30 '22 18:09

Trevor Dixon