Skip to content

Instantly share code, notes, and snippets.

@t8g
Last active January 1, 2016 19:59
Show Gist options
  • Save t8g/8194467 to your computer and use it in GitHub Desktop.
Save t8g/8194467 to your computer and use it in GitHub Desktop.
Print to pdf with header (lmtm)
#!/usr/bin/env node
// INSTALLATION :
// install phantomjs && node
// > (sudo) npm install -g marked
// > (sudo) npm install -g tmp
// Copy this script in a bin directory (/usr/local/bin) as "md2pdf"
// > (sudo) chmod a+x /usr/local/bin/md2pdf
// USAGE :
// > pl file.md [file.pdf]
try {
phantom.version;
} catch(err) {
var phantom = false;
}
if (phantom) {
var page = require('webpage').create();
var system = require('system');
var fs = require('fs');
if (system.args.length !== 3) phantom.exit(1);
var address = system.args[1];
var output = system.args[2];
var options = {
header: '<p style="color:#888;font-size:8pt;font-family:Georgia, Times, serif;text-align:right;padding-top:.5cm;padding-right:1cm;">'
+ '<img style="position:absolute;top:.5cm;left:.5cm;" src="data:image/png;base64,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" />'
+ '%pagenum% sur %numpages%</p>',
footer: '<p style="color:#888;font-size:8pt;font-family:Georgia, Times, serif;text-align:center;padding-top:1cm;"><strong>LMTM</strong> - 2 quai André Rhuys 44200 Nantes, France - Tél: +33.6 14 66 76 41 - [email protected]</p>'
}
page.open(address, function (status) {
if (status !== 'success') {
console.log('Unable to load the address');
phantom.exit();
return;
}
page.viewportSize = { width: 1600, height: 1200 };
page.clipRect = { top:0, left:0, width:1600, height:1200 };
page.paperSize = {
format: 'A4',
orientation: 'portrait',
margin: options.margin || '0cm',
header: {
height: '3cm',
contents: phantom.callback(function(pageNum, numPages) {
return options.header.replace('%pagenum%', pageNum).replace('%numpages%', numPages);
})
},
footer: {
height: '2cm',
contents: phantom.callback(function(pageNum, numPages) {
return options.footer.replace('%pagenum%', pageNum).replace('%numpages%', numPages);
})
}
};
setTimeout(function () {
page.render(output);
page.close()
phantom.exit(0)
}, 10);
});
} else {
var fs = require('fs');
var childProcess = require('child_process');
var path = require('path');
var marked = require('marked');
var tmp = require('tmp');
tmp.setGracefulCleanup(); // cleanup tmp files on exceptions
var from = process.argv[2];
var to = process.argv[3] || (path.basename(process.argv[2], path.extname(process.argv[2])) + '.pdf');
fs.readFile(from, 'utf8', function (err, data) {
if (err) throw err;
var html = '<!DOCTYPE html><head><meta charset="utf-8">'
+ '<style>html{font-size:100%;overflow-y:scroll;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{color:#000;font-family:Georgia,Palatino,"Palatino Linotype",Times,"Times New Roman",serif;font-size:12px;line-height:1.5em;padding:1em;margin:auto;max-width:42em;background:#fefefe}a{color:#222;text-decoration:none}p{margin:1em 0;text-align:justify}img{max-width:100%}h1,h2,h3,h4,h5,h6{font-weight:400;color:#555;line-height:1em}h4,h5,h6{font-weight:700}h1{font-size:2.5em;margin-bottom:2em}h2{font-size:2em}h3{font-size:1.5em}h4{font-size:1.2em}h5{font-size:1em}h6{font-size:.9em}blockquote{color:#555;margin:0;padding-left:3em;border-left:.1pt #EEE solid}hr{display:block;height:2px;border:0;border-top:1px solid #aaa;border-bottom:1px solid #eee;margin:1em 0;padding:0}code,kbd,pre,samp{color:#000;font-family:monospace,monospace;_font-family:"courier new",monospace;font-size:.98em}pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word}b,strong{font-weight:700}dfn{font-style:italic}ins{background:#ff9;color:#000;text-decoration:none}mark{background:#ff0;color:#000;font-style:italic;font-weight:700}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}ol,ul{margin:1em 0;padding:0 0 0 2em}li p:last-child{margin:0}dd{margin:0 0 0 2em}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle}table{border-collapse:collapse;border-spacing:0;width:90%}td{vertical-align:top;border:1pt solid #888;padding:5px}@media only screen and (min-width:480px){body{font-size:14px}}@media only screen and (min-width:768px){body{font-size:16px}}@media print{*{background:transparent!important;filter:none!important;-ms-filter:none!important}body{font-size:9pt;max-width:100%;margin:0 5%}a,a:visited{text-decoration:underline}hr{height:1px;border:0;border-bottom:1px solid #000}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript: "]:after,a[href^="#"]:after{content:""}blockquote,pre{border:0;padding-right:1em;page-break-inside:avoid}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}li,p,table,ul{page-break-inside:avoid}}</style>'
+ '</head><body>'
+ '<img style="display:none;" src="data:image/png;base64,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" />'
+ marked(data)
+ '</body></html>';
tmp.file({
postfix: '.html'
}, function _tempFileCreated(err, path, fd) {
if (err) throw err;
fs.close(fd);
fs.writeFile(path, html, function (err) {
if (err) throw err;
childProcess.execFile('phantomjs', [
__filename,
path,
to
], function(err, stdout, stderr) {
if (err) throw err;
if (stdout) console.log(stdout);
if (stderr) console.error(stderr);
});
})
});
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment