Ops/AWS
AWS Lambda Code - 이미지 리사이징 (feat. cloudfront)
mkdir.chandler
2023. 11. 28. 00:00
반응형
AWS Lambda Code - 이미지 리사이징 (feat. cloudfront)
const imagemin = require("imagemin");
const imageminGiflossy = require("imagemin-giflossy");
const fsPromise = require("fs").promises;
const querystring = require("querystring");
const Sharp = require("sharp");
const AWS = require("aws-sdk");
const S3 = new AWS.S3({ region: "us-east-2" });
const BUCKET = {
test1: "s3-ue2-test1",
test2: "s3-ue2-test2",
test3: "s3-ue2-test3",
};
const LAMBDA_TIMEOUT_IN_MILLI_SECONDS = 25000;
const allowedTransformExtensions = {
jpg: ["webp"],
jpeg: ["webp"],
png: ["webp"],
gif: ["webp"],
};
function isNumeric(value) {
return /^-?\d+$/.test(value);
}
exports.handler = async (event, context, callback) => {
const request = event.Records[0].cf.request;
let timeoutId;
let targetBucketName;
try {
for (const bucketName in BUCKET) {
if (request.uri.startsWith(`/${bucketName}/`)) {
targetBucketName = BUCKET[bucketName];
break;
}
}
if (!targetBucketName) {
callback(null, request);
console.log(
"Target bucket not exists, pass to original file : ",
request.uri
);
return;
}
const [, originalFileName, originalExtension] = request.uri.match(
/\/(.*)\.(.*)/
);
const params = querystring.parse(request.querystring);
let targetWidth = params.w;
let targetExtension = params.f;
console.log("input target Width / Extension", targetWidth, targetExtension);
if (!targetWidth && !targetExtension) {
callback(null, request);
console.log(
"Target width & extension not exists, pass to original file : ",
request.uri
);
return;
}
if (!allowedTransformExtensions[originalExtension.toLowerCase()]) {
callback(null, request);
console.log(
"Not allowed extension for resizing, pass to original file : " +
originalExtension.toLowerCase()
);
return;
}
if (targetWidth && !isNumeric(targetWidth)) {
console.log("ERROR : Width should be number or not exists");
return;
}
targetWidth = targetWidth ? parseInt(targetWidth) : undefined;
console.log("Target width in number format : " + targetWidth);
if (
targetExtension &&
!allowedTransformExtensions[originalExtension.toLowerCase()].includes(
targetExtension
)
) {
console.log("ERROR : Not allowed target format");
return;
}
/* Input Validation END */
timeoutId = setTimeout(() => {
console.log(`${LAMBDA_TIMEOUT_IN_MILLI_SECONDS} ms Timeout for resizing`);
return callback(null, request);
}, LAMBDA_TIMEOUT_IN_MILLI_SECONDS);
targetExtension = targetExtension ?? originalExtension.toLowerCase();
targetExtension = targetExtension === "jpg" ? "jpeg" : targetExtension;
console.log("TargetExtension for work " + targetExtension);
const resizedTargetFileName = `${originalFileName}__resizedByCFLE__${originalExtension}_${
targetWidth ?? "originalWidth"
}.${targetExtension}`;
try {
const s3HeadObject = await S3.headObject({
Bucket: targetBucketName,
Key: resizedTargetFileName,
}).promise();
console.log("Resized File Content-Length", s3HeadObject.ContentLength);
if (s3HeadObject) {
console.log("Resized file exists in bucket : ", resizedTargetFileName);
request.uri = "/" + resizedTargetFileName;
clearTimeout(timeoutId);
callback(null, request);
return;
}
} catch (error) {
console.log(
"Resized file not exists, process goes on : ",
resizedTargetFileName
);
}
const s3OriginalObject = await S3.getObject({
Bucket: targetBucketName,
Key: originalFileName + "." + originalExtension,
}).promise();
console.log("Original File", originalFileName + "." + originalExtension);
console.log("Original File Content-Length", s3OriginalObject.ContentLength);
let resizedImage = "";
let resizedImageTmp = "";
const originalImage = await Sharp(s3OriginalObject.Body);
const originalFileMetadata = await originalImage.metadata();
if (targetWidth >= originalFileMetadata.width) {
console.log(
"Target width is larger than original width, pass to original file"
);
clearTimeout(timeoutId);
callback(null, request);
return;
}
if (["jpeg", "webp", "png"].includes(targetExtension)) {
console.log("Start resizing jpeg, webp, png");
resizedImage = await originalImage
.resize({
width: targetWidth,
withoutEnlargement: true,
})
.toFormat(targetExtension)
.toBuffer();
console.log("Resize complete");
} else if (targetExtension === "gif") {
console.log("Start resizing gif");
const targetHeight = Number.parseInt(
(targetWidth * originalFileMetadata.height) / originalFileMetadata.width
);
await fsPromise.writeFile("/tmp/resizedImg.gif", s3OriginalObject.Body);
console.log(
"TargetWidth / TargetHeight for gif : ",
targetWidth,
targetHeight
);
resizedImageTmp = await imagemin(["/tmp/resizedImg.gif"], {
plugins: [
imageminGiflossy({ resize: `${targetWidth}x${targetHeight}` }),
],
});
resizedImage = resizedImageTmp[0].data;
}
await S3.putObject({
Body: resizedImage,
Bucket: targetBucketName,
ContentType: "image/" + targetExtension,
Key: resizedTargetFileName,
StorageClass: "STANDARD",
}).promise();
console.log("New file uploaded " + resizedTargetFileName);
request.uri = "/" + resizedTargetFileName;
clearTimeout(timeoutId);
callback(null, request);
return;
} catch (error) {
console.log("Error, pass with original request : " + request.uri, error);
if (timeoutId) clearTimeout(timeoutId);
callback(null, request);
return;
}
};
by mkdir-chandler
728x90
반응형