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)
/**
* 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)
}
}
Top comments (1)
What's a Clipping Mask? How to Put a Picture Inside Text or Graphics ? Spell to break two people up