Open3

lambdaでpdf変換をやってみた

hakohakophakohakop

ローカルのDocker上でlambaを動かしてみる

https://qiita.com/nodokamome/items/8a7e895185146c133b5b
https://qiita.com/sasaco/items/b65ce36c05c50a74ac3e
このへんの記事に沿って進めていく


ファイル作成

app.py
import json

def handler(event, context):
    return {
        "statusCode": 200,
        "body": json.dumps(
            {
                "message": "hello world",
            }
        ),
    }
Dockerfile
FROM public.ecr.aws/lambda/python:3.12
COPY app.py ${LAMBDA_TASK_ROOT}
CMD ["app.handler"]

1. イメージ作成

$ docker build -t func1 .
ERROR: failed to solve: public.ecr.aws/lambda/python:3.12: failed to resolve source metadata for public.ecr.aws/lambda/python:3.12: error getting credentials - err: exec: "docker-credential-desktop.exe": executable file not found in $PATH, out: ``

エラーが出たので以下で解決
https://kazupon.org/docker-build-error-filenotfound/

2. コンテナ作成

$ docker run -d -p 9000:8080 func1

3. 動作確認

$ curl -d '{}' http://localhost:9000/2015-03-31/functions/function/invocations
{"statusCode": 200, "body": "{\"message\": \"hello world\"}"}

なるほどこれで動くのか~

hakohakophakohakop

ローカル環境でxlsxをpdfに変換する

ファイルを用意

Dockerfile
# Pull the base image with python 3.11 as a runtime for your Lambda
FROM public.ecr.aws/lambda/python:3.11

# Install OS packages
RUN yum -y install wget tar gzip zlib freetype-devel openssl
RUN yum -y install libxslt \
    gcc \
    ghostscript \
    lcms2-devel \
    libffi-devel \
    libjpeg-devel \
    libtiff-devel \
    libwebp-devel \
    make \
    openjpeg2-devel \
    sudo \
    tcl-devel \
    tk-devel \
    which \
    xorg-x11-server-Xvfb \
    zlib-devel \
    java \
    && yum clean all

RUN wget https://downloadarchive.documentfoundation.org/libreoffice/old/7.6.7.2/rpm/x86_64/LibreOffice_7.6.7.2_Linux_x86-64_rpm.tar.gz
RUN tar -xvzf LibreOffice_7.6.7.2_Linux_x86-64_rpm.tar.gz
RUN cd LibreOffice_7.6.7.2_Linux_x86-64_rpm/RPMS; yum -y localinstall *.rpm;
RUN yum -y install cairo

COPY app.py ${LAMBDA_TASK_ROOT}
CMD ["app.handler"]
app.py
import json
import subprocess
# import boto3 # type: ignore
import os
import urllib.parse

# s3 = boto3.resource('s3')
# output_bucket = "libreoffice-out"

def handler(event, context):
    # if 'Records' in event.keys():
    #     input_bucket = event['Records'][0]['s3']['bucket']['name']
    #     input_key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8')
    #     in_bucket = s3.Bucket(input_bucket)
    # else :
    #     return 'test finished'

    input_key = 'test.xlsx'
    print(input_key)
    # get S3 Object
    file_path = '/tmp/'+input_key
    # in_bucket.download_file(input_key, file_path)

    proc = subprocess.run("/opt/libreoffice7.6/program/soffice --headless --norestore --invisible --nodefault --nofirststartwizard --nolockcheck --nologo --convert-to pdf:writer_pdf_Export --outdir /tmp {}".format("/tmp/"+input_key), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    print('STDOUT: {}'.format(proc.stdout))
    print('STDERR: {}'.format(proc.stderr))

    key_list = input_key.split('.')
    pdf_path = "/tmp/"+input_key.replace(key_list[-1], 'pdf')

    # put S3 Object
    if os.path.exists(pdf_path):
        print('PDF: {}'.format(pdf_path.replace("/tmp/", "")))
        print('Size: {}'.format(os.path.getsize(pdf_path)))
        data = open(pdf_path, 'rb')
        # out_bucket = s3.Bucket(output_bucket)
        # out_bucket.put_object(Key=pdf_path.replace("/tmp/", ""),Body=data)
        data.close()
    else :
        print("The PDF file({}) cannot be found".format(pdf_path))

    return ''

上記2ファイル[1]に加えて/src配下にtest.xlsxファイル(変換検証用ファイル)を準備

Dockerコマンド実行

ビルド

$ docker build -t py-pdf:latest .

コンテナ起動

$ docker run --name app --volume ./src:/tmp  -p 8080:8080 py-pdf:latest

lambdaトリガー実行

$ curl -XPOST "http://localhost:8080/2015-03-31/functions/function/invocations" -d '{}'

pdfファイルが作成される

$ ls -l ./src/
total 300
drwxr-xr-x 2 root      root        4096 Oct 31 21:38 hsperfdata_root
-rw-r--r-- 1 root      root      212201 Oct 31 21:38 test.pdf
-rw-rw-r-- 1 hoge hoge  88757 Oct 31 20:42 test.xlsx

感想

ちゃんと変換出来ててすごいけど、適切なフォントを入れてないからそこは別途入れる必要がありそう

脚注
  1. python3.11にしたのは、python3.12だとOSがAL2023になり、デフォルトで入っているmicrodnfだとlocal installが利用できないため ↩︎