Please bookmark this page to avoid losing your image tool!

Long Image Face Detection And 16:9 Aspect Ratio Cropping Tool

(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, aspectRatioString = '16:9') {
    let targetRatio = 16 / 9;
    try {
        const parts = String(aspectRatioString).split(':');
        if (parts.length === 2 && !isNaN(parts[0]) && !isNaN(parts[1])) {
            const num = parseFloat(parts[0]);
            const den = parseFloat(parts[1]);
            if (den > 0 && num > 0) {
                targetRatio = num / den;
            }
        }
    } catch (e) {
        console.warn('Invalid aspect ratio format, defaulting to 16:9');
    }

    const imgRatio = originalImg.width / originalImg.height;

    let targetWidth, targetHeight;
    if (imgRatio > targetRatio) {
        // Image is wider than target ratio
        targetHeight = originalImg.height;
        targetWidth = Math.round(originalImg.height * targetRatio);
    } else {
        // Image is taller than target ratio (likely a long image)
        targetWidth = originalImg.width;
        targetHeight = Math.round(originalImg.width / targetRatio);
    }

    async function loadScript(url, globalName) {
        if (window[globalName]) return window[globalName];
        return new Promise((resolve, reject) => {
            const script = document.createElement('script');
            script.src = url;
            script.onload = () => resolve(window[globalName]);
            script.onerror = reject;
            document.head.appendChild(script);
        });
    }

    let faces = [];
    
    // Approach 1: Try Native FaceDetector (Shape Detection API)
    if ('FaceDetector' in window) {
        try {
            const detector = new window.FaceDetector();
            const detected = await detector.detect(originalImg);
            faces = detected.map(f => ({
                x: f.boundingBox.x,
                y: f.boundingBox.y,
                width: f.boundingBox.width,
                height: f.boundingBox.height
            }));
        } catch (e) {
            console.warn('FaceDetector not available or failed', e);
        }
    }

    // Approach 2: Fallback to tracking.js for face detection
    if (faces.length === 0) {
        try {
            await loadScript('https://cdnjs.cloudflare.com/ajax/libs/tracking.js/1.1.3/tracking-min.js', 'tracking');
            await new Promise((resolve, reject) => {
                if (window.tracking.ViolaJones && window.tracking.ViolaJones.classifiers && window.tracking.ViolaJones.classifiers.face) {
                    resolve();
                } else {
                    const script = document.createElement('script');
                    script.src = 'https://cdnjs.cloudflare.com/ajax/libs/tracking.js/1.1.3/data/face-min.js';
                    script.onload = resolve;
                    script.onerror = reject;
                    document.head.appendChild(script);
                }
            });

            // Prevent UI freeze on large images by downscaling the detection phase
            const MAX_DIM = 1200;
            let scaleFactor = 1;

            if (originalImg.width > MAX_DIM || originalImg.height > MAX_DIM) {
                scaleFactor = MAX_DIM / Math.max(originalImg.width, originalImg.height);
            }

            const trackWidth = Math.round(originalImg.width * scaleFactor);
            const trackHeight = Math.round(originalImg.height * scaleFactor);

            const trackingCanvas = document.createElement('canvas');
            trackingCanvas.width = trackWidth;
            trackingCanvas.height = trackHeight;
            const trackingCtx = trackingCanvas.getContext('2d');
            trackingCtx.drawImage(originalImg, 0, 0, trackWidth, trackHeight);

            // Manually fetch pixels to handle cross-origin canvas taint cleanly
            const imageData = trackingCtx.getImageData(0, 0, trackWidth, trackHeight);
            
            const tracker = new window.tracking.ObjectTracker('face');
            tracker.setInitialScale(4);
            tracker.setStepSize(2);
            tracker.setEdgesDensity(0.1);
            
            const trackedFaces = await new Promise(resolve => {
                const timeout = setTimeout(() => resolve([]), 5000); 
                tracker.on('track', event => {
                    clearTimeout(timeout);
                    resolve(event.data);
                });
                tracker.track(imageData.data, trackWidth, trackHeight);
            });

            if (trackedFaces) {
                // Scale coordinates back to original size
                faces = trackedFaces.map(f => ({
                    x: Math.round(f.x / scaleFactor),
                    y: Math.round(f.y / scaleFactor),
                    width: Math.round(f.width / scaleFactor),
                    height: Math.round(f.height / scaleFactor)
                }));
            }
        } catch (e) {
            console.warn('Tracking.js face detection failed or canvas is tainted due to cross-origin isolation.', e);
        }
    }

    const boost = faces.map(f => ({
        x: f.x,
        y: f.y,
        width: f.width,
        height: f.height,
        weight: 1.0 // Emphasize facial areas strongly
    }));

    // Approach 3: Apply smartcrop.js to find the most visually significant 16:9 segment
    await loadScript('https://cdnjs.cloudflare.com/ajax/libs/smartcrop/2.0.5/smartcrop.min.js', 'smartcrop');

    // Passing the actual dimension to force maximum scale sliding (avoids zoom-in crops entirely)
    const result = await window.smartcrop.crop(originalImg, {
        width: Math.max(1, targetWidth),
        height: Math.max(1, targetHeight),
        boost: boost
    });

    const crop = result.topCrop;

    const canvas = document.createElement('canvas');
    canvas.width = targetWidth;
    canvas.height = targetHeight;
    const ctx = canvas.getContext('2d');
    
    // Improve final sampling quality
    ctx.imageSmoothingEnabled = true;
    ctx.imageSmoothingQuality = 'high';

    ctx.fillStyle = "#ffffff";
    ctx.fillRect(0, 0, targetWidth, targetHeight);

    ctx.drawImage(
        originalImg,
        crop.x, crop.y, crop.width, crop.height,
        0, 0, targetWidth, targetHeight
    );

    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

This tool is designed to automatically crop long or vertically-oriented images into a 16:9 aspect ratio. It utilizes intelligent face detection technology to identify human faces within the image, ensuring that facial features are prioritized and preserved during the cropping process. This makes it highly useful for converting portrait-style photos or long scrolling screenshots into widescreen formats suitable for video platforms, social media headers, or presentation slides without losing the most important subjects.

Leave a Reply

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