Please bookmark this page to avoid losing your image tool!

Image Heart Eyes Effects Adder

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
You can edit the below JavaScript code to customize the image tool.
async function processImage(originalImg, heartColor = '#FF0000', heartOpacity = 0.85) {

    /**
     * Dynamically loads the face-api.js script and required models.
     * Uses a global promise to ensure the script is loaded and initialized only once.
     * @returns {Promise<void>} A promise that resolves when the library is ready.
     */
    const loadFaceApi = () => {
        if (!window.faceApiPromise) {
            window.faceApiPromise = new Promise((resolve, reject) => {
                const SCRIPT_URL = 'https://cdn.jsdelivr.net/npm/@vladmandic/face-api@1.7.9/dist/face-api.min.js';
                
                // Avoid re-adding the script if it's already in the DOM
                if (document.querySelector(`script[src="${SCRIPT_URL}"]`)) {
                    // Script tag exists, need to check if faceapi is ready
                    const checkInterval = setInterval(() => {
                        if (window.faceapi && window.faceapi.nets.tinyFaceDetector.isLoaded) {
                            clearInterval(checkInterval);
                            resolve();
                        }
                    }, 100);
                    return;
                }

                const script = document.createElement('script');
                script.src = SCRIPT_URL;
                script.async = true;
                
                script.onload = async () => {
                    try {
                        const MODEL_URL = 'https://cdn.jsdelivr.net/npm/@vladmandic/face-api@1.7.9/model';
                        await window.faceapi.nets.tinyFaceDetector.loadFromUri(MODEL_URL);
                        await window.faceapi.nets.faceLandmark68TinyNet.loadFromUri(MODEL_URL);
                        resolve();
                    } catch (error) {
                        console.error('Error loading face-api models:', error);
                        reject(error);
                    }
                };
                
                script.onerror = (error) => {
                    console.error('Error loading face-api.js script:', error);
                    reject(new Error('Failed to load face-api.js script.'));
                };
                
                document.head.append(script);
            });
        }
        return window.faceApiPromise;
    };

    /**
     * Draws a heart shape centered at (0, 0) to be used with canvas transforms.
     * @param {CanvasRenderingContext2D} ctx - The canvas rendering context.
     * @param {number} size - The overall size of the heart.
     */
    const drawHeartShape = (ctx, size) => {
        const s = size; // Use size directly for width/height
        ctx.beginPath();
        // Move to the bottom point of the heart
        ctx.moveTo(0, s / 2);
        // Left curve
        ctx.bezierCurveTo(s / 4, s / 4, s / 2, -s / 4, 0, -s / 2);
        // Right curve
        ctx.bezierCurveTo(-s / 2, -s / 4, -s / 4, s / 4, 0, s / 2);
        ctx.closePath();
    };
    
    /**
     * Parses a hex color string and returns RGB components and a darker stroke style.
     * @param {string} hex - The hex color string (e.g., '#FF0000').
     * @returns {object} An object with r, g, b values and a strokeStyle string.
     */
    const parseColor = (hex) => {
        const r = parseInt(hex.slice(1, 3), 16);
        const g = parseInt(hex.slice(3, 5), 16);
        const b = parseInt(hex.slice(5, 7), 16);
        const darkR = Math.floor(r * 0.75);
        const darkG = Math.floor(g * 0.75);
        const darkB = Math.floor(b * 0.75);
        return { r, g, b, strokeStyle: `rgb(${darkR}, ${darkG}, ${darkB})` };
    };

    // 1. Set up the canvas
    const canvas = document.createElement('canvas');
    canvas.width = originalImg.naturalWidth;
    canvas.height = originalImg.naturalHeight;
    const ctx = canvas.getContext('2d');
    ctx.drawImage(originalImg, 0, 0);

    try {
        // 2. Load face detection library and models
        await loadFaceApi();

        // 3. Detect all faces and their landmarks in the image
        const detections = await window.faceapi.detectAllFaces(originalImg, new window.faceapi.TinyFaceDetectorOptions()).withFaceLandmarks(true);

        if (!detections.length) {
            console.warn("Could not detect any faces in the image.");
            return canvas; // Return original image if no faces are found
        }
        
        const color = parseColor(heartColor);
        ctx.fillStyle = `rgba(${color.r}, ${color.g}, ${color.b}, ${heartOpacity})`;
        ctx.strokeStyle = color.strokeStyle;

        // 4. Iterate over each detected face to draw hearts on the eyes
        detections.forEach(detection => {
            const landmarks = detection.landmarks;
            
            const drawHeartOnEye = (eyePoints) => {
                // Calculate the center of the eye by averaging the points
                const eyeCenter = eyePoints.reduce((acc, p) => ({ x: acc.x + p.x, y: acc.y + p.y }), { x: 0, y: 0 });
                eyeCenter.x /= eyePoints.length;
                eyeCenter.y /= eyePoints.length;

                // Calculate eye width and add padding for heart size
                const eyeWidth = Math.hypot(eyePoints[3].x - eyePoints[0].x, eyePoints[3].y - eyePoints[0].y) * 1.9;

                // Calculate the angle of the eye
                const eyeAngle = Math.atan2(eyePoints[3].y - eyePoints[0].y, eyePoints[3].x - eyePoints[0].x);

                // Draw the heart shape
                ctx.save();
                ctx.translate(eyeCenter.x, eyeCenter.y);
                ctx.rotate(eyeAngle);
                
                ctx.lineWidth = eyeWidth / 12; // Make stroke proportional to the heart size
                drawHeartShape(ctx, eyeWidth);
                
                ctx.fill();
                ctx.stroke();
                ctx.restore();
            };

            drawHeartOnEye(landmarks.getLeftEye());
            drawHeartOnEye(landmarks.getRightEye());
        });

    } catch (error) {
        console.error("Failed to apply heart eyes effect due to an error:", error);
        // In case of an error (e.g., script fails to load), the original image on the canvas is still returned.
    }
    
    return canvas;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

The Image Heart Eyes Effects Adder is a web tool designed to enhance images by adding heart-shaped overlays to the eyes of detected faces. This tool utilizes advanced face detection technology to identify facial landmarks, ensuring that heart effects are accurately placed on the eyes. Users can customize the color and opacity of the hearts to suit their preferences. This tool can be useful for creating fun and engaging images for social media posts, personalized gifts, or artistic projects where a playful touch is desired.

Leave a Reply

Your email address will not be published. Required fields are marked *