in source/image-handler/image-request.ts [29:95]
public async setup(event: ImageHandlerEvent): Promise<ImageRequestInfo> {
try {
await this.validateRequestSignature(event);
let imageRequestInfo: ImageRequestInfo = <ImageRequestInfo>{};
imageRequestInfo.requestType = this.parseRequestType(event);
imageRequestInfo.bucket = this.parseImageBucket(event, imageRequestInfo.requestType);
imageRequestInfo.key = this.parseImageKey(event, imageRequestInfo.requestType);
imageRequestInfo.edits = this.parseImageEdits(event, imageRequestInfo.requestType);
const originalImage = await this.getOriginalImage(imageRequestInfo.bucket, imageRequestInfo.key);
imageRequestInfo = { ...imageRequestInfo, ...originalImage };
imageRequestInfo.headers = this.parseImageHeaders(event, imageRequestInfo.requestType);
// If the original image is SVG file and it has any edits but no output format, change the format to WebP.
if (imageRequestInfo.contentType === 'image/svg+xml' && imageRequestInfo.edits && Object.keys(imageRequestInfo.edits).length > 0 && !imageRequestInfo.edits.toFormat) {
imageRequestInfo.outputFormat = ImageFormatTypes.PNG;
}
/* Decide the output format of the image.
* 1) If the format is provided, the output format is the provided format.
* 2) If headers contain "Accept: image/webp", the output format is webp.
* 3) Use the default image format for the rest of cases.
*/
if (imageRequestInfo.contentType !== 'image/svg+xml' || imageRequestInfo.edits.toFormat || imageRequestInfo.outputFormat) {
const outputFormat = this.getOutputFormat(event, imageRequestInfo.requestType);
// if webp check reduction effort, if invalid value, use 4 (default in sharp)
if (outputFormat === ImageFormatTypes.WEBP && imageRequestInfo.requestType === RequestTypes.DEFAULT) {
const decoded = this.decodeRequest(event);
if (typeof decoded.reductionEffort !== 'undefined') {
const reductionEffort = Math.trunc(decoded.reductionEffort);
const isValid = !isNaN(reductionEffort) && reductionEffort >= 0 && reductionEffort <= 6;
imageRequestInfo.reductionEffort = isValid ? reductionEffort : ImageRequest.DEFAULT_REDUCTION_EFFORT;
}
}
if (imageRequestInfo.edits && imageRequestInfo.edits.toFormat) {
imageRequestInfo.outputFormat = imageRequestInfo.edits.toFormat;
} else if (outputFormat) {
imageRequestInfo.outputFormat = outputFormat;
}
}
// Fix quality for Thumbor and Custom request type if outputFormat is different from quality type.
if (imageRequestInfo.outputFormat) {
const requestType = [RequestTypes.CUSTOM, RequestTypes.THUMBOR];
const acceptedValues = [ImageFormatTypes.JPEG, ImageFormatTypes.PNG, ImageFormatTypes.WEBP, ImageFormatTypes.TIFF, ImageFormatTypes.HEIF];
imageRequestInfo.contentType = `image/${imageRequestInfo.outputFormat}`;
if (requestType.includes(imageRequestInfo.requestType) && acceptedValues.includes(imageRequestInfo.outputFormat)) {
const qualityKey = Object.keys(imageRequestInfo.edits).filter(key => acceptedValues.includes(key as ImageFormatTypes))[0];
if (qualityKey && qualityKey !== imageRequestInfo.outputFormat) {
imageRequestInfo.edits[imageRequestInfo.outputFormat] = imageRequestInfo.edits[qualityKey];
delete imageRequestInfo.edits[qualityKey];
}
}
}
return imageRequestInfo;
} catch (error) {
console.error(error);
throw error;
}
}