augmented-reality-pdf
Version:
A module to prepare PDF documents for AR. It automatically inserts a QR code and an image target of choice on each page of the document.
111 lines (100 loc) • 5.47 kB
JavaScript
const fs = require('fs');
const fsc = require("fs-cheerio");
const cheerio = require('cheerio');
const sharp = require('sharp');
const path = require('path');
const pdf = require('html-pdf');
const QRCode = require('qrcode');
const htmlToPdf = require('html-to-pdf');
const dockerCLI = require('docker-cli-js');
const wkhtmltopdf = require('wkhtmltopdf');
const cmd=require('node-cmd');
const DockerOptions = dockerCLI.Options;
const Docker = dockerCLI.Docker;
var letters = getLetterArray();
/*
Converts a PDF document to HTML format using Docker and inserts a QR code and an image target on all pages
Takes an options object as input with the following properties:
input: Relative path of input. Must have .pdf extension if useDocker is set to true. Must have .html extension if useDocker is set to false.
output: Relative path of output file. Defaults to './annotated.pdf'.
target: Relative path of Image Target
width: Width of image target/QR code in pixels
height: Height of image target/QR code in pixel
text: Text to automatically generate QR code from
qr: Relative path of QR code image if not using automatically generated QR code from text
top: Offset from top of page of image target/QR code in pixels
left: Offset from left of page of image target/QR code in pixels
pages: Number of pages in the PDF document to place target/QR code on
useImageTarget: Whether to embed an image or not. Defaults to true.
useQRCode: Whether to embed a QR code or not. Defaults to true.
useDocker: Whether to use Docker or not. If set to false, input has to be a html file. If set to true, input has to be a pdf file.
dockerOptions: Optional Docker Options, see https://www.npmjs.com/package/docker-cli-js
*/
async function insertQRAndMarker(options) {
var useDocker = options.useDocker !== undefined ? options.useDocker : false;
var result = useDocker ? await insertQRAndMarkerDocker(options) : await insertQRAndMarkerNoDocker(options);
}
async function insertQRAndMarkerDocker(options) {
const dockerOptions = options.dockerOptions || new DockerOptions();
const docker = new Docker(dockerOptions);
var input = path.parse(options.input).ext === '.pdf' ? options.input : 'sample.pdf';
var pdf_to_html = await convertToHTML(input, docker);
await insertQRAndMarkerBase(__dirname + '/' + path.parse(input).name + '.html',
options.target || 'target.jpg', options.qr || 'generated_qr.png', options.text || 'Hey', options.width || 50, options.height || 50,
options.top || 1020, options.left || 0, options.pages || 100, options.output || 'annotated.pdf',
options.useQRCode || true, options.useImageTarget || true);
}
async function insertQRAndMarkerNoDocker(options) {
var input = path.parse(options.input).ext === '.html' ? options.input : 'sample.html';
await insertQRAndMarkerBase(__dirname + '/' + input,
options.target || 'target.jpg', options.qr || 'generated_qr.png', options.text || 'Hey', options.width || 50, options.height || 50,
options.top || 1020, options.left || 0, options.pages || 100, options.output || 'annotated.pdf',
options.useQRCode || true, options.useImageTarget || true);
}
async function insertQRAndMarkerBase(input, target, qr, text, width, height, top, left, pages, output, useQRCode, useImageTarget) {
var $ = cheerio.load(fs.readFileSync(input));
var QRCODE = await QRCode.toFile('generated_qr.png', text);
var resized_target = await resizeImage(__dirname + '/' + target, __dirname + '/target_resized.png', width, height);
var resized_qr = await resizeImage(__dirname + '/' + qr, __dirname + '/qr_resized.png', width, height);
var target_html = '<img src="target_resized.png" style="z-index:1000 !important; position: absolute; left: ' + new String(left) +
'px; top: ' + new String(top-height) + 'px"/>';
var qr_html = '<img src="qr_resized.png" style="z-index:1000 !important; position: absolute; left: ' + new String(left+width) +
'px; top: ' + new String(top-height) + 'px"/>';
var augment = (useImageTarget ? target_html : '') + (useQRCode ? qr_html : '');
for (var i = 0; i < pages; i++) {
$('div[data-page-no=' + new String (i) + ']').append(augment);
}
for (var i = 0; i < letters.length; i++) {
$('div[data-page-no=' + letters[i] + ']').append(augment);
}
await fsc.writeFile(__dirname + '/annotated.html', $);
await htmlToPDF(input, output);
}
async function convertToHTML(input, docker) {
var data = await docker.command('run --rm -v ' + __dirname + '/:/pdf bwits/pdf2htmlex pdf2htmlEX --zoom 1.3 --proof 1 ' + input);
}
async function resizeImage(input, output, x, y) {
var resized = await sharp(input).resize(x, y)
.toFile(output);
}
async function htmlToPDF(input, output) {
var stream = await cmd.run('wkhtmltopdf annotated.html ' + output);
await fs.unlinkSync(input);
setTimeout(async function(){
await fs.unlinkSync(__dirname + '/target_resized.png');
await fs.unlinkSync(__dirname + '/qr_resized.png');
await fs.unlinkSync(__dirname + '/generated_qr.png');
await fs.unlinkSync(__dirname + '/annotated.html');
},30000);
return stream;
}
function getLetterArray() {
var letters=[], letter_first = 'a', letter_last = 'z';
for (var letter = letter_first.charCodeAt(0); letter<=letter_last.charCodeAt(0); letter++)
letters.push(String.fromCharCode(letter));
return letters;
}
module.exports = {
insertQRAndMarker: insertQRAndMarker,
htmlToPDF: htmlToPDF
}