我还遇到了将 Word 文档 (doc/docx) 转换为 PDF 或任何其他文档类型的问题。我使用 AWS Lambda 中的子进程通过 LibreOffice 和 Python 3.8 解决了这个问题(也适用于 python 3.6 和 3.7)。
基本上,此设置将通过输入事件从 S3 中选择您的文件并将文件转换为 PDF 并将转换后的文件放入相同的 S3 位置。让我们来看看设置指南。
对于此设置,我们需要可通过 Lambda 访问的 LibreOffice 可执行文件。为此,我们将使用 Lambda 层。
现在,您有两个选择:
- 您可以create your own AWS Lambda layer 并上传layer.tar.br.zip(您可以从shelfio GitHub repository 下载此存档)
- 或者,您可以直接在 Lambda 中使用 Layer ARN。
2.1。 Layer ARN for python3.6 and 3.7
2.2. Layer ARN for python 3.8
是时候创建 Lambda(依赖包)了。
- 在您的 lambda 文件夹的根目录下创建
fonts/fonts.conf,并包含以下内容(假设 libreoffice 将被提取到 /tmp/instdir 目录下):
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<dir>/tmp/instdir/share/fonts/truetype</dir>
<cachedir>/tmp/fonts-cache/</cachedir>
<config></config>
</fontconfig>
- 将以下代码粘贴到您的
lambda_function.py 文件中:
import os
from io import BytesIO
import tarfile
import boto3
import subprocess
import brotli
libre_office_install_dir = '/tmp/instdir'
def load_libre_office():
if os.path.exists(libre_office_install_dir) and os.path.isdir(libre_office_install_dir):
print('We have a cached copy of LibreOffice, skipping extraction')
else:
print('No cached copy of LibreOffice exists, extracting tar stream from Brotli file.')
buffer = BytesIO()
with open('/opt/lo.tar.br', 'rb') as brotli_file:
decompressor = brotli.Decompressor()
while True:
chunk = brotli_file.read(1024)
buffer.write(decompressor.decompress(chunk))
if len(chunk) < 1024:
break
buffer.seek(0)
print('Extracting tar stream to /tmp for caching.')
with tarfile.open(fileobj=buffer) as tar:
tar.extractall('/tmp')
print('Done caching LibreOffice!')
return f'{libre_office_install_dir}/program/soffice.bin'
def download_from_s3(bucket, key, download_path):
s3 = boto3.client("s3")
s3.download_file(bucket, key, download_path)
def upload_to_s3(file_path, bucket, key):
s3 = boto3.client("s3")
s3.upload_file(file_path, bucket, key)
def convert_word_to_pdf(soffice_path, word_file_path, output_dir):
conv_cmd = f"{soffice_path} --headless --norestore --invisible --nodefault --nofirststartwizard --nolockcheck --nologo --convert-to pdf:writer_pdf_Export --outdir {output_dir} {word_file_path}"
response = subprocess.run(conv_cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if response.returncode != 0:
response = subprocess.run(conv_cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if response.returncode != 0:
return False
return True
def lambda_handler(event, context):
bucket = event["document_bucket"]
key = event["document_key"]
key_prefix, base_name = os.path.split(key)
download_path = f"/tmp/{base_name}"
output_dir = "/tmp"
download_from_s3(bucket, key, download_path)
soffice_path = load_libre_office()
is_converted = convert_word_to_pdf(soffice_path, download_path, output_dir)
if is_converted:
file_name, _ = os.path.splitext(base_name)
upload_to_s3(f"{output_dir}/{file_name}.pdf", bucket, f"{key_prefix}/{file_name}.pdf")
return {"response": "file converted to PDF and available at same S3 location of input key"}
else:
return {"response": "cannot convert this document to PDF"}
- 从 Linux 环境构建(并在安装后从您的 Linux 环境中复制
site-packages/brotli)brotlipy 依赖项,因为目标 Lambda 运行时是 AmazonLinux。
最后,你的 lambda(依赖包)的目录结构应该是这样的:
.
+-- brotli/*
+-- fonts
| +-- fonts.conf
+-- lambda_function.py
如果您的文件 s3 URI 是 s3://my-bucket-name/dir/file.docx,您可以使用以下输入事件来调用此 Lambda 处理程序:
{
"document_bucket: "my-bucket-name"
"document_key": "dir/file.docx"
}
干杯!如果您遇到任何问题,请告诉我,很乐意为您提供帮助:)