Я использую функции Firebase, чтобы обрезать определенную область PDF и преобразовать их в изображение, используя ghostscript [Оболочка https://www.npmjs.com/package/node-gs и скомпилированную версию GS v9.2 "https://github.com/sina-masnadi/node-gs/tarball/master "]
и это код, который я использую:
const functions = require('firebase-functions');
const { Storage } = require('@google-cloud/storage');
const gcs = new Storage();
const spawn = require('child-process-promise').spawn;
const path = require('path');
const os = require('os');
const fs = require('fs');
var gs = require('gs');
const THUMB_MAX_HEIGHT = 200;
const THUMB_MAX_WIDTH = 200;
const THUMB_SUFFIX = '-thumb';
//This function triggers whenever any pdf is uploaded to the firebase storage
//and attempts to generate
exports.makePreviews = functions.storage.object().onFinalize(async (object, event) => {
//Checking for pdf files
if (!object.name.endsWith('.pdf')) return false;
const filePath = object.name;
//slicing name and path
const splitFileName = object.name.split(".");
console.log(splitFileName);
const fileID = splitFileName;
//creating temporary path strings for gcp file system
const fileName = path.basename(filePath);
const tempFilePath = path.join(os.tmpdir(), fileName);
const newName1 = path.basename(filePath, '.pdf') + '01.jpeg';
const tempNewPath1 = path.join(os.tmpdir(), newName1);
const newName2 = path.basename(filePath, '.pdf') + '02.jpeg';
const tempNewPath2 = path.join(os.tmpdir(), newName2);
const thumbName = path.basename(filePath, '.pdf') + THUMB_SUFFIX + '.jpeg';
const tempThumbPath = path.join(os.tmpdir(), thumbName);
//downloading file from firebase storage
const bucket = gcs.bucket(object.bucket);
return bucket.file(filePath).download({
destination: tempFilePath
}).then(async () => {
console.log('PDF downloaded locally to', tempFilePath);
//generating two preview JPEGS
await new Promise((resolve, reject) => {
gs()
.safer()
.batch()
.nopause()
.option('-dTextAlphaBits=4')
.option('-dGraphicsAlphaBits=4')
.option('-dDEVICEWIDTHPOINTS=238')
.option('-dDEVICEHEIGHTPOINTS=149.5')
.option('-dFIXEDMEDIA')
.res(600)
.option('-dDownScaleFactor=2')
.executablePath('gs')
.device('jpeg')
.output(tempNewPath2)
.option('-c "<</PageOffset[-308.5 40]>> setpagedevice"')
.option('-sPDFPassword=01011977')
.input(tempFilePath)
.exec((err, stdout, stderr) => {
if (!err) {
console.log('Part One Exceuted');
bucket.upload(tempNewPath1, {
destination: 'files/' + fileID + '.jpeg'
}).then(() => {
console.log('stdout', stdout);
console.log('stderr', stderr);
}).catch(err => {
console.log(err);
});
resolve();
} else {
console.log('gs error:', err);
reject(err);
}
});
});
await new Promise((resolve, reject) => {
gs()
.safer()
.batch()
.nopause()
.option('-dTextAlphaBits=4')
.option('-dGraphicsAlphaBits=4')
.option('-dDEVICEWIDTHPOINTS=238')
.option('-dDEVICEHEIGHTPOINTS=149.5')
.option('-dFIXEDMEDIA')
.res(600)
.option('-dDownScaleFactor=2')
.executablePath('gs')
.device('jpeg')
.output(tempNewPath2)
.option('-c "<</PageOffset[-308.5 40]>> setpagedevice"')
.option('-sPDFPassword=01011977')
.input(tempFilePath)
.exec((err, stdout, stderr) => {
if (!err) {
console.log('gs Part two excuted');
bucket.upload(tempNewPath1, {
destination: 'files/' + fileID + '-2.jpeg'
}).then(() => {
console.log('stdout', stdout);
console.log('stderr', stderr);
})
.catch(err => {
console.log(err);
});
resolve();
} else {
console.log('gs error:', err);
reject(err);
}
});
});
//generating thumbnail from the first JPEG
return spawn('convert', [tempNewPath1, '-thumbnail', `${THUMB_MAX_WIDTH}x${THUMB_MAX_HEIGHT}>`, tempThumbPath], {
capture: ['stdout', 'stderr']
});
}).then(async () => {
console.log('PNG created at', tempNewPath1 + 'and' + tempNewPath2);
console.log('Thumbnail created at', tempThumbPath);
//uploading the files back to firebase storage
return bucket.upload(tempThumbPath, {
destination: 'files/' + fileID + 'thumb.jpeg'
});
}).then(() => {
//once the files have been uploaded delete the local temporary
//files to free up disk space.
fs.unlinkSync(tempNewPath1);
fs.unlinkSync(tempNewPath2);
fs.unlinkSync(tempThumbPath);
return fs.unlinkSync(tempFilePath);
}).catch((err) => {
console.log('exception:', err);
return err;
});
});
развертывание вышеуказанного кода, журнал:
[ 'PAN_01011977', 'pdf' ]
PDF downloaded locally to /tmp/PAN_01011977.pdf
gs command: -dSAFER,-dBATCH,-dNOPAUSE,-dTextAlphaBits=4,-dGraphicsAlphaBits=4,-dDEVICEWIDTHPOINTS=238,-dDEVICEHEIGHTPOINTS=149.5,-dFIXEDMEDIA,-r600,-dDownScaleFactor=2,-sDEVICE=jpeg,-sOutputFile=/tmp/PAN_0101197702.jpeg,-c "<</PageOffset[-308.5 40]>> setpagedevice",-sPDFPassword=01011977,/tmp/PAN_01011977.pdf
Part One Exceuted
gs command: -dSAFER,-dBATCH,-dNOPAUSE,-dTextAlphaBits=4,-dGraphicsAlphaBits=4,-dDEVICEWIDTHPOINTS=238,-dDEVICEHEIGHTPOINTS=149.5,-dFIXEDMEDIA,-r600,-dDownScaleFactor=2,-sDEVICE=jpeg,-sOutputFile=/tmp/PAN_0101197702.jpeg,-c "<</PageOffset[-308.5 40]>> setpagedevice",-sPDFPassword=01011977,/tmp/PAN_01011977.pdf
{ Error: ENOENT: no such file or directory, stat '/tmp/PAN_0101197701.jpeg'
errno: -2,
code: 'ENOENT',
syscall: 'stat',
path: '/tmp/PAN_0101197701.jpeg' }
gs Part two excuted
{ Error: ENOENT: no such file or directory, stat '/tmp/PAN_0101197701.jpeg'
errno: -2,
code: 'ENOENT',
syscall: 'stat',
path: '/tmp/PAN_0101197701.jpeg' }
и ошибка:
and the error log
exception: { ChildProcessError: `convert /tmp/PAN_0101197701.jpeg -thumbnail 200x200> /tmp/PAN_01011977-thumb.jpeg` failed with code 1
at ChildProcess.<anonymous> (/srv/node_modules/child-process-promise/lib/index.js:132:23)
at emitTwo (events.js:126:13)
at ChildProcess.emit (events.js:214:7)
at maybeClose (internal/child_process.js:915:16)
at Process.ChildProcess._handle.onexit (internal/child_process.js:209:5)
name: 'ChildProcessError',
code: 1,
childProcess:
ChildProcess {
domain:
Domain {
domain: null,
_events: [Object],
_eventsCount: 1,
_maxListeners: undefined,
members: [Array] },
_events: { error: [Function], close: [Function] },
_eventsCount: 2,
_maxListeners: undefined,
_closesNeeded: 3,
_closesGot: 3,
connected: false,
signalCode: null,
exitCode: 1,
killed: false,
spawnfile: 'convert',
_handle: null,
spawnargs:
[ 'convert',
'/tmp/PAN_0101197701.jpeg',
'-thumbnail',
'200x200>',
'/tmp/PAN_01011977-thumb.jpeg' ],
pid: 14,
stdin:
Socket {
connecting: false,
_hadError: false,
_handle: null,
_parent: null,
_host: null,
_readableState: [Object],
readable: false,
domain: [Object],
_events: [Object],
_eventsCount: 2,
_maxListeners: undefined,
_writableState: [Object],
writable: false,
allowHalfOpen: false,
_bytesDispatched: 0,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
_idleNext: null,
_idlePrev: null,
_idleTimeout: -1,
[Symbol(asyncId)]: 4540,
[Symbol(bytesRead)]: 0 },
stdout:
Socket {
connecting: false,
_hadError: false,
_handle: null,
_parent: null,
_host: null,
_readableState: [Object],
readable: false,
domain: [Object],
_events: [Object],
_eventsCount: 3,
_maxListeners: undefined,
_writableState: [Object],
writable: false,
allowHalfOpen: false,
_bytesDispatched: 0,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
_idleNext: null,
_idlePrev: null,
_idleTimeout: -1,
write: [Function: writeAfterFIN],
[Symbol(asyncId)]: 4541,
[Symbol(bytesRead)]: 0 },
stderr:
Socket {
connecting: false,
_hadError: false,
_handle: null,
_parent: null,
_host: null,
_readableState: [Object],
readable: false,
domain: [Object],
_events: [Object],
_eventsCount: 3,
_maxListeners: undefined,
_writableState: [Object],
writable: false,
allowHalfOpen: false,
_bytesDispatched: 0,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
_idleNext: null,
_idlePrev: null,
_idleTimeout: -1,
write: [Function: writeAfterFIN],
[Symbol(asyncId)]: 4542,
[Symbol(bytesRead)]: 232 },
stdio: [ [Object], [Object], [Object] ] },
stdout: '',
stderr: 'convert-im6.q16: unable to open image `/tmp/PAN_0101197701.jpeg\': No such file or directory @ error/blob.c/OpenBlob/2701.\nconvert-im6.q16: no images defined `/tmp/PAN_01011977-thumb.jpeg\' @ error/convert.c/ConvertImageCommand/3258.\n' }
Error serializing return value: TypeError: Converting circular structure to JSON
Function execution took 9561 ms, finished with status: 'ok'
Проблема в том, что в gs используется опция ниже, эта функция работает, но она не обрезает pdf, просто преобразует изображение в полную страницу.
//.option('-c "<</PageOffset [ -64.2 40 ]>> setpagedevice"')
//.option('-c "<</PageOffset [ -308.5 40 ]>> setpagedevice"')
Как я могу использовать вышеупомянутая опция?
Редактировать
Пытался завершить -c
с -f
, но не повезло
$ node index.js
gs command: -dSAFER,-dBATCH,-dNOPAUSE,-dTextAlphaBits=4,-dGraphicsAlphaBits=4,-dDEVICEWIDTHPOINTS=238,-dDEVICEHEIGHTPOINTS=149.5,-dFIXEDMEDIA,-r150,-dDownScaleFactor=2,-sPDFPassword=01011977,-sDEVICE=jpeg,-sOutputFile=/home/jcol/Desktop/gs_offline/functions/output.jpeg,-c <</PageOffset[-64.2 40]>>setpagedevice,-f,/home/jcol/Desktop/gs_offline/functions/pan.pdf
Suceess
GPL Ghostscript 9.20 (2016-09-26)
Copyright (C) 2016 Artifex Software, Inc. All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
Processing pages 1 through 1.
Page 1
Loading NimbusSans-Regular font from %rom%Resource/Font/NimbusSans-Regular... 4244908 2808684 2600016 1250276 3 done.