Please bookmark this page to avoid losing your image tool!

Image Long Shadow Filter Effect 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.
function processImage(originalImg, shadowLength = 100, angleDeg = 45, shadowColorStr = '#000000', shadowOpacity = 0.7) {
    // Helper function to parse CSS color string and apply an overall opacity multiplier.
    // Returns an RGBA color string e.g. "rgba(255,0,0,0.5)".
    function getRgbaColorWithOpacity(colorStr, opacityMultiplier) {
        let r = 0, g = 0, b = 0, a = 0;

        // Create a temporary DOM element to resolve the input colorStr string to an RGBA value.
        const resolverDiv = document.createElement("div");
        resolverDiv.style.color = colorStr;
        // Element must be in the DOM for getComputedStyle to work reliably.
        document.body.appendChild(resolverDiv);
        const computedColor = window.getComputedStyle(resolverDiv).color;
        document.body.removeChild(resolverDiv);

        // Parse the computed color string (which is usually in "rgb(r, g, b)" or "rgba(r, g, b, a)" format).
        const match = computedColor.match(/rgba?\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([\d.]+))?\)/);
        if (match) {
            r = parseInt(match[1]);
            g = parseInt(match[2]);
            b = parseInt(match[3]);
            const alphaFromColor = match[4] !== undefined ? parseFloat(match[4]) : 1;
            a = alphaFromColor * opacityMultiplier;
            a = Math.max(0, Math.min(1, a)); // Clamp final alpha to [0, 1]
        } else {
            // Fallback if color parsing fails.
            console.warn(`Could not parse shadowColorStr '${colorStr}'. Defaulting to black.`);
            r = 0; g = 0; b = 0;
            a = opacityMultiplier; // Relies on shadowOpacity being pre-clamped.
        }
        return `rgba(${r}, ${g}, ${b}, ${a})`;
    }

    // 0. Parameter Sanitization and Validation
    shadowLength = Math.max(0, Number(shadowLength));
    angleDeg = Number(angleDeg);
    shadowOpacity = Math.max(0, Math.min(1, Number(shadowOpacity)));

    if (!originalImg || typeof originalImg.width === 'undefined' || originalImg.width === 0 || originalImg.height === 0) {
        console.warn("processImage: Original image is invalid or has zero dimensions.");
        const emptyCanvas = document.createElement('canvas');
        emptyCanvas.width = 1;
        emptyCanvas.height = 1;
        return emptyCanvas;
    }

    // 1. Calculate Shadow and Canvas Geometry
    const angleRad = angleDeg * Math.PI / 180;
    const dxUnit = Math.cos(angleRad); // Unit vector x for shadow direction
    const dyUnit = Math.sin(angleRad); // Unit vector y for shadow direction

    const totalShadowOffsetX = dxUnit * shadowLength;
    const totalShadowOffsetY = dyUnit * shadowLength;

    const canvasWidth = Math.ceil(originalImg.width + Math.abs(totalShadowOffsetX));
    const canvasHeight = Math.ceil(originalImg.height + Math.abs(totalShadowOffsetY));

    const imageDrawX = (totalShadowOffsetX < 0) ? Math.ceil(Math.abs(totalShadowOffsetX)) : 0;
    const imageDrawY = (totalShadowOffsetY < 0) ? Math.ceil(Math.abs(totalShadowOffsetY)) : 0;

    const mainCanvas = document.createElement('canvas');
    mainCanvas.width = canvasWidth;
    mainCanvas.height = canvasHeight;
    const ctx = mainCanvas.getContext('2d');

    // 2. Determine the final shadow color
    const finalShadowRgbaFillStyle = getRgbaColorWithOpacity(shadowColorStr, shadowOpacity);
    
    // 3. Create a Silhouette Canvas
    const silhouetteCanvas = document.createElement('canvas');
    silhouetteCanvas.width = originalImg.width;
    silhouetteCanvas.height = originalImg.height;
    const silhouetteCtx = silhouetteCanvas.getContext('2d');

    silhouetteCtx.drawImage(originalImg, 0, 0, originalImg.width, originalImg.height);
    silhouetteCtx.globalCompositeOperation = 'source-in';
    silhouetteCtx.fillStyle = finalShadowRgbaFillStyle;
    silhouetteCtx.fillRect(0, 0, originalImg.width, originalImg.height);

    // 4. Draw the Shadow Layers on the Main Canvas
    // If shadowLength is 0 or the silhouette is fully transparent (due to shadowOpacity or shadowColorStr alpha),
    // this loop won't run or drawing the transparent silhouette will have no effect.
    if (shadowLength > 0) { // Only attempt to draw shadow if length is positive
        // Check if silhouette has any visible pixels. Minor optimization.
        // A more robust check would be to check final 'a' in finalShadowRgbaFillStyle
        // However, drawing a fully transparent silhouette is a no-op, so it's implicitly handled.
        for (let i = 1; i <= shadowLength; i++) {
            const currentShadowLayerX = imageDrawX + i * dxUnit;
            const currentShadowLayerY = imageDrawY + i * dyUnit;
            ctx.drawImage(silhouetteCanvas, currentShadowLayerX, currentShadowLayerY);
        }
    }

    // 5. Draw the Original Image on Top
    ctx.globalCompositeOperation = 'source-over';
    ctx.drawImage(originalImg, imageDrawX, imageDrawY);

    // 6. Return the Main Canvas
    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 Image Long Shadow Filter Effect Tool allows users to create a long, stylized shadow effect for images. By specifying parameters such as shadow length, angle, color, and opacity, users can enhance their images with a visually appealing shadow that adds depth and dimension. This tool is ideal for graphic designers, social media marketers, and anyone looking to improve their images for presentations, online posts, or creative projects.

Leave a Reply

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