aws-samples / image-optimization

Simple, performant and cost efficient solution for optimizing images using Amazon CloudFront, Amazon S3 and AWS Lambda
MIT No Attribution
195 stars 116 forks source link

When request svg file without format; content-type got wrong #48

Closed yunhaoww closed 3 months ago

yunhaoww commented 3 months ago

when we request svg image directly

what will be executed with sharp are:

const getOriginalImageCommand = new GetObjectCommand({ Bucket: S3_ORIGINAL_IMAGE_BUCKET, Key: originalImagePath });
const getOriginalImageCommandOutput = await s3Client.send(getOriginalImageCommand);

originalImageBody = getOriginalImageCommandOutput.Body.transformToByteArray();
contentType = getOriginalImageCommandOutput.ContentType;

let transformedImage = Sharp(await originalImageBody, { failOn: 'none', animated: true });
transformedImage = await transformedImage.toBuffer();

const putImageCommand = new PutObjectCommand({
    Body: transformedImage,
    Bucket: S3_TRANSFORMED_IMAGE_BUCKET,
    Key: originalImagePath + '/' + operationsPrefix,
    ContentType: contentType,
    Metadata: {
        'cache-control': TRANSFORMED_IMAGE_CACHE_TTL,
    },
})

content-type keep as "image/svg+xml" which differs from the docs

If no explicit format is set, the output format will match the input image, except SVG input which becomes PNG output.

which result a wrong image render from browser

achrafsouk commented 3 months ago

So should I add the below check, if the there is no format operation, and the source format is svg, then change the output format to png. Can you try it?

        if (operationsJSON['format']) {
            var isLossy = false;
            switch (operationsJSON['format']) {
                case 'jpeg': contentType = 'image/jpeg'; isLossy = true; break;
                case 'gif': contentType = 'image/gif'; break;
                case 'webp': contentType = 'image/webp'; isLossy = true; break;
                case 'png': contentType = 'image/png'; break;
                case 'avif': contentType = 'image/avif'; isLossy = true; break;
                default: contentType = 'image/jpeg'; isLossy = true;
            }
            if (operationsJSON['quality'] && isLossy) {
                transformedImage = transformedImage.toFormat(operationsJSON['format'], {
                    quality: parseInt(operationsJSON['quality']),
                });
            } else transformedImage = transformedImage.toFormat(operationsJSON['format']);
        } else {
                if (contentType = 'image/svg+xml') contentType = 'image/png';
        }
yunhaoww commented 3 months ago

@achrafsouk Thank you achrafsouk. Already used in my work; works ok

achrafsouk commented 3 months ago

thank you, will update the code