Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
File size: 1,705 Bytes
fddab62 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
/**
* Applies a mask to an image using canvas blending modes to avoid explicit pixel iteration.
*
* @param image The source image as an HTMLImageElement.
* @param maskCanvas The canvas element containing a mask.
* @returns A new Promise resolving to a headless canvas element containing the masked image.
*/
export async function filterImage(
image?: HTMLImageElement,
maskCanvas?: HTMLCanvasElement
): Promise<HTMLCanvasElement> {
return new Promise((resolve, reject) => {
// Create a new canvas to construct the final image
const resultCanvas = document.createElement("canvas");
if (!image) {
// reject(`missing image (must be a HTMLImageElement)`)
resolve(resultCanvas)
return
}
resultCanvas.width = image.width;
resultCanvas.height = image.height;
if (!maskCanvas) {
// reject(`missing image (must be a HTMLImageElement)`)
resolve(resultCanvas)
return
}
const ctx = resultCanvas.getContext("2d");
if (!ctx) {
reject(new Error("Failed to get 2D context"));
return;
}
// Draw the original image
ctx.drawImage(image, 0, 0, image.width, image.height);
// Set blending mode to 'destination-in' to keep only the content that overlaps the mask
ctx.globalCompositeOperation = "destination-in";
ctx.drawImage(maskCanvas, 0, 0, image.width, image.height);
// Reset composite operation to default
ctx.globalCompositeOperation = "source-over";
// Draw white rectangle where the mask is opaque
ctx.globalCompositeOperation = "destination-over";
ctx.fillStyle = "white";
ctx.fillRect(0, 0, image.width, image.height);
resolve(resultCanvas);
});
} |