GS Firebase 功能无法设置偏移量?
GS Firebase function can't set offset?
我正在使用 firebase 函数裁剪 pdf 的某些区域并使用 ghostscript 将它们转换为图像
[包装纸 https://www.npmjs.com/package/node-gs and compiled version of 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"')
如何使用上述选项?
编辑
尝试用 -f
终止 -c
但没有成功
$ 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.
在没有示例文件(理想情况下是发送到 Ghostscript 的实际命令行)以及缺少反向通道输出(stout 和 stderr)的情况下,我唯一可以观察到的是 'option' 你指的(实际上是一段 PostScript 编程)使用 -c
开关引入 PostScript 输入,但不会用 -f
终止它。这意味着命令行上的任何内容都将被视为更多 PostScript,这可能会导致错误或 'hang',等待更多输入。
致未来读者
对于像我这样的新手
由于我是新手,所以在使用 NODEJS
中的库时有些困惑。
首先,我使用了一些 gs-wrapper
来自一些不在 NPM 上的教程,这是错误的原因,因为由于某些原因不支持命令。
经过一些研究,我从 npm 来到 Node-gs
,我在 NPM 的页面上检查了 Node-GS
API,它有专门的 command
选项。
现在我为什么要发布这个答案:
NODE-GS
库是唯一支持像 Firebsae Functions 这样的无服务器架构的库。但是这里的错误处理是最糟糕的,因为它只会直接从可执行文件中生成 Ghostscirpt。
例如,如果您为 PDF 提供了错误的密码,那么图书馆只会在错误消息中推送 Ghostscript Unrecoverable Error
。
(我知道如果你在无服务器功能中使用 Ghostscirpt,你足够聪明,可以在客户端检查密码是否正确,但只是举个例子)
在撰写本文时,我发现 Ghostscript4JS for NODE
使用 Ghostscript 的 C++ API 但不幸的是,该库不支持无服务器架构,因为该库依赖于系统安装了 Ghostscirpt,但开发人员表示它有一些计划。
检查库现在是否支持无服务器架构。
最后,作为新手我不得不经历的挣扎是找到 Ghostscirpt 的便携式版本与 NODE-GS
一起使用,你可以在这里找到它 Ghostscript Releases
对于 Firebase 函数用户
Firebase 函数是基于 Ubuntu Bionic 18.04 arch x64
构建的,因此您必须使用 x86_64 版本的 Ghostscript,撰写本文时最新版本是 Ghostscript 9.52
再见:)
我正在使用 firebase 函数裁剪 pdf 的某些区域并使用 ghostscript 将它们转换为图像 [包装纸 https://www.npmjs.com/package/node-gs and compiled version of 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"')
如何使用上述选项?
编辑
尝试用 -f
终止 -c
但没有成功
$ 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.
在没有示例文件(理想情况下是发送到 Ghostscript 的实际命令行)以及缺少反向通道输出(stout 和 stderr)的情况下,我唯一可以观察到的是 'option' 你指的(实际上是一段 PostScript 编程)使用 -c
开关引入 PostScript 输入,但不会用 -f
终止它。这意味着命令行上的任何内容都将被视为更多 PostScript,这可能会导致错误或 'hang',等待更多输入。
致未来读者
对于像我这样的新手
由于我是新手,所以在使用 NODEJS
中的库时有些困惑。
首先,我使用了一些 gs-wrapper
来自一些不在 NPM 上的教程,这是错误的原因,因为由于某些原因不支持命令。
经过一些研究,我从 npm 来到 Node-gs
,我在 NPM 的页面上检查了 Node-GS
API,它有专门的 command
选项。
现在我为什么要发布这个答案:
NODE-GS
库是唯一支持像 Firebsae Functions 这样的无服务器架构的库。但是这里的错误处理是最糟糕的,因为它只会直接从可执行文件中生成 Ghostscirpt。
例如,如果您为 PDF 提供了错误的密码,那么图书馆只会在错误消息中推送 Ghostscript Unrecoverable Error
。
(我知道如果你在无服务器功能中使用 Ghostscirpt,你足够聪明,可以在客户端检查密码是否正确,但只是举个例子)
在撰写本文时,我发现 Ghostscript4JS for NODE
使用 Ghostscript 的 C++ API 但不幸的是,该库不支持无服务器架构,因为该库依赖于系统安装了 Ghostscirpt,但开发人员表示它有一些计划。
检查库现在是否支持无服务器架构。
最后,作为新手我不得不经历的挣扎是找到 Ghostscirpt 的便携式版本与 NODE-GS
一起使用,你可以在这里找到它 Ghostscript Releases
对于 Firebase 函数用户
Firebase 函数是基于 Ubuntu Bionic 18.04 arch x64
构建的,因此您必须使用 x86_64 版本的 Ghostscript,撰写本文时最新版本是 Ghostscript 9.52
再见:)