Files

88 lines
2.3 KiB
TypeScript

export type Area = {
x: number;
y: number;
width: number;
height: number;
};
function loadImage(src: string): Promise<HTMLImageElement> {
return new Promise((resolve, reject) => {
const image = new Image();
image.addEventListener("load", () => resolve(image));
image.addEventListener("error", (error) => reject(error));
image.crossOrigin = "anonymous";
image.src = src;
});
}
/**
* Crop that may extend outside the source image.
* Outside pixels stay transparent (PNG) or fillColor (JPEG).
*/
export async function getCroppedImageFile(
imageSrc: string,
pixelCrop: Area,
fileName: string,
mimeType = "image/jpeg",
quality = 0.92,
fillColor = "#ffffff",
): Promise<File> {
const image = await loadImage(imageSrc);
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
if (!ctx) throw new Error("Could not crop image.");
const outputWidth = Math.max(1, Math.round(pixelCrop.width));
const outputHeight = Math.max(1, Math.round(pixelCrop.height));
canvas.width = outputWidth;
canvas.height = outputHeight;
if (mimeType !== "image/png") {
ctx.fillStyle = fillColor;
ctx.fillRect(0, 0, outputWidth, outputHeight);
} else {
ctx.clearRect(0, 0, outputWidth, outputHeight);
}
const srcX = Math.max(0, pixelCrop.x);
const srcY = Math.max(0, pixelCrop.y);
const srcRight = Math.min(image.naturalWidth, pixelCrop.x + pixelCrop.width);
const srcBottom = Math.min(
image.naturalHeight,
pixelCrop.y + pixelCrop.height,
);
const srcWidth = srcRight - srcX;
const srcHeight = srcBottom - srcY;
if (srcWidth > 0 && srcHeight > 0) {
const destX = Math.round(srcX - pixelCrop.x);
const destY = Math.round(srcY - pixelCrop.y);
ctx.drawImage(
image,
srcX,
srcY,
srcWidth,
srcHeight,
destX,
destY,
srcWidth,
srcHeight,
);
}
const blob = await new Promise<Blob>((resolve, reject) => {
canvas.toBlob(
(result) => {
if (result) resolve(result);
else reject(new Error("Could not export cropped image."));
},
mimeType,
quality,
);
});
const base = fileName.replace(/\.[^.]+$/, "") || "image";
const extension = mimeType === "image/png" ? "png" : "jpg";
return new File([blob], `${base}-cropped.${extension}`, { type: mimeType });
}