AWS LambdaでqrcodeとPillowを利用したQRコード生成(カスタムレイヤーを利用)

AWS

AWS Lambdaでqrcodeとpillowを利用しQRコードを生成してみます。
実装自体は簡単なのですがLambadaのカスタムレイヤーの作成に手こずりました。
LambdaのランタイムにはPython3.8を利用します。

利用ライブラリについて (qrcode/pillow)

qrcodeとpillowはLambda標準ライブラリに含まれていないのでカスタムレイヤーとして追加します。
pillowはOS依存があるのでレイヤー用のZipを作成する際はLambdaのPython実行環境と同じOSで作成する必要があります。
実行環境は言語やバージョンによって異なります。詳細は以下リンク先を参照ください。
Lambda ランタイム

今回はAWS SAM用に用意されたDockerコンテナを利用してレイヤーを作成します。

事前準備 Docker

今回はCloud9上でレイヤーの作成を行います。
Cloud9では標準でDockerがインストールされているはずです。以下で確認します。

# バージョン確認
docker --version
# サービスの実行状態確認
sudo docker info
# 自分がDockerグループに所属しているか確認。「docker」が含まれていればOK.
groups
# 動作確認
docker run hello-world

カスタムレイヤーの作成

以下の構造でフォルダと「requirements.txt」を作成します。

├── requirements.txt
└── python/
    └── lib/
        └── python3.8/
            └── site-packages/

requirements.txtには必要なライブラリを記載します。今回は以下の2つです。

qrcode
Pillow

準備したフォルダにライブラリをインストールします。

docker run -v "$PWD":/var/task "public.ecr.aws/sam/build-python3.8" /bin/sh -c "pip install -r requirements.txt -t python/lib/python3.8/site-packages/; exit"

インストールしたライブラリをZIP化します。

zip -r qrcodelibs.zip python > /dev/null

レイヤーを更新します。

aws lambda publish-layer-version --layer-name qrcodelibs --description "qrCodelibs" --zip-file fileb://qrcodelibs.zip --compatible-runtimes "python3.8"

作成したレイヤーを使用するようにLamba関数を更新します。
レイヤーのARNとLambda関数名は環境に合わせて変更してください。

aws lambda update-function-configuration --layers arn:aws:lambda:us-east-1:xxx:layer:qrcodelibs:1 --function-name my-function

QRコードの生成(SVG形式)

QRコードを生成するLambda関数です。
Lambdaプロキシ統合の場合はBase64での返却が必須なので
生成したデータをBase64形式にしてから送信します。

import io
import qrcode
import base64
import qrcode.image.svg

def lambda_handler(event, context):

    encoded_image = make_base64_svg('qrtest')

    return {
        "statusCode": 200,
        "headers": {"Content-Type": 'image/svg+xml'},
#        "headers": {"Content-Type": "image/png"},
        # Lambdaプロキシ統合の場合はBase64での返却が必須
        "isBase64Encoded": True,
        "body": encoded_image
    }

def make_base64_svg(data):
    qr = qrcode.QRCode(
        box_size=400,
        border=2,
    )
    qr.add_data(data)
    qr.make(fit=True)
    img = qr.make_image(image_factory=qrcode.image.svg.SvgPathImage,fill_color="black", back_color="white")
    buffered = io.BytesIO()
    img.save(buffered)
    buffered.flush()
    base64str = base64.b64encode(buffered.getvalue()).decode("utf-8")

    return base64str 

QRコードの生成(PNG形式)

PNG形式の場合は下記のようになります。フォーマット指定が変更になるだけです。

def make_base64_png(data):
    qr = qrcode.QRCode()
    qr.add_data(data)
    qr.make()
    img = qr.make_image()

    buffered = io.BytesIO()
    img.save(buffered, format="PNG")
    base64str = base64.b64encode(buffered.getvalue()).decode("utf-8")
    return base64str

APIGatewayで画像返却する際の注意点

AWS Lambda プロキシ統合のバイナリペイロードを処理するには、関数のレスポンスを base64 でエンコードする必要があります。
また、API の binaryMediaTypes を設定する必要があります。

参考

以上

タイトルとURLをコピーしました