Please bookmark this page to avoid losing your image tool!

Image Day Of The Dead 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.
async function processImage(originalImg, color1 = "#200020", color2 = "#D90077", color3 = "#FFD700", contrast = 1.5, vignetteStrength = 0.4) {

    // Helper function to parse hex color string to an {r, g, b} object
    function hexToRgb(hex) {
        let r = 0, g = 0, b = 0;
        // Remove # if present
        if (hex.startsWith('#')) {
            hex = hex.substring(1);
        }
        
        if (hex.length === 3) { // #RGB format
            r = parseInt(hex[0] + hex[0], 16);
            g = parseInt(hex[1] + hex[1], 16);
            b = parseInt(hex[2] + hex[2], 16);
        } else if (hex.length === 6) { // #RRGGBB format
            r = parseInt(hex.substring(0, 2), 16);
            g = parseInt(hex.substring(2, 4), 16);
            b = parseInt(hex.substring(4, 6), 16);
        } else {
            // Fallback to black if invalid hex
            console.warn("Invalid hex color:", hex, "defaulting to black.");
            return { r: 0, g: 0, b: 0 };
        }
        // Check for NaN cases from parseInt if hex is malformed (e.g. "GGGGGG")
        if (isNaN(r) || isNaN(g) || isNaN(b)) {
            console.warn("Invalid characters in hex color:", hex, "defaulting to black.");
            return { r: 0, g: 0, b: 0 };
        }
        return { r, g, b };
    }

    // Helper function for linear interpolation
    function lerp(a, b, t) {
        return a * (1 - t) + b * t;
    }

    // Helper function to clamp a value between min and max
    function clamp(value, min, max) {
        return Math.max(min, Math.min(value, max));
    }

    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d', { willReadFrequently: true });

    const width = originalImg.naturalWidth || originalImg.width;
    const height = originalImg.naturalHeight || originalImg.height;

    if (!width || !height) {
        console.error("Image has no dimensions or is not loaded properly.");
        // Return a small error indicator canvas
        canvas.width = 200;
        canvas.height = 100;
        ctx.fillStyle = 'red';
        ctx.font = '12px Arial';
        ctx.fillText("Error: Image not loaded or invalid.", 10, 20);
        return canvas;
    }
    
    canvas.width = width;
    canvas.height = height;

    // Draw original image onto the canvas to get its pixel data
    ctx.drawImage(originalImg, 0, 0, width, height);
    
    const imageData = ctx.getImageData(0, 0, width, height);
    const data = imageData.data;

    const rgb1 = hexToRgb(color1);
    const rgb2 = hexToRgb(color2);
    const rgb3 = hexToRgb(color3);

    // Process each pixel
    for (let i = 0; i < data.length; i += 4) {
        let r = data[i];
        let g = data[i + 1];
        let b = data[i + 2];

        // Apply contrast: (value - midpoint) * factor + midpoint
        // Contrast factor: 1.0 is no change. >1 increases, <1 decreases.
        r = clamp((r - 128) * contrast + 128, 0, 255);
        g = clamp((g - 128) * contrast + 128, 0, 255);
        b = clamp((b - 128) * contrast + 128, 0, 255);
        
        // Convert to grayscale (luminosity method)
        const gray = 0.299 * r + 0.587 * g + 0.114 * b;
        const grayNorm = gray / 255; // Normalized grayscale (0 to 1)

        // Apply gradient map based on grayscale value
        let finalR, finalG, finalB;
        if (grayNorm < 0.5) {
            // Interpolate between color1 (dark) and color2 (mid)
            const t = grayNorm / 0.5; // t from 0 to 1
            finalR = lerp(rgb1.r, rgb2.r, t);
            finalG = lerp(rgb1.g, rgb2.g, t);
            finalB = lerp(rgb1.b, rgb2.b, t);
        } else {
            // Interpolate between color2 (mid) and color3 (light)
            const t = (grayNorm - 0.5) / 0.5; // t from 0 to 1
            finalR = lerp(rgb2.r, rgb3.r, t);
            finalG = lerp(rgb2.g, rgb3.g, t);
            finalB = lerp(rgb2.b, rgb3.b, t);
        }

        data[i] = clamp(Math.round(finalR), 0, 255);
        data[i + 1] = clamp(Math.round(finalG), 0, 255);
        data[i + 2] = clamp(Math.round(finalB), 0, 255);
        // Alpha (data[i+3]) remains unchanged
    }
    ctx.putImageData(imageData, 0, 0);

    // Apply vignette effect
    if (vignetteStrength > 0 && vignetteStrength <= 1) {
        ctx.globalCompositeOperation = 'source-over'; // Ensure drawing normally

        const centerX = width / 2;
        const centerY = height / 2;
        // Outer radius is the distance to the furthest corner
        const outerRadius = Math.sqrt(Math.pow(centerX, 2) + Math.pow(centerY, 2));
        // Inner radius, where transparency starts to fade. 0.3 is a common value.
        const innerRadiusRatio = 0.3; 
        const innerRadius = outerRadius * innerRadiusRatio;

        const gradient = ctx.createRadialGradient(
            centerX, centerY, innerRadius,
            centerX, centerY, outerRadius
        );
        
        // Vignette is transparent in the center, dark at the edges
        gradient.addColorStop(0, 'rgba(0,0,0,0)'); 
        gradient.addColorStop(1, `rgba(0,0,0,${clamp(vignetteStrength, 0, 1)})`);

        ctx.fillStyle = gradient;
        ctx.fillRect(0, 0, width, height);
    }
    
    // Reset composite operation if it was changed by other effects (though not in this version)
    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

The Image Day Of The Dead Filter Effect Tool allows users to apply a vibrant filter inspired by the Day of the Dead celebration to their images. This tool enhances photos with customizable color gradients and contrast adjustments, creating unique and visually striking effects. Users can enjoy creative expression by transforming their images with a combination of vivid colors and a vignette effect, making it suitable for artistic projects, social media posts, or personal keepsakes that celebrate cultural themes.

Leave a Reply

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