ImageMagick 不再在 AWS Lambda 中转换 pdf

Posted

技术标签:

【中文标题】ImageMagick 不再在 AWS Lambda 中转换 pdf【英文标题】:ImageMagick not converting pdfs anymore in AWS Lambda 【发布时间】:2019-11-25 18:51:38 【问题描述】:

在过去的 18 个月里,我在 S3 对象上运行了一个 AWS Lambda 函数,但它在大约一个月前在一次小更新后就死了。我已经恢复了它,但它仍然坏了。我已经研究过使用 ImageMagick 进行最基本的 pdf 转换,但没有成功,所以我认为 AWS 更新了一些内容并导致 pdf 模块被删除或停止工作。

我只完成了我在 Node.js 8.10 中的核心代码中基本完成的基本功能:

gm(response.Body).setFormat("png").stream((err, stdout,stderr) => 
  if (err) 
    console.log('broken');
  
  const chunks = [];
  stdout.on('data', (chunk) => 
    chunks.push(chunk);
  );
  stdout.on('end', () => 
    console.log('gm done!');
  );
  stderr.on('data', (data) => 
    console.log('std error data ' + data);
  )
);

带有错误响应:

标准错误数据转换:无法加载模块`/usr/lib64/ImageMagick-6.7.8/modules-Q16/coders/pdf.la':找不到文件

我还尝试迁移到 Node.js 10.x 并使用可通过 aws 无服务器应用程序存储库获得的 ImageMagick 层。在相同的代码上尝试这个会产生这个错误

标准错误数据转换:FailedToExecuteCommand `'gs' -sstdout=%stderr -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 '-sDEVICE=pngalpha' -dTextAlphaBits=4 -dGraphicsAlphaBits=4 '-r72x72' '-sOutputFile=/tmp/magick-22TOeBgB4WrfoN%d' '-f/tmp/magick-22KvuEBeuJuyq3' '-f/tmp/magick-22dj24vSktMXsj'' (1) @error/pdf。 c/InvokePDFDelegate/292

在这两种情况下,该函数在图像文件上运行时都能正常工作。

基于此,我认为 aws 8.10 ImageMagick 和 10 层都缺少 pdf 模块,但我不确定如何添加它或为什么首先将其删除。修复此功能的最佳方法是什么?

编辑

所以我已经下载了https://github.com/serverlesspub/imagemagick-aws-lambda-2 并手动构建了库,将其上传到 Lambda 并使其成功地作为一个层工作,但是它不包含作为可选库的 GhostScript。我尝试将它添加到Makefile_ImageMagick,它构建并在结果中有一些对 Ghostscript 的引用,但运行它并不能解决 PDF 问题(图像仍然有效)。将 GhostScript 可选库添加到 Make 文件的最佳方法是什么?

【问题讨论】:

您是否为 Imagemagick 安装了 Ghostscript?如果你不这样做,那么你需要它。如果您这样做,那么您可能需要编辑 delegates.xml 文件以插入到 gs (ghostscript) 的完整路径以获取 PDF 相关条目。或者您可能需要编辑您的 policy.xml 文件以授予对 PDF 文件的读写权限。见***.com/questions/52861946/…。对不起,我不知道或使用 AWS @fmw42 我不需要,但我以前不需要它。 AWS 是否删除了它? 什么意思,你以前不需要它?在 AWS 或只是 Imagemagick 上。阅读 PDF 文件总是需要 Ghostscript。不需要编写它们。如果您的 Imagemagick 版本以前是旧的,则 policy.xml 文件可能没有包含它。它是在几个月前报告有关 Ghostscript 的安全错误时添加的。也许 AWS 更新了 Imagemagick 并在 policy.xml 文件中引入了新条目。或者他们可能遗漏了 Ghostscript。 同样的问题!看起来像一个 AWS 问题,因为它已经运行了一年多... 我相信AWS Lambda默认不再包含ghostscript,也就是ImageMagick使用的PDF委托。 【参考方案1】:

虽然其他答案有所帮助,但要找到一个可行的解决方案还有很多工作要做,所以下面是我设法解决这个问题的方法,特别是针对 NodeJS。

下载:https://github.com/sina-masnadi/lambda-ghostscript

压缩 bin 目录并将其作为层上传到 Lambda。

将https://github.com/sina-masnadi/node-gs 添加到您的 NodeJS 模块中。您可以将它们作为项目的一部分上传,也可以按照我的方式上传(以及所有其他必需的)。

将https://github.com/serverlesspub/imagemagick-aws-lambda-2 添加为图层。最好的方法是在 Lambda 中创建一个新函数,选择浏览无服务器应用程序存储库,搜索“ImageMagick”并选择“image-magick-lambda-layer”(您也可以构建它并将其上传为层) .

将三层添加到你的函数中,我已经按照这个顺序完成了

    GhostScript ImageMagick NodeJS 模块

将 appPath 添加到 ImageMagick 和 GhostScript 的 require 语句中:

var gm = require("gm").subClass(imageMagick: true, appPath: '/opt/bin/');
var gs = require('gs');

我的是在一个异步瀑布中,所以在我之前的处理函数之前,我添加了这个函数来转换为 png,如果不是图像的话:

  function convertIfPdf(response, next) 
    if (fileType == "pdf") 
      fs.writeFile("/tmp/temp.pdf", response.Body, function(err) 
        if (!err) 
          gs().batch().nopause().executablePath('/opt/bin/./gs').device('png16m').input("/tmp/temp.pdf").output('/tmp/temp.png').exec(function (err, stdout, stderr)
            if (!err && !stderr) 
              var data = fs.readFileSync('/tmp/temp.png');
              next(null, data);
             else 
              console.log(err);
              console.log(stderr);
            
          );
        
      );
     else 
      next(null, response.Body);
    
  

从那时起,您可以执行之前在 ImageMagick 中执行的操作,因为它的格式相同。可能有更好的方法来进行 pdf 转换,但除非使用文件,否则我遇到了 GS 库的问题。如果有更好的方法请告诉我。

如果您在加载库时遇到问题,请确保路径正确,这取决于您如何压缩它。

【讨论】:

@SachinChavan 这是完全相同的结果,除了这个答案有更清晰的步骤并使用层进行良好的重用。它甚至在博文中说它做了同样的事情。 你是对的,我正在尝试这个但无法跟随图层的东西,这真的很好。我已经在 zip 中添加了这些二进制文件并上传了它。会试一试。谢谢你,它真的很有用。 如果假设我想拍摄图像并上传到 S3,我们如何使用 GS 来做到这一点?@Rudiger,如果你输出到 /tmp/temp.png,不会写到本地lambda的文件系统?那将被保存在哪里?因为 lambda 是无状态的,是的(lambda 与 EC2 有文件系统的 EC2 不同)? @KJAng 是的,您需要编写代码来拾取并移动它,但这超出了此答案的范围。有许多教程会向您展示执行此操作的代码,这个答案是特定于它的 GS 部分的。 @Rudiger,感谢您的回答。还有一个问题。你为什么要var data = fs.readFileSync('/tmp/temp.png');?是因为您要使用数据发送到 S3 吗?数据是缓冲区还是 base64 或其他?【参考方案2】:

我遇到了同样的问题。由于 pdf.la not found 错误,每天处理数千个 PDF 页面的两个云服务失败。

解决方案是从 Image Magick 切换到 GhostScript 以将 PDF 转换为 PNG,然后将 ImageMagick 与 PNG 结合使用(如果需要)。这样,IM 永远不必处理 PDF,也不需要 pdf.la 文件。

要在 AWS Lambda 上使用 GhostScript,只需将 gs 二进制文件上传到函数 zip 文件中。

【讨论】:

这太糟糕了。一旦我调查了它,我会试一试并更新它。你刚刚构建了github.com/sina-masnadi/lambda-ghostscript吗? @Rudiger 我在 Amazon Linux EC2 实例上安装了 ghostscript,使用“whereis”查找“gs”二进制文件,使用“lld gs”获取所需库的列表。将 gs 二进制文件添加到函数 zip 文件的根目录中,并将库添加到函数 zip 文件内的“lib”文件夹中。 @Rudiger 另外,更改了 lambda 函数代码,以便它可以在 /var/task/gs 中找到 gs 二进制文件。 谢谢,我已将 ImageMagick 添加为一个效果很好的图层,因此我也会将 gs 添加为一个图层。 虽然这不是我的答案,但它对我得到的答案最有帮助,所以我会奖励它。【参考方案3】:

您可以向您的 lambda 函数添​​加一个层,以使其在 2019 年 7 月 22 日之前再次工作。 您需要添加的层的 ARN 如下:arn:aws:lambda:::awslayer:AmazonLinux1703

该过程在upcoming-updates-to-the-aws-lambda-execution-environment进行了描述

任何长期的解决方案都会很棒。

【讨论】:

谢谢。它确实解决了这个问题,但只有 2 天,这不是很好。由于这个原因,可能无法将其标记为正确,但现在绝对是临时修复。【参考方案4】:

我遇到了找不到 ghostscript 的问题。

以前,我通过以下方式引用了 ghostscript:

var gs = '/usr/bin/gs';

由于 AWS lambda 停止提供该软件包,我将其直接包含在我的 lambda 函数中,该函数对我有用。我刚刚从https://github.com/sina-masnadi/lambda-ghostscript 下载了文件并将其放在一个名为“ghostscript”的文件夹中,然后这样引用它:

var path = require('path')
var gs = path.join(__dirname,"ghostscript","bin","gs")

【讨论】:

以上是关于ImageMagick 不再在 AWS Lambda 中转换 pdf的主要内容,如果未能解决你的问题,请参考以下文章

来自执行环境的 AWS Lambda 凭证没有执行角色的权限

使用ImageMagick操作gif图

Amazon Kinesis 和 AWS Lambda 重试

imagemagick:调整大小后如何获取图像大小?

aws lambda 函数可以向专用网​​络中的端点发布帖子吗?

如何替换在我部署 Elastic Beanstalk 应用程序时不再工作的 AWS CLI 命令