2017-04-05 61 views
4

Firebase的云端函数有这样一个很好的示例,可以为每个上传的图片创建一个缩略图。这是通过使用ImageMagick完成的。Firebase的云端函数 - 将PDF转换为图片

我试图转换示例将PDF转换为图像。这是ImageMagick可以做的事情,但我无法使用Firebase的Cloud Functions工作。我不断收到代码1错误:

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文件根本不被支持。

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] 
}); 
+0

看起来,对于转换pdf文件,您还需要ghostscript包,该包并未默认安装在Google Cloud Functions上。 – EJay

+0

还有另外一种方法吗?这是可惜这是不可用... –

+1

还没有找到一个。至少不使用云端功能作为Firebase。 – EJay

回答

1

节点模块可以安装本地代码是在同一目录中的云功能的源代码。我发现,在GitHub上的一些节点库,代表ghostscript做到这一点这是PDF处理一个非常有用的库:

我把λ-ghostscript的到我functions目录的子目录,然后添加node-gs作为依赖于我的包文件像这样:

{ 
    "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文件,我可以只要求节点库方便地使用ghostscript的从JavaScript。下面是云功能,使用谷歌的云存储触发器的完整代码:

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

免责声明:这是使用编译的本地代码和我验证实验,为了这个工作情况,所以它可能是好的。我没有查看具体的编译选项,并验证它们是否完全正确地适用于云功能环境。