UNPKG

@paroicms/server-image-cache-engine

Version:

The image variant engine that we use at Paroi.

93 lines 3.68 kB
import sharp from "sharp"; import { authorizedMediaTypes } from "./constants.js"; import { sharpQueue } from "./image-processor-setup.js"; import { convertSharpFormatToMediaType, getQuality } from "./internal/resizer.js"; export async function processOriginalImage({ binaryFile, mediaType, ApiError, policy, defaultPolicy, qualityPolicy, }) { const weightB = binaryFile.byteLength; const sharpInst = sharp(binaryFile); const { width, height, format } = await sharpQueue(() => sharpInst.metadata()); if (width === undefined || height === undefined || !format) { throw new Error("cannot get image metadata"); } const foundMediaType = convertSharpFormatToMediaType(format); if (foundMediaType !== mediaType) { throw new ApiError(`mismatch media type '${mediaType}' with '${foundMediaType}'`, 400); } if (!authorizedMediaTypes.has(mediaType)) { throw new ApiError("Invalid image type", 400); } const weightLimitB = policy?.weightLimitB ?? defaultPolicy.weightLimitB; const areaLimitPx = policy?.areaLimitPx ?? defaultPolicy.areaLimitPx; if (mediaType === "image/gif" || mediaType === "image/svg+xml") { if (weightLimitB && weightB > weightLimitB) { throw new ApiError("Image weight exceeds limit", 400); } return { binaryFile, rawWidth: width, rawHeight: height, mediaType, weightB, lossless: undefined, }; } const input = { rawWidth: width, rawHeight: height, mediaType, sharpInst, }; if (mediaType === "image/webp") { if (weightLimitB === undefined || weightB <= weightLimitB) { return { binaryFile, rawWidth: width, rawHeight: height, mediaType, weightB, lossless: undefined, }; } return await convertToWebp({ input, qualityPolicy, areaLimitPx, lossless: false }); } if (mediaType === "image/png") { return await convertToWebp({ input, qualityPolicy, areaLimitPx, // WebP lossless images are 26% smaller in size compared to PNGs // See: https://developers.google.com/speed/webp lossless: weightLimitB === undefined || weightB <= weightLimitB * 1.35, }); } return await convertToWebp({ input, qualityPolicy, areaLimitPx, lossless: false }); } async function convertToWebp({ input, qualityPolicy, areaLimitPx, lossless, }) { const { rawWidth, rawHeight } = areaLimitPx === undefined ? input : computeOriginalSize(input, areaLimitPx); const quality = getQuality({ rawWidth, rawHeight }, qualityPolicy); const { data, info } = await sharpQueue(() => input.sharpInst .resize({ width: rawWidth, height: rawHeight }) .webp({ lossless, quality, }) .toBuffer({ resolveWithObject: true })); return { rawWidth: info.width, rawHeight: info.height, weightB: data.byteLength, mediaType: "image/webp", lossless, binaryFile: data, }; } function computeOriginalSize(input, areaLimitPx) { const inputArea = input.rawWidth * input.rawHeight; if (inputArea <= areaLimitPx) return input; const ratio = input.rawWidth / input.rawHeight; const width = Math.trunc(Math.sqrt(areaLimitPx * ratio)); const height = Math.round((input.rawHeight / input.rawWidth) * width); return { rawWidth: width, rawHeight: height }; } //# sourceMappingURL=original-images-processing.js.map