Lambda関数でLibreOfficeを使ってExcelファイルからpdfファイルを出力する

# 作るもの
S3からエクセルファイルを取得し、
その内容をPDFに変換し、
そのPDFをS3に保存するLambda関数
**PDF操作にはLibreOfficeを使用**

# 前提
- aws samを使って構築していく
- CLIを使えるようにしておく
- init samでhello worldのテンプレートが実行できる状態にしておく

# 開発
### template

~~~yaml:template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  convert_excel_into_pdf

Globals:
  Function:
    Timeout: 900 # ここまで増やす必要ないと思うが念の為
    MemorySize: 256 # LibreOfficeは結構メモリ使うので上げとく。128じゃ足りないかも。

    Tracing: Active
  Api:
    TracingEnabled: true

Parameters:
  BucketName:
    Type: String
    Default: 'my-bucket'

  ConvertExcelIntoPdfFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: convert_excel_into_pdf/
      Architectures:
        - x86_64
      Environment:
        Variables:
          BUCKET_NAME: !Ref BucketName
      # コンテナイメージをDockerで手動作成したいのでパッケージタイプはImage
      PackageType: Image
      Policies:
        - arn:aws:iam::aws:policy/AmazonS3FullAccess
    Metadata:
      Dockerfile: Dockerfile
      DockerContext: ./convert_excel_into_pdf
      DockerTag: python3.8-v1
~~~

### DockerFile

~~~Docker:Dockerfile
FROM public.ecr.aws/lambda/python:3.8

RUN yum -y install curl wget tar gzip zlib freetype-devel
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 \
    tkinter \
    which \
    xorg-x11-server-Xvfb \
    zlib-devel \
    java \
    ipa-gothic-fonts ipa-mincho-fonts ipa-pgothic-fonts ipa-pmincho-fonts \
    && yum clean all

# LibreOfficeツールをダウンロード
RUN wget http://download.documentfoundation.org/libreoffice/stable/7.5.3/rpm/x86_64/LibreOffice_7.5.3_Linux_x86-64_rpm.tar.gz
RUN tar -xvzf LibreOffice_7.5.3_Linux_x86-64_rpm.tar.gz
RUN cd LibreOffice_7.5.3.2_Linux_x86-64_rpm/RPMS; yum -y localinstall *.rpm;
RUN yum -y install cairo

COPY app.py ${LAMBDA_TASK_ROOT}

CMD [ "app.lambda_handler" ]
~~~

### Lambda関数

~~~python:app.py
import os
import subprocess

import boto3

s3 = boto3.resource("s3")
output_bucket = os.getenv("BUCKET_NAME")


def lambda_handler(event, context):
    input_bucket = os.getenv("BUCKET_NAME")
    input_key = "output.xlsx"
    in_bucket = s3.Bucket(input_bucket)
    # エクセルファイルを取得
    file_path = "/tmp/" + input_key
    in_bucket.download_file(input_key, file_path)
    # LibreOfficeを使ってPDF変換
    proc = subprocess.run(
        "/opt/libreoffice7.5/program/soffice --headless --norestore --invisible --nodefault --nofirststartwizard --nolockcheck --nologo --convert-to pdf:writer_pdf_Export --outdir /tmp {}".format(
            file_path
        ),
        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 = file_path.replace(key_list[-1], "pdf")

    # PDFファイルをアップロード
    if not os.path.exists(pdf_path):
        print("The PDF file({}) cannot be found".format(pdf_path))
        return
    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()

    return {"statusCode": 200, "message": "PDF変換完了"}
~~~

# 参考

https://note.com/dimage/n/nc3c843accdee