13
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

S3にアップロードされたJPEG画像をLambdaでWebPへ変換する

Last updated at Posted at 2019-04-26

WebPとは

Googleが開発している画像フォーマットで、ウェッピーと読みます。
JPEGと比較してファイルサイズが25-34%小さくなり、採用することで表示の高速化が見込めます。
WebPに対応するプラットフォームは徐々に増加しています。

参考リンク

WebサイトのWebP対応方法

まだWebPに対応できていないプラットフォームが存在するため、JPEG(またはPNG)とWebPと両フォーマットの画像を用意する必要があります。
画像の使い分け方としては、HTMLタグで出し分ける方法と、HTTP RequestのAcceptヘッダの値に応じてサーバのレスポンスを変える方法があります。

HTMLで出し分ける例

<picture>
  <source type="image/webp" src="A.webp">
  <img src="A.jpg">
</picture>

サーバで出し分ける例

Qiita-Webp-Dashiwake.png

[実践]WebP画像を用意する方法

今回WebPの対応をする画像は、Amazon S3で管理しております。
画像はブラウザからサーバサイドアプリ経由でS3にアップロードされる仕組みになっています。

Qiita-Webp-System-Kizon.png

既存の仕組みを変更せずWebP画像を用意したかったため、S3に画像がアップロードされるとAWS Lambdaで自動的に変換する仕組みを作ることにしました。

Qiita-Webp-System-New.png

Lambda functionの実装

functionの作成

Management ConsoleでLambda functionを作成します。
Pythonで実装したかったので、RuntimeはPythonを選択しました。
lambda-create-function.png

IAM Roleの設定

JPEGの画像がアップロードされるバケットの読み込み、WebPの画像をアップロードするバケットへの書き込みとそのオブジェクトのパーミッション変更ができる権限を設定します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:PutObjectAcl"
            ],
            "Resource": "arn:aws:s3:::bucketName/path-to-image/*"
        }
    ]
}

Codeの作成

S3のイベント情報から元画像をダウンロードし、変換したものをS3にアップロードする、という処理を記述します。

lambda_function.py
from PIL import Image
import urllib.parse
import boto3
import os

s3 = boto3.client('s3')

def lambda_handler(event, context):
    bucket = event['Records'][0]['s3']['bucket']['name']
    source_key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8')
    destination_key = source_key + u'.webp'
    source_file = u'/tmp/' + os.path.basename(source_key)
    destination_file = source_file + u'.webp'

    try:
        s3.download_file(Bucket=bucket, Key=source_key, Filename=source_file)
        img = Image.open(source_file, 'r')
        img.save(destination_file, 'webp', quality = 80)
        s3.upload_file(Filename=destination_file,
                       Bucket=bucket,
                       Key=destination_key,
                       ExtraArgs={"ACL":"public-read","ContentType":"image/webp"})
        return source_key
    except Exception as e:
        print(e)
        raise e

ライブラリのインストールとZip化

必要なライブラリ(webp)をインストールするため、lambda_function.py を作成したディレクトリで下記のコマンドを実行します。

pip install webp -t ./

ライブラリインストール後、作業中ディレクトリの内容は下記のようになります。

$ ls -1
PIL/
Pillow-6.0.0.dist-info/
_cffi_backend.cpython-36m-x86_64-linux-gnu.so*
_webp.abi3.so*
bin/
cffi/
cffi-1.12.3.dist-info/
lambda_function.py
numpy/
numpy-1.16.3.dist-info/
pycparser/
pycparser-2.19.dist-info/
webp/
webp-0.1.0a13.dist-info/
webp_build/

下記のコマンドを実行し、zipファイルを作成します。

zip -r convertJpegToWebp.zip ./*

functionへの登録

Function codeパネルにてCode entry typeをUpload a .zip fileとし、Function packageのUploadボタンを押してzipファイルをアップロードします。
Screen Shot 0031-04-25 at 17.05.38.png

S3にEvent Notificationを登録

変換元となる画像がアップロードされるS3バケットに、Lambdaを起動するEvent Notificationを登録します。
画像の登録をトリガーとしたいため、EventsにはAll object create eventsを選択し、対象とする画像のPrefix, SuffixをFilterに設定、TypeはLambdaを選択して作成したLambda functionを設定します。
Screen Shot 0031-04-25 at 17.03.51.png

以上で実装完了です。

元画像をアップロードした数秒後に、WebPの画像が作成されていることが確認できます。
image.png

まとめ

WebP対応するにあたり、未対応環境も考慮すると、WebPとJPEG/PNGの両方を用意しておくことは必須です。手作業で画像を用意しようとしたら大変ですが、自動化する仕組みを作ってしまえば手間無く用意できます。
ファイルサイズが2〜3割程度小さくなるので、画像の多いWebサイトであれば導入のメリットは大きいと思います。

13
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?