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);
  });
}