44 lines
1.8 KiB
TypeScript
44 lines
1.8 KiB
TypeScript
|
|
export const applyMask = (originalImageUrl: string, maskDataUrl: string): Promise<string> => {
|
|
return new Promise((resolve, reject) => {
|
|
const canvas = document.createElement('canvas');
|
|
const ctx = canvas.getContext('2d');
|
|
if (!ctx) return reject(new Error('Could not get canvas context'));
|
|
|
|
const original = new Image();
|
|
original.crossOrigin = 'anonymous';
|
|
const mask = new Image();
|
|
mask.crossOrigin = 'anonymous';
|
|
|
|
let loadedImages = 0;
|
|
const onImageLoad = () => {
|
|
loadedImages++;
|
|
if (loadedImages === 2) {
|
|
canvas.width = original.naturalWidth;
|
|
canvas.height = original.naturalHeight;
|
|
|
|
// Draw the original image
|
|
ctx.drawImage(original, 0, 0);
|
|
|
|
// Use 'destination-in' to keep the parts of the original image
|
|
// that overlap with the non-transparent parts of the mask.
|
|
// The mask should have white for the subject and black for the background.
|
|
// For destination-in, any non-transparent part of the mask will be kept.
|
|
ctx.globalCompositeOperation = 'destination-in';
|
|
ctx.drawImage(mask, 0, 0);
|
|
|
|
// Return base64 data of the resulting image (PNG for transparency)
|
|
resolve(canvas.toDataURL('image/png').split(',')[1]);
|
|
}
|
|
};
|
|
|
|
original.onload = onImageLoad;
|
|
mask.onload = onImageLoad;
|
|
original.onerror = () => reject(new Error('Failed to load original image.'));
|
|
mask.onerror = () => reject(new Error('Failed to load mask image.'));
|
|
|
|
original.src = originalImageUrl;
|
|
mask.src = maskDataUrl;
|
|
});
|
|
};
|