본문 바로가기

Compute/Lambda

AWS Lambda Edge를 이용한 이미지 리사이징

먼저 기본 내용은 아래 AWS Blog를 통해 확인하자.

 

 

Resizing Images with Amazon CloudFront & Lambda@Edge | AWS CDN Blog | Amazon Web Services

Do you have lots of images that need to be modified before delivery? No problem with Amazon CloudFront and Lambda@Edge. Read more on how you can use our services to modify image dimensions, apply watermarks, or optimize formats based on browser support all

aws.amazon.com

 

중요 키워드는 Lambda Edge 그리고 Origin Response를 활용하는 것이다. 이 워크플로우는 기타 여러 블로그에 기재되어 있다.

 

AWS Lambda@edge로 실시간 이미지 리사이징(updated)

AWS Lambda@edge(CloudFront)로 실시간 이미지 리사이징 기능을 구현합니다. Cloud 9으로 람다 함수를 작성하고 CloudWatch로 로그를 확인합니다.

heropy.blog

 

 

내 경우 원본이 S3가 아닌 IDC 혹은 EC2의 경우 axios를 활용해 이미지 데이터를 다운 받은 후 sharp를 통해 이미지 리사이징을 구현했다. AWS Blog의 코드를 참고 했으며 조금 수정했다.

 

[index.js] v.10.18.0

'use strict';

const querystring = require('querystring'); // Don't install.
const AWS = require('aws-sdk'); // Don't install.
const sharp = require('sharp');
const axios = require('axios');
const fs = require('fs');

exports.handler = async(event, context, callback) => {
    let origin = "http://52.78.189.144" //Custom Origin URL
    console.log(event.Records[0].cf)
    const { request, response } = event.Records[0].cf
    console.log(`request: ${request}`)
    console.log(`response: ${response}`)
    const params = querystring.parse(request.querystring)
    if (!params.w && !params.h) {
        return callback(null, response)
    }
    const { uri } = request
    const [, imageName, extension] = uri.match(/\/?(.*)\.(.*)/)
    let width
    let height
    let format
    width = parseInt(params.w, 10) ? parseInt(params.w, 10) : null;
    height = parseInt(params.h, 10) ? parseInt(params.h, 10) : null;
    format = params.f ? params.f : extension;
    format = format === 'jpg' ? 'jpeg' : format
    console.log(`format: ${format}`)
    console.log(`parmas: ${JSON.stringify(params)}`) // Cannot convert object to primitive value.
    console.log(`name: ${imageName}.${extension}`) // Favicon error, if name is `favicon.ico`.
    console.log(origin + '/' + imageName + '.' + extension)
    const data = await originCheck(origin + '/' + imageName + '.' + extension)
    const resizedImage = await resize(data, width, height)
    const resizedImageByteLength = Buffer.byteLength(resizedImage, 'base64');
    console.log('byteLength: ', resizedImageByteLength);
    if (resizedImageByteLength >= 1 * 1024 * 1024) {
        return callback(null, response);
    }
    response.status = 200;
    response.body = resizedImage.toString('base64');
    response.bodyEncoding = 'base64';
    response.headers['content-type'] = [{
        key: 'Content-Type',
        value: `image/${format}`
    }];
    return callback(null, response);
}

const originCheck = async(uri) => {
    try {
        const body = await axios.get(uri, { responseType: "arraybuffer" })
        return body.data
    }
    catch (err) {
        console.log(`axios err: ${err}`)
    }
}

const resize = async(data, width, height) => {
    try {
        // const result = await sharp(data).resize(200, 100, { fit: "fill" }).toFile("./200x500_outside.jpg");
        const result = await sharp(data).resize(width, height, { fit: "fill" }).toFormat('jpeg').toBuffer()
        return result
    }
    catch (err) {
        console.log(`resize: ${err}`)
    }
}

 

[package.json]

{
  "name": "resize-image",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "aws-sdk": "^2.595.0",
    "axios": "^0.19.0",
    "base64-img": "^1.0.4",
    "sharp": "^0.23.4"
  }
}

 

결과

TEST URI: http://d3ois01c955xts.cloudfront.net/test.jpg

Thumnail URI: http://d3ois01c955xts.cloudfront.net/test.jpg?w=100&h=200

 

[github]

https://github.com/leedoing/imageResize-lambdaedge

 

 

람다 로깅 레벨은 아래와 같이 정의 가능

import logging

logger = logging.getLogger()
logger.setLevel(logging.ERROR)