pdf-officegen
Version:
Converts one or more PDFs into a powerpoint or word document with one pdf page per slide/page
119 lines (109 loc) • 3.96 kB
JavaScript
const EventEmitter2 = require('eventemitter2').EventEmitter2
const rmdir = require('rimraf')
const fs = require('fs')
const path = require('path')
const Engine = require('./engine')
const {info} = require('./logger')
const {nowInMillis, elapsed, getStagingDirectory} = require('./util')
class OfficeDoc extends EventEmitter2 {
/**
* @param {String} options.extension 'pptx', 'docx'
*
* @param {String} [options.engine=ghostscript] options: mupdf, inkscape, ghostscript
*
* @param {Boolean} [options.clean=true] set to false if intermediate image
* files should be left on the filesystem.
*
* @param {String} [options.jobId] if provided this will be included in any logging output
*
* @param {Boolean} [options.cropLastImage=false] requires ImageMagick
* `convert` to be on the path. Will crop the last pdf image before
* placing on slide.
*
* @constructs
*/
constructor (options) {
super({
wildcard: true, // Allow clients to listen based on wildcard expressions
maxListeners: 10 // Node Default, set to 0 for Infinity
})
this.options = options
process.nextTick(() => {
this.emit('options', { output: JSON.stringify(this.options) })
})
}
/**
*
* @param pdfFiles {array|string} An array of PDF files that should be
* converted
*
* @param options.stagingDir - A directory where intermediate PNG images will
* be placed when converting into slides. A different folder should be
* used for each conversion. If undefined, a random directory will be
* created under the systems temp directory. It will be deleted once the
* job has completed.
*
* @param options.convertOptions - ImageMagick conversion options (minus the
* -) Currently supported: density(<300)
*
* @param done
*/
convertFromPdf (pdfFiles, options, done) {
let callback
let opts = {}
if (typeof arguments[1] === 'object') {
opts = options
callback = done
} else {
callback = arguments[1]
}
const {stagingDir, convertOptions} = opts
getStagingDirectory(stagingDir)
.then((outputDir) => {
const imgDir = path.resolve(outputDir, 'img')
const pdfDir = path.resolve(outputDir, 'pdf')
const {engine, extension, cropLastImage} = this.options
const engineOpts = {engine, cropLastImage, convertOptions, imgDir, pdfDir}
const conversionEngine = new Engine(engineOpts)
conversionEngine.onAny((name, result) => this.emit(name, result))
conversionEngine.convert(outputDir, pdfFiles).then(sortedImages => {
const filename = `output_${process.hrtime()[1]}.${extension}`
const outputFile = path.resolve(outputDir, filename)
this._aggregatePageImages(sortedImages, outputFile, imgDir, callback)
})
}, (err) => callback(err))
.catch(err => callback(err))
}
/**
*
* @param {Array} images
* @param outputFile output file path
* @param imgDir the directory where png files are generated
* @param done callback
* @private
*/
_aggregatePageImages (images, outputFile, imgDir, done) {
this.createDocument(images, outputFile, (slideErr, output) => {
done(slideErr, output)
if (this.options.clean) {
const start = nowInMillis()
rmdir(imgDir, (err) => {
if (err) {
this.emit('done.png.clean', {output: imgDir, time: elapsed(start), error: err})
info(this.options.jobId, 'Could not delete working directory:', imgDir, err)
}
})
}
})
}
saveOfficeDocument (file, done, officeGenDoc) {
const start = nowInMillis()
const out = fs.createWriteStream(file)
out.on('close', () => {
this.emit(`done.${this.options.extension}.saved`, {output: file, time: elapsed(start)})
done(null, file)
})
officeGenDoc.generate(out)
}
}
module.exports = OfficeDoc