summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortomsmeding <tom.smeding@gmail.com>2017-11-16 00:33:41 +0100
committertomsmeding <tom.smeding@gmail.com>2017-11-16 00:33:47 +0100
commitdbd9786a07e9c10cfe07db58f660fa186243b9a3 (patch)
treeb5e231bd999cbdde1432027561bfa59efe506f63
parent4ef74766662a8b57124cdc4b7a9fdafd686f0de2 (diff)
Add pdfrotate module
-rw-r--r--modules/pdfrotate/editor.html17
-rw-r--r--modules/pdfrotate/index.html65
-rw-r--r--modules/pdfrotate/pdfrotate.js106
-rw-r--r--package-lock.json196
-rw-r--r--package.json2
5 files changed, 386 insertions, 0 deletions
diff --git a/modules/pdfrotate/editor.html b/modules/pdfrotate/editor.html
new file mode 100644
index 0000000..6be03a8
--- /dev/null
+++ b/modules/pdfrotate/editor.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>PDF rotate</title>
+<script>
+var sessionid=(function(){
+ var spl=location.href.split("/");
+ return spl[spl.length-1];
+})();
+</script>
+</head>
+<body>
+Editor...
+</body>
+<script>alert(sessionid);</script>
+</html>
diff --git a/modules/pdfrotate/index.html b/modules/pdfrotate/index.html
new file mode 100644
index 0000000..ae63865
--- /dev/null
+++ b/modules/pdfrotate/index.html
@@ -0,0 +1,65 @@
+<!doctype html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>PDF rotate</title>
+<script>
+window.addEventListener("load",function(){
+ var errc=location.href.split("?err=")[1];
+ if(errc){
+ if(errc=="nopdf")alert("That doesn't seem to be a PDF document.");
+ else if(errc=="rot0")alert("Haha your document was already upright. Maybe just use that instead?");
+ else if(errc=="invrot")alert("Don't bug my form, that rotation was invalid!");
+ else if(errc=="pdfjamerr")alert("An error occurred trying to convert that document. Maybe it isn't a PDF document?");
+ else alert("Unknown error occurred ('"+errc+"')");
+ }
+});
+</script>
+<style>
+.pagediagram {
+ display: inline-block;
+ border: 1px black solid;
+ width: 40px;
+ height: 56px;
+ font-family: sans-serif;
+ font-size: 40px;
+ text-align: center;
+ margin-left: 9px;
+ margin-right: 9px;
+ line-height: 62px;
+}
+</style>
+</head>
+<body>
+<h1>PDF rotate</h1>
+<p>Select a PDF file below.</p>
+<form method="POST" action="/pdfrotate/upload" enctype="multipart/form-data">
+ <input type="file" id="file" name="file" required><br>
+ <p>Click the button that looks most like the document you have. We will turn it upright.</p>
+ <table><tbody><tr>
+ <!-- CSS and pdfjam rotation are conveniently each other's inverses. -->
+ <td style="text-align: center;">
+ <label for="rot0"><div class="pagediagram" style="transform:rotate(0deg);">A</div></label><br>
+ <input type="radio" id="rot0" name="rotgroup" value="rot0" required>
+ </td>
+ <td style="text-align: center;">
+ <label for="rot90"><div class="pagediagram" style="transform:rotate(90deg);">A</div></label><br>
+ <input type="radio" id="rot90" name="rotgroup" value="rot90" required>
+ </td>
+ <td style="text-align: center;">
+ <label for="rot180"><div class="pagediagram" style="transform:rotate(180deg);">A</div></label><br>
+ <input type="radio" id="rot180" name="rotgroup" value="rot180" required>
+ </td>
+ <td style="text-align: center;">
+ <label for="rot270"><div class="pagediagram" style="transform:rotate(270deg);">A</div></label><br>
+ <input type="radio" id="rot270" name="rotgroup" value="rot270" required>
+ </td>
+ </tr></tbody></table>
+ <p>Now click the button below to finish the process!</p>
+ <input type="submit" value="Upload, turn and download result!">
+</form>
+<br>
+<br>
+<i><small>This uses <a href="https://warwick.ac.uk/fac/sci/statistics/staff/academic-research/firth/software/pdfjam/">pdfjam</a> to perform the actual hard work. Credits to me only for the slick rotated A's above.</small></i>
+</body>
+</html>
diff --git a/modules/pdfrotate/pdfrotate.js b/modules/pdfrotate/pdfrotate.js
new file mode 100644
index 0000000..a41241d
--- /dev/null
+++ b/modules/pdfrotate/pdfrotate.js
@@ -0,0 +1,106 @@
+var cmn=require("../$common.js"),
+ fs=require("fs"),
+ child_process=require("child_process"),
+ multer=require("multer"),
+ mkdirp=require("mkdirp");
+
+var moddir;
+
+var uniqid=(function(){
+ var id=0;
+ return function uniqid(){return id++;};
+})();
+
+function clearDirectory(path){
+ var entries=fs.readdirSync(path);
+ for(var i=0;i<entries.length;i++){
+ fs.unlinkSync(path+"/"+entries[i]);
+ }
+}
+
+function cleanUpDir(path){
+ var nowtime=new Date().getTime();
+ var entries=fs.readdirSync(path);
+ for(var i=0;i<entries.length;i++){
+ var stat=fs.statSync(path+"/"+entries[i]);
+ if(stat.mtime-nowtime>30*60*1000){
+ fs.unlink(path+"/"+entries[i],function(err){});
+ }
+ }
+}
+
+// Clear files older than 30 mins every 30 mins
+setInterval(function(){
+ process.nextTick(cleanUpDir(moddir+"/uploads"));
+ process.nextTick(cleanUpDir(moddir+"/converted"));
+},30*60*1000);
+
+module.exports=function(app,io,_moddir){
+ moddir=_moddir;
+
+ mkdirp.sync(moddir+"/uploads");
+ mkdirp.sync(moddir+"/converted");
+ clearDirectory(moddir+"/uploads");
+
+ var multerupload=multer({
+ storage: multer.diskStorage({
+ destination: function(req,file,cb){
+ cb(null,moddir+"/uploads/");
+ },
+ filename: function(req,file,cb){
+ cb(null,uniqid()+".pdf");
+ }
+ }),
+ limits: {
+ files: 1,
+ fileSize: 100*1024*1024
+ }
+ });
+
+ app.get("/pdfrotate",function(req,res){
+ res.sendFile(moddir+"/index.html");
+ });
+ app.post("/pdfrotate/upload",multerupload.single("file"),function(req,res){
+ if(!req.file){
+ res.sendFile(moddir+"/index.html");
+ return;
+ }
+ var origname=req.file.originalname;
+ var path=req.file.path;
+ var rot=req.body.rotgroup+"";
+ if(rot=="rot0"){
+ fs.unlink(path,function(err){});
+ res.redirect("/pdfrotate?err=rot0");
+ return;
+ }
+
+ var cmd;
+ switch(rot){
+ case "rot90": cmd="pdf90"; break;
+ case "rot180": cmd="pdf180"; break;
+ case "rot270": cmd="pdf270"; break;
+ default:
+ fs.unlink(path,function(err){});
+ res.redirect("/pdfrotate?err=invrot");
+ return;
+ }
+
+ var outfile=moddir+"/converted/"+uniqid()+".pdf";
+
+ child_process.execFile(cmd,[path,"-o",outfile],function(err,stdout,stderr){
+ if(err){
+ console.log(err);
+ res.redirect("/pdfrotate?err=pdfjamerr");
+ return;
+ }
+ var newname=origname.replace(/\.pdf$/,"_rotated.pdf");
+ res.download(outfile,newname,function(err){
+ fs.unlink(path,function(err){});
+ fs.unlink(outfile,function(err){});
+ });
+ });
+ });
+ app.get("/pdfrotate/upload",function(req,res){
+ res.redirect("/pdfrotate");
+ });
+};
diff --git a/package-lock.json b/package-lock.json
index 3b7a4ec..6efa6ab 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4,6 +4,11 @@
"lockfileVersion": 1,
"requires": true,
"dependencies": {
+ "append-field": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/append-field/-/append-field-0.1.0.tgz",
+ "integrity": "sha1-bdxY+gg8e8VF08WZWygwzCNm1Eo="
+ },
"basic-auth": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz",
@@ -168,6 +173,73 @@
}
}
},
+ "busboy": {
+ "version": "0.2.14",
+ "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz",
+ "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=",
+ "requires": {
+ "dicer": "0.2.5",
+ "readable-stream": "1.1.14"
+ }
+ },
+ "concat-stream": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz",
+ "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=",
+ "requires": {
+ "inherits": "2.0.3",
+ "readable-stream": "2.3.3",
+ "typedarray": "0.0.6"
+ },
+ "dependencies": {
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+ },
+ "readable-stream": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
+ "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
+ "requires": {
+ "core-util-is": "1.0.2",
+ "inherits": "2.0.3",
+ "isarray": "1.0.0",
+ "process-nextick-args": "1.0.7",
+ "safe-buffer": "5.1.1",
+ "string_decoder": "1.0.3",
+ "util-deprecate": "1.0.2"
+ }
+ },
+ "string_decoder": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
+ "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
+ "requires": {
+ "safe-buffer": "5.1.1"
+ }
+ }
+ }
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+ },
+ "dicer": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz",
+ "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=",
+ "requires": {
+ "readable-stream": "1.1.14",
+ "streamsearch": "0.1.2"
+ }
+ },
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+ },
"express": {
"version": "4.15.4",
"resolved": "https://registry.npmjs.org/express/-/express-4.15.4.tgz",
@@ -472,6 +544,11 @@
"resolved": "https://registry.npmjs.org/express-subdomain/-/express-subdomain-1.0.5.tgz",
"integrity": "sha1-mQ75eUC39MKCPZWTZIt5voWKY4s="
},
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ },
"is-absolute": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.2.6.tgz",
@@ -502,6 +579,57 @@
"resolved": "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz",
"integrity": "sha1-3hqm1j6indJIc3tp8f+LgALSEIw="
},
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+ },
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+ },
+ "mime-db": {
+ "version": "1.30.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz",
+ "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE="
+ },
+ "mime-types": {
+ "version": "2.1.17",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz",
+ "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=",
+ "requires": {
+ "mime-db": "1.30.0"
+ }
+ },
+ "minimist": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "requires": {
+ "minimist": "0.0.8"
+ }
+ },
+ "multer": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/multer/-/multer-1.3.0.tgz",
+ "integrity": "sha1-CSsmcPaEb6SRSWXvyM+Uwg/sbNI=",
+ "requires": {
+ "append-field": "0.1.0",
+ "busboy": "0.2.14",
+ "concat-stream": "1.6.0",
+ "mkdirp": "0.5.1",
+ "object-assign": "3.0.0",
+ "on-finished": "2.3.0",
+ "type-is": "1.6.15",
+ "xtend": "4.0.1"
+ }
+ },
"naampje": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/naampje/-/naampje-1.0.1.tgz",
@@ -537,6 +665,40 @@
}
}
},
+ "object-assign": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz",
+ "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I="
+ },
+ "on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ },
+ "process-nextick-args": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
+ "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
+ },
+ "readable-stream": {
+ "version": "1.1.14",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
+ "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
+ "requires": {
+ "core-util-is": "1.0.2",
+ "inherits": "2.0.3",
+ "isarray": "0.0.1",
+ "string_decoder": "0.10.31"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
+ "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
+ },
"socket.io": {
"version": "1.7.4",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.7.4.tgz",
@@ -878,10 +1040,44 @@
}
}
},
+ "streamsearch": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
+ "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
+ },
+ "string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+ },
+ "type-is": {
+ "version": "1.6.15",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz",
+ "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=",
+ "requires": {
+ "media-typer": "0.3.0",
+ "mime-types": "2.1.17"
+ }
+ },
+ "typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
+ },
"unc-path-regex": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
"integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo="
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+ },
+ "xtend": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+ "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
}
}
}
diff --git a/package.json b/package.json
index 2b8d5f5..2518305 100644
--- a/package.json
+++ b/package.json
@@ -9,6 +9,8 @@
"body-parser": "^1.15.2",
"express": "^4.14.0",
"express-subdomain": "^1.0.5",
+ "mkdirp": "^0.5.1",
+ "multer": "^1.3.0",
"naampje": "^1.0.1",
"node-persist": "^2.0.2",
"socket.io": "^1.4.8"