Firebase的云功能 - 将PDF转换为图像 [英] Cloud Functions for Firebase - Converting PDF to image

查看:168
本文介绍了Firebase的云功能 - 将PDF转换为图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Firebase的Cloud Functions有一个很好的示例,它为每个上传的图像创建缩略图。这是通过使用ImageMagick来完成的。

Cloud Functions for Firebase has this nice sample where they create a thumbnail for each uploaded image. This is done by making use of ImageMagick.

我试图转换样本以将PDF转换为图像。这是ImageMagick可以做的事情,但是我无法使用Cloud Functions for Firebase。我一直收到代码1错误:

I tried to convert the sample to convert PDFs to images. This is something ImageMagick can do, but I can't make it work with Cloud Functions for Firebase. I keep getting a code 1 error:

ChildProcessError: `convert /tmp/cd9d0278-16b2-42be-aa3d-45b5adf89332.pdf[0] -density 200 /tmp/cd9d0278-16b2-42be-aa3d-45b5adf89332.pdf` failed with code 1
    at ChildProcess.<anonymous> (/user_code/node_modules/child-process-promise/lib/index.js:132:23)
    at emitTwo (events.js:106:13)
    at ChildProcess.emit (events.js:191:7)
    at maybeClose (internal/child_process.js:877:16)
    at Socket.<anonymous> (internal/child_process.js:334:11)
    at emitOne (events.js:96:13)
    at Socket.emit (events.js:188:7)
    at Pipe._handle.close [as _onclose] (net.js:498:12)

当然有一种可能性是转换PDF根本不受支持。

Of course one possibility is that converting PDFs are simply not supported.

const functions = require('firebase-functions');
const gcs = require('@google-cloud/storage')();
const spawn = require('child-process-promise').spawn;
// [END import]

// [START generateThumbnail]
/**
 * When an image is uploaded in the Storage bucket We generate a thumbnail automatically using
 * ImageMagick.
 */
// [START generateThumbnailTrigger]
exports.generateThumbnail = functions.storage.object().onChange(event => {
// [END generateThumbnailTrigger]
    // [START eventAttributes]
    const object = event.data; // The Storage object.

    const fileBucket = object.bucket; // The Storage bucket that contains the file.
    const filePath = object.name; // File path in the bucket.
    const contentType = object.contentType; // File content type.
    const resourceState = object.resourceState; // The resourceState is 'exists' or 'not_exists' (for file/folder deletions).
    // [END eventAttributes]

    // [START stopConditions]
    // Exit if this is triggered on a file that is not an image.
    if (!contentType.startsWith('application/pdf')) {
        console.log('This is not a pdf.');
        return;
    }

    // Get the file name.
    const fileName = filePath.split('/').pop();
    // Exit if the image is already a thumbnail.
    if (fileName.startsWith('thumb_')) {
        console.log('Already a Thumbnail.');
        return;
    }

    // Exit if this is a move or deletion event.
    if (resourceState === 'not_exists') {
        console.log('This is a deletion event.');
        return;
    }
    // [END stopConditions]

    // [START thumbnailGeneration]
    // Download file from bucket.
    const bucket = gcs.bucket(fileBucket);
    const tempFilePath = `/tmp/${fileName}`;
    return bucket.file(filePath).download({
        destination: tempFilePath
    }).then(() => {
        console.log('Pdf downloaded locally to', tempFilePath);
        // Generate a thumbnail of the first page using ImageMagick.
        return spawn('convert', [tempFilePath+'[0]' ,'-density', '200', tempFilePath]).then(() => {
            console.log('Thumbnail created at', tempFilePath);
            // Convert pdf extension to png
            const thumbFilePath = filePath.replace('.pdf', 'png');
            // Uploading the thumbnail.
            return bucket.upload(tempFilePath, {
                destination: thumbFilePath
            });
        });
    });
    // [END thumbnailGeneration]
});


推荐答案

节点模块可以安装相同的本机代码目录作为Cloud Function的源代码。我发现github上的一些节点库为ghostscript执行此操作,这是一个非常有用的PDF处理库:

Node modules can install native code that is in the same directory as the Cloud Function's source code. I found that some node libraries on github that do this for ghostscript which is a very useful library for PDF processing:

  • Node library that wraps Ghostscript command line: https://github.com/sina-masnadi/node-gs
  • Compiled Ghostscript which is used via git submodule: https://github.com/sina-masnadi/lambda-ghostscript

我将lambda-ghostscript放入我的 functions 目录的子目录中,然后将 node-gs 添加为我的包文件中的依赖关系如下:

I put lambda-ghostscript into a sub-directory of my functions directory, then add the node-gs as a dependency in my package file like this:

{
  "name": "functions",
  "dependencies": {
    "@google-cloud/storage": "^1.3.1",
    "child-process-promise": "^2.2.1",
    "firebase-admin": "~5.4.0",
    "firebase-functions": "^0.7.2",
    "gs": "https://github.com/sina-masnadi/node-gs/tarball/master"
  }
}

然后在我的index.js文件中,我只需要节点库就可以轻松地使用JavaScript中的ghostscript。以下是使用Google云端存储触发器的云功能的完整代码:

Then in my index.js file I can just require the node library to easily use ghostscript from JavaScript. Here's the complete code for the Cloud Function that uses a Google Cloud Storage trigger:

const functions = require('firebase-functions');
const gcs = require('@google-cloud/storage')();
const spawn = require('child-process-promise').spawn;
const path = require('path');
const os = require('os');
const fs = require('fs');
var   gs = require('gs');

exports.makePNG = functions.storage.object().onChange(event => {

  // ignore delete events
  if (event.data.resourceState == 'not_exists') return false;

  const filePath = event.data.name;
  const fileDir = path.dirname(filePath);
  const fileName = path.basename(filePath);
  const tempFilePath = path.join(os.tmpdir(), fileName);
  if (fileName.endsWith('.png')) return false;
  if (!fileName.endsWith('.pdf')) return false;

  const newName = path.basename(filePath, '.pdf') + '.png';
  const tempNewPath = path.join(os.tmpdir(), newName);


  // // Download file from bucket.
  const bucket = gcs.bucket(event.data.bucket);

  return bucket.file(filePath).download({
    destination: tempFilePath
  }).then(() => {
    console.log('Image downloaded locally to', tempFilePath);

    return new Promise(function (resolve, reject) {
        gs()
          .batch()
          .nopause()
          .option('-r' + 50 * 2)
          .option('-dDownScaleFactor=2')
          .executablePath('lambda-ghostscript/bin/./gs')
          .device('png16m')
          .output(tempNewPath)
          .input(tempFilePath)
          .exec(function (err, stdout, stderr) {
              if (!err) {
                console.log('gs executed w/o error');            
                console.log('stdout',stdout);            
                console.log('stderr',stderr);            
                resolve();
              } else {
                console.log('gs error:', err);
                reject(err);
              }
          });
    });

  }).then(() => {
    console.log('PNG created at', tempNewPath);

    // Uploading the thumbnail.
    return bucket.upload(tempNewPath, {destination: newName});
  // Once the thumbnail has been uploaded delete the local file to free up disk space.
  }).then(() => {
    fs.unlinkSync(tempNewPath);
    fs.unlinkSync(tempFilePath);
  }).catch((err) => {
    console.log('exception:', err);
    return err;
  });

});

这是github上的项目: https://github.com/ultrasaurus/ghostscript-cloud-function

Here's the project on github: https://github.com/ultrasaurus/ghostscript-cloud-function

免责声明:此正在使用编译的本机代码,我通过实验验证了适用于这种情况,所以它可能很好。我没有查看具体的编译选项,并验证它们是否完全符合Cloud Functions环境。

Disclaimer: This is using compiled native code and I verified experimentally that works for this case, so it is probably fine. I didn't look into the specific compile options and validate if they exactly correct for the Cloud Functions environment.

这篇关于Firebase的云功能 - 将PDF转换为图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆