Allow {png,gif,jpg,pdf} output.

This commit is contained in:
Thaddee Tyl 2014-01-05 11:29:58 +01:00
parent de668667d3
commit 16da2eee02
4 changed files with 79 additions and 9 deletions

View File

@ -9,9 +9,10 @@
},
"license": "CC0",
"dependencies": {
"dot": ">=1.0.2",
"dot": "~1.0.2",
"svgo": "~0.4.2",
"canvas": "~1.1.2",
"phantomjs": "~1.9.2-6",
"es6-promise": "~0.1.1",
"camp": "~13.11.9"
},

27
phantomjs-svg2png.js Normal file
View File

@ -0,0 +1,27 @@
var page = require('webpage').create();
var system = require('system');
var svg = system.args[1];
var svgUrl = 'data:image/svg+xml,' + window.encodeURI(svg);
var tmpFile = system.args[2];
page.viewportSize = getSvgDimensions(svg);
page.open(svgUrl, function(status) {
if (status !== 'success') {
console.error('Failed to load the following SVG data:');
console.error(svgUrl);
phantom.exit(1);
} else {
page.render(tmpFile);
phantom.exit();
}
});
function getSvgDimensions(svg) {
var frag = window.document.createElement('div');
frag.innerHTML = svg;
var svgRoot = frag.querySelector('svg');
return {
width: parseFloat(svgRoot.getAttribute('width') || 80),
height: parseFloat(svgRoot.getAttribute('height') || 19)
};
}

View File

@ -2,6 +2,7 @@ var camp = require('camp').start({
port: process.env.PORT||+process.argv[2]||80
});
var badge = require('./badge.js');
var svg2img = require('./svg-to-img.js');
var serverStartTime = new Date((new Date()).toGMTString());
// Escapes `t` using the format specified in
@ -18,12 +19,14 @@ function escapeFormat(t) {
function sixHex(s) { return /^[0-9a-fA-F]{6}$/.test(s); }
camp.route(/^\/(([^-]|--)+)-(([^-]|--)+)-(([^-]|--)+).svg$/,
camp.route(/^\/(([^-]|--)+)-(([^-]|--)+)-(([^-]|--)+).(svg|png|gif|jpg|pdf)$/,
function(data, match, end, ask) {
var subject = escapeFormat(match[1]);
var status = escapeFormat(match[3]);
var color = escapeFormat(match[5]);
ask.res.setHeader('Content-Type', 'image/svg+xml');
var format = match[7];
// Cache management.
var cacheDuration = (3600*24*1)|0; // 1 day.
ask.res.setHeader('Cache-Control', 'public, max-age=' + cacheDuration);
if (+(new Date(ask.req.headers['if-modified-since'])) >= +serverStartTime) {
@ -32,6 +35,8 @@ camp.route(/^\/(([^-]|--)+)-(([^-]|--)+)-(([^-]|--)+).svg$/,
return;
}
ask.res.setHeader('Last-Modified', serverStartTime.toGMTString());
// Badge creation.
try {
var badgeData = {text: [subject, status]};
if (sixHex(color)) {
@ -39,16 +44,31 @@ camp.route(/^\/(([^-]|--)+)-(([^-]|--)+)-(([^-]|--)+).svg$/,
} else {
badgeData.colorscheme = color;
}
badge(badgeData, function(res) {
end(null, {template: streamFromString(res)});
});
badge(badgeData, makeSend(format, ask.res, end));
} catch(e) {
badge({text: ["error", "bad badge"], colorscheme: "red"}, function(res) {
end(null, {template: streamFromString(res)});
});
badge({text: ["error", "bad badge"], colorscheme: "red"},
makeSend(format, ask.res, end));
}
});
function makeSend(format, askres, end) {
if (format === 'svg') {
return function(res) { sendSVG(res, askres, end); };
} else {
return function(res) { sendOther(format, res, askres, end); };
}
}
function sendSVG(res, askres, end) {
askres.setHeader('Content-Type', 'image/svg+xml');
end(null, {template: streamFromString(res)});
}
function sendOther(format, res, askres, end) {
askres.setHeader('Content-Type', 'image/' + format);
svg2img(res, format, askres);
}
var stream = require('stream');
function streamFromString(str) {
var newStream = new stream.Readable();

22
svg-to-img.js Normal file
View File

@ -0,0 +1,22 @@
var fs = require('fs');
var os = require('os');
var path = require('path');
var phantom = require('phantomjs');
var childProcess = require('child_process');
var phantomScript = path.join(__dirname, 'phantomjs-svg2png.js');
module.exports = function (svg, format, out, cb) {
var tmpFile = path.join(os.tmpdir(),
"svg2img-" + (Math.random()*2147483648|0) + "." + format);
// Conversion to PNG happens in the phantom script.
childProcess.execFile(phantom.path, [phantomScript, svg, tmpFile],
function(err, stdout, stderr) {
if (stdout) { console.log(stdout); }
if (stderr) { console.log(stderr); }
if (err != null) { console.error(err.stack); if (cb) { cb(err); } return; }
var inStream = fs.createReadStream(tmpFile);
inStream.pipe(out);
// Remove the temporary file after use.
inStream.on('end', function() { fs.unlink(tmpFile, cb); });
});
};