Please bookmark this page to avoid losing your image tool!

Hair Shape And Style Visualizer

(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.
function processImage(
    originalImg, 
    style = 'long', 
    color = '#2E1A11', 
    volume = 100, 
    faceCenterX = 50, 
    faceCenterY = 40, 
    faceWidth = 22
) {
    // Determine canvas dimensions
    const width = originalImg.naturalWidth || originalImg.width;
    const height = originalImg.naturalHeight || originalImg.height;

    // Create the main canvas and draw the original image
    const mainCanvas = document.createElement('canvas');
    mainCanvas.width = width;
    mainCanvas.height = height;
    const ctx = mainCanvas.getContext('2d');
    ctx.drawImage(originalImg, 0, 0, width, height);

    // Calculate face bounding box based on percentage parameters
    const cx = width * (faceCenterX / 100);
    const cy = height * (faceCenterY / 100);
    const fw = width * (faceWidth / 100);
    const fh = fw * 1.35; // Standard human face aspect ratio

    const rX = fw / 2;
    const rY = fh / 2;
    const vol = volume / 100;
    
    // Create a temporary canvas to draw and mask the hair
    const hairCanvas = document.createElement('canvas');
    hairCanvas.width = width;
    hairCanvas.height = height;
    const hCtx = hairCanvas.getContext('2d');

    // Configure brush settings for hair
    hCtx.fillStyle = color;
    hCtx.strokeStyle = color;
    hCtx.lineJoin = 'round';
    hCtx.lineCap = 'round';

    style = style.toLowerCase();
    const validStyles = ['bob', 'long', 'spiky', 'curly'];
    if (!validStyles.includes(style)) style = 'long';

    if (style === 'bob') {
        // Main mass of bob cut
        hCtx.beginPath();
        hCtx.ellipse(cx, cy - rY * 0.1, rX * 1.6 * vol, rY * 1.5 * vol, 0, 0, Math.PI * 2);
        hCtx.fill();

        // Subtractive cutout for the face
        hCtx.globalCompositeOperation = 'destination-out';
        hCtx.beginPath();
        hCtx.ellipse(cx, cy + rY * 0.1, rX * 0.95, rY * 1.05, 0, 0, Math.PI * 2);
        hCtx.fill();
        hCtx.globalCompositeOperation = 'source-over';

        // Bangs over the forehead
        hCtx.beginPath();
        hCtx.moveTo(cx - rX * 1.2 * vol, cy - rY * 0.4);
        hCtx.quadraticCurveTo(cx, cy - rY * 0.1, cx + rX * 1.2 * vol, cy - rY * 0.4);
        hCtx.lineTo(cx + rX * 1.5 * vol, cy - rY * 1.8 * vol);
        hCtx.lineTo(cx - rX * 1.5 * vol, cy - rY * 1.8 * vol);
        hCtx.fill();

    } else if (style === 'long') {
        // Main mass flowing down
        hCtx.beginPath();
        hCtx.ellipse(cx, cy + rY * 0.5, rX * 1.7 * vol, rY * 2.5 * vol, 0, 0, Math.PI * 2);
        hCtx.fill();

        // Subtractive cutout for the face
        hCtx.globalCompositeOperation = 'destination-out';
        hCtx.beginPath();
        hCtx.ellipse(cx, cy + rY * 0.1, rX * 0.95, rY * 1.05, 0, 0, Math.PI * 2);
        hCtx.fill();
        hCtx.globalCompositeOperation = 'source-over';

        // Parted hair sweeps from top center to sides
        hCtx.beginPath();
        hCtx.moveTo(cx, cy - rY * 1.8 * vol);
        hCtx.quadraticCurveTo(cx - rX * 0.2, cy - rY * 0.5, cx - rX * 1.1, cy - rY * 0.1);
        hCtx.lineTo(cx - rX * 1.8 * vol, cy - rY * 1.8 * vol);
        hCtx.fill();

        hCtx.beginPath();
        hCtx.moveTo(cx, cy - rY * 1.8 * vol);
        hCtx.quadraticCurveTo(cx + rX * 0.2, cy - rY * 0.5, cx + rX * 1.1, cy - rY * 0.1);
        hCtx.lineTo(cx + rX * 1.8 * vol, cy - rY * 1.8 * vol);
        hCtx.fill();

    } else if (style === 'spiky') {
        // No full face cutout required; rest entirely on upper half of head
        hCtx.beginPath();
        hCtx.moveTo(cx - rX * 1.05, cy - rY * 0.6);
        const spikes = 15;
        for(let i = 0; i <= spikes; i++) {
            let pct = i / spikes;
            let x = cx - rX * 1.05 + pct * (rX * 2.1);
            let arch = Math.sin(pct * Math.PI);
            let yBase = cy - rY * 0.6 - arch * rY * 0.3 * vol;
            let yTip = yBase - rY * 0.6 * vol - (Math.random() * rY * 0.4);
            
            if (i === 0) {
                hCtx.lineTo(x, yBase);
            } else {
                hCtx.lineTo(x - (rX * 2.1) / (spikes * 2), yTip);
                hCtx.lineTo(x, yBase);
            }
        }
        // Sweep underneath the spikes to cover hairline
        hCtx.quadraticCurveTo(cx, cy - rY * 0.9, cx - rX * 1.05, cy - rY * 0.6);
        hCtx.fill();

    } else if (style === 'curly') {
        // Voluminous base
        hCtx.beginPath();
        hCtx.ellipse(cx, cy + rY * 0.2, rX * 1.8 * vol, rY * 2.0 * vol, 0, 0, Math.PI * 2);
        hCtx.fill();

        // Loop generating outer curly texture clouds
        for (let a = 0; a < Math.PI * 2; a += 0.2) {
            let radX = rX * 1.6 * vol + Math.random() * rX * 0.3;
            let radY = rY * 1.8 * vol + Math.random() * rY * 0.3;
            let oX = cx + Math.cos(a) * radX;
            let oY = cy + Math.sin(a) * radY;
            hCtx.beginPath();
            hCtx.arc(oX, oY, rX * 0.5 * vol, 0, Math.PI * 2);
            hCtx.fill();
        }

        // Subtractive cutout for the face
        hCtx.globalCompositeOperation = 'destination-out';
        hCtx.beginPath();
        hCtx.ellipse(cx, cy + rY * 0.1, rX * 0.95, rY * 1.05, 0, 0, Math.PI * 2);
        hCtx.fill();
        hCtx.globalCompositeOperation = 'source-over';

        // Add overlapping curly bangs across the front top
        for (let x = cx - rX * 0.9; x <= cx + rX * 0.9; x += rX * 0.35) {
            hCtx.beginPath();
            hCtx.arc(x, cy - rY * 0.65, rX * 0.35 * vol, 0, Math.PI * 2);
            hCtx.fill();
        }
    }

    // Add texture highlights (strands) bounded directly to the drawn hair
    hCtx.globalCompositeOperation = 'source-atop';
    hCtx.lineWidth = Math.max(1, width * 0.002);

    for (let i = 0; i < 250; i++) {
        // Randomly choose subtle dark shadows or light highlights
        hCtx.strokeStyle = Math.random() > 0.5 ? 'rgba(255, 255, 255, 0.06)' : 'rgba(0, 0, 0, 0.15)';
        hCtx.beginPath();
        
        let sx = cx + (Math.random() * 6 - 3) * rX * vol;
        let sy = cy - rY * 2 * vol + (Math.random() * 2) * rY;
        hCtx.moveTo(sx, sy);
        
        let cpX = sx + (Math.random() * rX - rX / 2);
        let cpY = sy + rY * 1.5;
        let ex = sx + (Math.random() * rX * 2 - rX);
        let ey = sy + rY * 4 * vol;
        
        if (style === 'curly') {
            hCtx.arc(sx, sy, Math.random() * rX * 0.4, 0, Math.PI * 2);
        } else if (style === 'spiky') {
            ex = sx + (Math.random() * rX - rX / 2);
            ey = sy - rY * 1.5 * vol;
            hCtx.quadraticCurveTo(cpX, cpY, ex, ey);
        } else {
            hCtx.quadraticCurveTo(cpX, cpY, ex, ey);
        }
        hCtx.stroke();
    }
    
    // Reset compositing and blend hair to the main canvas
    hCtx.globalCompositeOperation = 'source-over';
    
    // Draw the temporary hair canvas onto the final canvas
    ctx.drawImage(hairCanvas, 0, 0);

    return mainCanvas;
}

Free Image Tool Creator

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

Description

The Hair Shape and Style Visualizer is an image manipulation tool that allows users to virtually overlay different hairstyles onto a photo. Users can experiment with various hair shapes—such as bob, long, spiky, or curly styles—and customize the look by adjusting hair color, volume, and the positioning of the hair relative to the face. This tool is ideal for individuals looking to preview new hair trends before visiting a salon or for creative projects requiring quick character hair adjustments.

Leave a Reply

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