Your site is growing! Your free team promes-projects has used 75% of the included free tier usage for Image Optimization - Cache Writes (100,000 Writes). 당신의 사이트는 성장하고 있습니다! 무료 팀 promes-projects는 이미지 최적화 - 캐시 쓰기(100,000 쓰기)의 포함된 무료 사용량의 75%를 사용했습니다.
original-image-bucket-prome
thumbnail-image-bucket-prome
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:PutLogEvents",
"logs:CreateLogGroup",
"logs:CreateLogStream"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": "arn:aws:s3:::*/*"
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject"
],
"Resource": "arn:aws:s3:::*/*"
}
]
}
LambdaS3Policy
로 설정하고, 정책을 생성합니다. 이 정책은 Lambda 함수가 S3 버킷에 접근할 수 있도록 허용합니다.LambdaS3Policy
를 선택하고, 역할 이름을 LambdaS3Role
로 설정 후 역할을 생성합니다.LambdaS3Role
을 선택해야 합니다.
mkdir resize-image
cd resize-image
npm init
sharp
라이브러리를 설치합니다. sharp
는 이미지 리사이징을 위한 라이브러리입니다.npm install --platform=linux --arch=x64 sharp@0.32.6
index.mjs
파일을 생성합니다. 최종 폴더 구조는 다음과 같습니다.📦resize-image
┣ 📂node_modules
┣ 📜index.mjs
┣ 📜package-lock.json
┗ 📜package.json
// dependencies
import { S3Client, GetObjectCommand, PutObjectCommand } from '@aws-sdk/client-s3';
import { Readable } from 'stream';
import sharp from 'sharp';
import util from 'util';
// create S3 client
const s3 = new S3Client({region: 'us-east-1'});
// define the handler function
export const handler = async (event, context) => {
// Read options from the event parameter and get the source bucket
console.log("Reading options from event:\n", util.inspect(event, {depth: 5}));
const srcBucket = event.Records[0].s3.bucket.name;
// Object key may have spaces or unicode non-ASCII characters
const srcKey = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " "));
const dstBucket = srcBucket + "-resized";
const dstKey = "resized-" + srcKey;
// Infer the image type from the file suffix
const typeMatch = srcKey.match(/\.([^.]*)$/);
if (!typeMatch) {
console.log("Could not determine the image type.");
return;
}
// Check that the image type is supported
const imageType = typeMatch[1].toLowerCase();
if (imageType != "jpg" && imageType != "png") {
console.log(`Unsupported image type: ${imageType}`);
return;
}
// Get the image from the source bucket. GetObjectCommand returns a stream.
try {
const params = {
Bucket: srcBucket,
Key: srcKey
};
var response = await s3.send(new GetObjectCommand(params));
var stream = response.Body;
// Convert stream to buffer to pass to sharp resize function.
if (stream instanceof Readable) {
var content_buffer = Buffer.concat(await stream.toArray());
} else {
throw new Error('Unknown object stream type');
}
} catch (error) {
console.log(error);
return;
}
// set thumbnail width. Resize will set the height automatically to maintain aspect ratio.
const width = 200;
// Use the sharp module to resize the image and save in a buffer.
try {
var output_buffer = await sharp(content_buffer).resize(width).toBuffer();
} catch (error) {
console.log(error);
return;
}
// Upload the thumbnail image to the destination bucket
try {
const destparams = {
Bucket: dstBucket,
Key: dstKey,
Body: output_buffer,
ContentType: "image"
};
const putResult = await s3.send(new PutObjectCommand(destparams));
} catch (error) {
console.log(error);
return;
}
console.log('Successfully resized ' + srcBucket + '/' + srcKey +
' and uploaded to ' + dstBucket + '/' + dstKey);
};
original-image-bucket-prome
에 업로드된 이미지를 resized-image-bucket-prome
에 리사이즈하여 저장합니다. 이때, 원본 이미지의 확장자에 따라 리사이즈 후 확장자를 변경합니다. 예를 들어, 원본 이미지가 image.jpg
라면 리사이즈 후 image.webp
로 저장됩니다. 만약 원본 이미지가 이미 webp라면 리사이즈만 진행합니다.
이 코드는 gif 같은 애니메이션 파일도 지원합니다.// dependencies
import {
S3Client,
GetObjectCommand,
PutObjectCommand,
} from "@aws-sdk/client-s3";
import { Readable } from "stream";
import sharp from "sharp";
// create S3 client
const s3 = new S3Client({ region: "ap-northeast-2" });
// define the handler function
export const handler = async (event, context) => {
const srcBucket = event.Records[0].s3.bucket.name;
const srcKey = decodeURIComponent(
event.Records[0].s3.object.key.replace(/\+/g, " ")
);
const dstBucket = "resized-image-bucket-prome"; // 리사이즈된 이미지를 저장할 버킷 이름
const filename = srcKey.split("/").pop(); // 파일명만 추출
const dstKey = `${filename.replace(/\.[^.]+$/, ".webp")}`;
const typeMatch = srcKey.match(/\.([^.]*)$/);
if (!typeMatch) {
return;
}
const imageType = typeMatch[1].toLowerCase();
// WebP 파일은 변환 없이 그대로 복사
if (imageType === "webp") {
try {
const params = {
Bucket: srcBucket,
Key: srcKey,
};
var response = await s3.send(new GetObjectCommand(params));
var stream = response.Body;
if (stream instanceof Readable) {
var content_buffer = Buffer.concat(await stream.toArray());
} else {
throw new Error("알 수 없는 객체 스트림 타입입니다");
}
const destparams = {
Bucket: dstBucket,
Key: dstKey,
Body: content_buffer,
ContentType: "image/webp",
};
await s3.send(new PutObjectCommand(destparams));
return;
} catch (error) {
return;
}
}
try {
const params = {
Bucket: srcBucket,
Key: srcKey,
};
var response = await s3.send(new GetObjectCommand(params));
var stream = response.Body;
if (stream instanceof Readable) {
var content_buffer = Buffer.concat(await stream.toArray());
} else {
throw new Error("알 수 없는 객체 스트림 타입입니다");
}
} catch (error) {
return;
}
const width = 600;
const height = 600;
try {
let sharpInstance = sharp(content_buffer, {
animated: true, // 애니메이션 GIF 지원
pages: -1, // 모든 프레임 처리
}).resize(width, height, {
fit: sharp.fit.inside,
});
var output_buffer = await sharpInstance
.webp({
lossless: false,
animated: true, // 애니메이션 보존
})
.toBuffer();
} catch (error) {
return;
}
try {
const destparams = {
Bucket: dstBucket,
Key: dstKey,
Body: output_buffer,
ContentType: "image/webp",
};
await s3.send(new PutObjectCommand(destparams));
} catch (error) {
return;
}
};
index.mjs
와 node_modules
폴더를 포함하여 zip 파일을 생성합니다. 이때, node_modules
폴더는 반드시 포함되어야 합니다. AWS Lambda는 Node.js 런타임을 사용하므로, 필요한 모든 종속성을 포함해야 합니다.
이렇게 생긴 zip 파일을 AWS Lambda 콘솔로 돌아가서 업로드합니다. "코드" 탭에서 "업로드" 버튼을 클릭하여 zip 파일을 선택합니다. 업로드가 완료되면 Lambda 함수가 생성됩니다.original-image-bucket-prome
버킷에 이미지를 업로드합니다.original-image-bucket-prome
에 원하는 이미지를 업로드하고 테스트 탭으로 이동해 이벤트를 생성해주세요. 다음과 같이 S3 PUT 템플릿을 생성합니다.{
"Records": [
{
"eventVersion": "2.0",
"eventSource": "aws:s3",
"awsRegion": "ap-northeast-2", // 리전
"eventTime": "1970-01-01T00:00:00.000Z",
"eventName": "ObjectCreated:Put",
"userIdentity": {
"principalId": "EXAMPLE"
},
"requestParameters": {
"sourceIPAddress": "127.0.0.1"
},
"responseElements": {
"x-amz-request-id": "EXAMPLE123456789",
"x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"
},
"s3": {
"s3SchemaVersion": "1.0",
"configurationId": "testConfigRule",
"bucket": {
"name": "original-image-bucket-prome", // 사진이 저장된된 버킷 이름
"ownerIdentity": {
"principalId": "EXAMPLE"
},
"arn": "arn:aws:s3:::original-image-bucket-prome" // 사진이 저장된된 버킷 ARN
},
"object": {
"key": "1234.png", // 파일 이름
"size": 1024,
"eTag": "0123456789abcdef0123456789abcdef",
"sequencer": "0A1B2C3D4E5F678901"
}
}
}
]
}
resized-image-bucket-prome
버킷에 리사이즈된 이미지가 저장되어 있는지 확인합니다. 실패했다면 CloudWatch 로그를 확인하여 에러 메시지를 확인합니다.module.exports = {
images: {
unoptimized: true,
},
};