fix(wp7-02): normalize generated image dimensions
Dada P0-A isolated Windows CI / validate-and-package (push) Failing after 2m17s
Dada P0-A isolated Windows CI / validate-and-package (push) Failing after 2m17s
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
import sharp from "sharp";
|
||||
|
||||
const productDimensions = Object.freeze({
|
||||
"3:4": Object.freeze({ pixelHeight: 1440, pixelWidth: 1080 }),
|
||||
"1:1": Object.freeze({ pixelHeight: 1080, pixelWidth: 1080 }),
|
||||
"4:3": Object.freeze({ pixelHeight: 1080, pixelWidth: 1440 }),
|
||||
"9:16": Object.freeze({ pixelHeight: 1920, pixelWidth: 1080 }),
|
||||
});
|
||||
|
||||
const gptImageRequestSizes = Object.freeze({
|
||||
"3:4": "1056x1408",
|
||||
"1:1": "1088x1088",
|
||||
"4:3": "1408x1056",
|
||||
"9:16": "1008x1792",
|
||||
});
|
||||
|
||||
const allowedMimeTypes = new Set(["image/jpeg", "image/png", "image/webp"]);
|
||||
const maximumInputBytes = 20 * 1024 * 1024;
|
||||
|
||||
function assertRatio(ratio) {
|
||||
if (!(ratio in productDimensions)) throw new Error("image_output_ratio_unsupported");
|
||||
return ratio;
|
||||
}
|
||||
|
||||
export function productDimensionsForRatio(ratio) {
|
||||
return { ...productDimensions[assertRatio(ratio)] };
|
||||
}
|
||||
|
||||
export function gptImageRequestSizeForRatio(ratio) {
|
||||
return gptImageRequestSizes[assertRatio(ratio)];
|
||||
}
|
||||
|
||||
export async function normalizeImageOutputToRatio(input) {
|
||||
const ratio = assertRatio(input?.ratio);
|
||||
if (!Buffer.isBuffer(input?.bytes) || input.bytes.length === 0 || input.bytes.length > maximumInputBytes
|
||||
|| !allowedMimeTypes.has(input?.mimeType)) {
|
||||
throw new Error("image_output_media_invalid");
|
||||
}
|
||||
const target = productDimensions[ratio];
|
||||
if (input.pixelWidth === target.pixelWidth && input.pixelHeight === target.pixelHeight) {
|
||||
return {
|
||||
bytes: Buffer.from(input.bytes),
|
||||
mimeType: input.mimeType,
|
||||
normalized: false,
|
||||
...target,
|
||||
upstreamPixelHeight: input.pixelHeight,
|
||||
upstreamPixelWidth: input.pixelWidth,
|
||||
};
|
||||
}
|
||||
|
||||
const image = sharp(input.bytes, { failOn: "error", limitInputPixels: 40_000_000 });
|
||||
const metadata = await image.metadata();
|
||||
if (!metadata.width || !metadata.height) throw new Error("image_output_dimensions_missing");
|
||||
const requestedRatio = target.pixelWidth / target.pixelHeight;
|
||||
const upstreamRatio = metadata.width / metadata.height;
|
||||
if (Math.abs(upstreamRatio - requestedRatio) / requestedRatio > 0.02) {
|
||||
throw new Error("image_output_aspect_ratio_mismatch");
|
||||
}
|
||||
const { data, info } = await image
|
||||
.resize(target.pixelWidth, target.pixelHeight, { fit: "fill", kernel: sharp.kernel.lanczos3 })
|
||||
.png({ compressionLevel: 9 })
|
||||
.toBuffer({ resolveWithObject: true });
|
||||
if (info.width !== target.pixelWidth || info.height !== target.pixelHeight || info.format !== "png") {
|
||||
throw new Error("image_output_normalization_failed");
|
||||
}
|
||||
return {
|
||||
bytes: data,
|
||||
mimeType: "image/png",
|
||||
normalized: true,
|
||||
...target,
|
||||
upstreamPixelHeight: metadata.height,
|
||||
upstreamPixelWidth: metadata.width,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user