DEV Community 👩‍💻👨‍💻

Cover image for How to apply a mask into a portrait with canvas
Arno Solo
Arno Solo

Posted on

How to apply a mask into a portrait with canvas

You see, photo contains a lot pixels, and each pixel contains 4 values: r: RED, g: GREEN, b: BLUE, a: ALPHA or opacity. What we need is set the alpha value of original photo as the average of r g b value of mask photo.

    const maskedImageBase64 = await maskPhoto(maskPhotoUrl, originalPhotoUrl)
Enter fullscreen mode Exit fullscreen mode
/**
 * Url to HTMLImageElement
 * @param {string} url: image url
 * @returns {Promise<HTMLImageElement>} HTMLImageElement
 */
export function urlToImageElement(url: string) {
  return new Promise<HTMLImageElement>((resolve, reject) => {
    const img = new Image()
    img.crossOrigin = "anonymous";
    img.src = url
    img.onload = () => resolve(img)
    img.onerror = reject
  })
}

/**
 * mask.jpg + original.jpg => masked.jpg
 * @param {string} maskImageUrl: mask image url
 * @param {string} originalImageUrl: original image url
 * @returns {Promise<string | undefined>} masked image url(base64)
 */
export async function maskPhoto(maskImageUrl:string, originalImageUrl:string) {
  try {
    const maskImage = await urlToImageElement(maskImageUrl)
    const originalImage = await urlToImageElement(originalImageUrl)
    const canvas = document.createElement('canvas')
    if (canvas) {
      canvas.width = originalImage.width
      canvas.height = originalImage.height
      const ctx = canvas.getContext('2d')
      if (ctx) {
        ctx.drawImage(maskImage, 0, 0, canvas.width, canvas.height)
        const maskImagedata = ctx.getImageData(0, 0, canvas.width, canvas.height)
        ctx.drawImage(originalImage, 0, 0, canvas.width, canvas.height)
        const originalImagedata = ctx.getImageData(0, 0, canvas.width, canvas.height)
        for (let i = 0; i < maskImagedata.data.length; i += 4) {
          const alpha = (maskImagedata.data[i] + maskImagedata.data[i+1] + maskImagedata.data[i+2]) / 3
          originalImagedata.data[i+3] = alpha;
        }
        ctx.putImageData(originalImagedata, 0, 0);
        return canvas.toDataURL()
      }
    }
  } catch (error) {
    console.error(error)
  }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
cherylyazzie profile image
CherylYazzie

What's a Clipping Mask? How to Put a Picture Inside Text or Graphics ? Spell to break two people up

🌚 Life is too short to browse without dark mode