Please bookmark this page to avoid losing your image tool!

Image Light Through Leaves Effect Generator

(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, intensity = 0.85, lightColor = '#fff7d6', shadowColor = '#1e2b17', density = 50, blur = 15) {
    // Parse numeric inputs
    intensity = Number(intensity);
    density = Number(density);
    blur = Number(blur);

    // Create the main canvas and context
    const canvas = document.createElement('canvas');
    const width = originalImg.width;
    const height = originalImg.height;
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext('2d');

    // Draw the original image as base
    ctx.drawImage(originalImg, 0, 0);

    // Minimum dimension for proportional scaling
    const minDim = Math.min(width, height);
    
    // Add padding to prevent blur edge-bleeding (halos) 
    const p = minDim * 0.1;

    // Create secondary canvas for the lighting / shadow map
    const mapCanvas = document.createElement('canvas');
    mapCanvas.width = width + p * 2;
    mapCanvas.height = height + p * 2;
    const mCtx = mapCanvas.getContext('2d');

    // Scale blur relative to image size for consistent effect at any resolution
    const dynamicBlur = blur * (minDim / 800);
    mCtx.filter = `blur(${dynamicBlur}px)`;

    // Fill the map with the underlying canopy shadow
    mCtx.fillStyle = shadowColor;
    mCtx.fillRect(0, 0, mapCanvas.width, mapCanvas.height);

    // Helper to compute hex to rgba safely
    function hexToRgba(hex, alpha) {
        hex = hex.replace(/^#/, '');
        if (hex.length === 3) {
            hex = hex.split('').map(c => c + c).join('');
        }
        const r = parseInt(hex.substring(0, 2), 16);
        const g = parseInt(hex.substring(2, 4), 16);
        const b = parseInt(hex.substring(4, 6), 16);
        return `rgba(${r}, ${g}, ${b}, ${alpha})`;
    }

    const transparentLight = hexToRgba(lightColor, 0);

    // Determine counts based on density and image resolution
    const numClusters = Math.max(1, Math.floor((density / 50) * 15 * (width * height) / 1000000));
    const spotsPerCluster = 12;

    // Procedural generation of dappled light through the canopy
    for (let i = 0; i < numClusters; i++) {
        // Random cluster center, encompassing padded area
        const cx = -p + Math.random() * (width + p * 2);
        const cy = -p + Math.random() * (height + p * 2);

        // Ambient scattered background light
        const ambRadius = minDim * (0.15 + Math.random() * 0.25);
        const ambGrad = mCtx.createRadialGradient(cx, cy, 0, cx, cy, ambRadius);
        ambGrad.addColorStop(0, hexToRgba(lightColor, 0.45));
        ambGrad.addColorStop(1, transparentLight);
        
        mCtx.fillStyle = ambGrad;
        mCtx.beginPath();
        mCtx.arc(cx, cy, ambRadius, 0, Math.PI * 2);
        mCtx.fill();

        // Specific focused "camera obscura" sunlight circles through leaf gaps
        for (let j = 0; j < spotsPerCluster; j++) {
            const rx = cx + (Math.random() - 0.5) * ambRadius * 1.5;
            const ry = cy + (Math.random() - 0.5) * ambRadius * 1.5;
            const spotRadius = minDim * (0.01 + Math.random() * 0.05);

            const spotGrad = mCtx.createRadialGradient(rx, ry, spotRadius * 0.2, rx, ry, spotRadius);
            spotGrad.addColorStop(0, hexToRgba(lightColor, 0.85));
            spotGrad.addColorStop(0.5, hexToRgba(lightColor, 0.5));
            spotGrad.addColorStop(1, transparentLight);

            mCtx.fillStyle = spotGrad;
            mCtx.beginPath();
            mCtx.arc(rx, ry, spotRadius, 0, Math.PI * 2);
            mCtx.fill();
        }
    }

    // Draw leaf silhouettes occasionally crossing out the light spots 
    // to simulate depth and overlapping canopy branches
    const numLeaves = Math.max(1, Math.floor(density * 5 * (width * height) / 1000000));
    mCtx.fillStyle = hexToRgba(shadowColor, 0.85);

    for (let i = 0; i < numLeaves; i++) {
        const lx = -p + Math.random() * (width + p * 2);
        const ly = -p + Math.random() * (height + p * 2);
        const lSize = minDim * (0.04 + Math.random() * 0.08);
        const lAngle = Math.random() * Math.PI * 2;

        mCtx.save();
        mCtx.translate(lx, ly);
        mCtx.rotate(lAngle);
        // Draw organic leaf shape
        mCtx.beginPath();
        mCtx.moveTo(0, -lSize);
        mCtx.quadraticCurveTo(lSize / 1.5, 0, 0, lSize);
        mCtx.quadraticCurveTo(-lSize / 1.5, 0, 0, -lSize);
        mCtx.fill();
        mCtx.restore();
    }

    // Blend the dappled light map over the original image
    
    // First pass: 'overlay' creates high contrast, darkening shadows and brightening light gaps
    ctx.globalAlpha = intensity;
    ctx.globalCompositeOperation = 'overlay';
    ctx.drawImage(mapCanvas, -p, -p);

    // Second pass: 'soft-light' at half strength to enrich colors without blowing out the highlights
    ctx.globalAlpha = intensity * 0.5;
    ctx.globalCompositeOperation = 'soft-light';
    ctx.drawImage(mapCanvas, -p, -p);

    // Reset properties
    ctx.globalAlpha = 1.0;
    ctx.globalCompositeOperation = 'source-over';

    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 generates a realistic dappled sunlight effect on your images, simulating the appearance of light filtering through a forest canopy or leafy branches. By using procedural generation, it creates a combination of soft light clusters, focused sunlight spots, and organic leaf silhouettes that blend seamlessly with your original photo. Users can customize the intensity, light and shadow colors, density of the effect, and the level of blur to achieve a specific mood. This tool is ideal for photographers, digital artists, or social media creators looking to add atmospheric depth, warmth, or a natural outdoor aesthetic to portraits, landscapes, or product photography.

Leave a Reply

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