Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lambda to allow gif types #1143

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 5 additions & 8 deletions cdk/lambdas/avatarResize/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ exports.handler = async (event) => {
const bucket = event.Records[0].s3.bucket.name;
const key = event.Records[0].s3.object.key;

console.log({ bucket, key });

try {
// Check if the image has already been resized
const headParams = {
Expand All @@ -21,10 +19,10 @@ exports.handler = async (event) => {
};

const headResponse = await s3.send(new HeadObjectCommand(headParams));
const metadata = headResponse.Metadata || {};
const s3Metadata = headResponse.Metadata || {};
const contentType = headResponse.ContentType;

if (metadata.resized === "true") {
if (s3Metadata.resized === "true") {
return {
statusCode: 200,
body: JSON.stringify({ message: "Image already resized. Skipping." }),
Expand All @@ -39,14 +37,13 @@ exports.handler = async (event) => {

const response = await s3.send(new GetObjectCommand(getParams));
const stream = response.Body;
console.log({ response, stream });

if (!stream) throw new Error("BodyStream is empty");

const imageBuffer = Buffer.concat(await stream.toArray());
const sharpImage = sharp(imageBuffer);

// Resize the image
const resizedImageBuffer = await sharpImage
const resizedImageBuffer = await sharp(imageBuffer)
.resize({ width: 220, height: 220, fit: "cover" })
.toBuffer();

Expand All @@ -56,7 +53,7 @@ exports.handler = async (event) => {
Bucket: bucket,
Key: key,
Body: resizedImageBuffer,
Metadata: { ...metadata, resized: "true" },
Metadata: { ...s3Metadata, resized: "true" },
ContentType: contentType,
}),
);
Expand Down
28 changes: 22 additions & 6 deletions cdk/lambdas/uploadResize/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,32 +61,48 @@ exports.handler = async (event) => {

const imageRaw = Buffer.concat(await stream.toArray());

// Determine the image format
const imageMetadata = await sharp(imageRaw).metadata();
const isGif = imageMetadata.format === "gif";

// Function to resize an image
const resizeImage = async (buffer, size) => {
return sharp(buffer)
.resize({
try {
const resizedImage = sharp(buffer).resize({
width: size.maxWidth,
height: size.maxHeight,
fit: "inside",
withoutEnlargement: false,
})
.webp({ quality: 80 })
.toBuffer();
});

if (isGif) {
return resizedImage.gif().toBuffer();
} else {
return resizedImage.webp({ quality: 80 }).toBuffer();
}
} catch (error) {
console.error(`Error resizing image to ${size.maxWidth}x${size.maxHeight}:`, error);
throw error;
}
};

// Loop through sizes and upload each resized image
for (const size of sizes) {
const resizedImage = await resizeImage(imageRaw, size);

const resizedKey = size.suffix
? key.replace(/(\.[\w\d_-]+)$/i, `_${size.suffix}$1`)
? key.replace(
/(\.[\w\d_-]+)$/i,
`_${size.suffix}${isGif ? ".gif" : ".webp"}`,
)
Comment on lines +94 to +97
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Use the Node.js path module for reliable file extension handling.

The regular expression used to replace the file extension may not handle all possible file names correctly, such as those without an extension or with multiple dots in their names. Using the built-in path module provides a more robust solution for handling file paths and extensions.

Modify your code to use the path module:

+const path = require("path");
...
 const resizedKey = size.suffix
   ? key.replace(
-      /(\.[\w\d_-]+)$/i,
-      `_${size.suffix}${isGif ? ".gif" : ".webp"}`,
+      path.extname(key),
+      `_${size.suffix}${isGif ? ".gif" : ".webp"}`
     )
   : key;

This change ensures that the file extension is accurately identified and replaced, regardless of the file name format.

Committable suggestion was skipped due to low confidence.

: key;

await s3.send(
new PutObjectCommand({
Bucket: bucket,
Key: resizedKey,
Body: resizedImage,
ContentType: isGif ? "image/gif" : "image/webp",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Set appropriate Content-Encoding header for WebP images.

When serving WebP images, it's beneficial to include the Content-Encoding header to ensure proper handling by clients and proxies that support WebP compression.

Modify the PutObjectCommand parameters:

 await s3.send(
   new PutObjectCommand({
     Bucket: bucket,
     Key: resizedKey,
     Body: resizedImage,
     ContentType: isGif ? "image/gif" : "image/webp",
+    ContentEncoding: isGif ? undefined : "webp",
   }),
 );

This addition helps improve compatibility and performance with clients that support WebP.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ContentType: isGif ? "image/gif" : "image/webp",
ContentType: isGif ? "image/gif" : "image/webp",
ContentEncoding: isGif ? undefined : "webp",

🛠️ Refactor suggestion

Set the correct Cache-Control header for optimized content delivery.

Setting appropriate cache headers can improve the performance of your application by enabling clients and intermediaries to cache the resized images. This reduces load on your server and decreases image load times for users.

Add the CacheControl parameter to your PutObjectCommand:

 await s3.send(
   new PutObjectCommand({
     Bucket: bucket,
     Key: resizedKey,
     Body: resizedImage,
     ContentType: isGif ? "image/gif" : "image/webp",
+    CacheControl: "max-age=31536000, public",
   }),
 );

This sets the cache to expire after one year (31536000 seconds), which is appropriate for versioned files that won't change.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ContentType: isGif ? "image/gif" : "image/webp",
ContentType: isGif ? "image/gif" : "image/webp",
CacheControl: "max-age=31536000, public",

}),
);
}
Expand Down
Loading