Please bookmark this page to avoid losing your image tool!

Photo Moody Filter Application

(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, saturationParam = 0.4, contrastParam = 1.3, brightnessParam = -0.1, temperatureParam = -0.2, vignetteStrengthParam = 0.6, vignetteExponentParam = 2.0) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d', { willReadFrequently: true }); // Performance hint

    // Ensure the image is loaded before trying to get its dimensions
    if (!originalImg.complete || originalImg.naturalWidth === 0) {
        // Wait for the image to load if it hasn't already.
        // This is a common pattern if originalImg is an Image object whose src was just set.
        await new Promise((resolve, reject) => {
            originalImg.onload = resolve;
            originalImg.onerror = reject;
            // If src is already set and it's broken, it might not fire error/load again in some cases
            // but typically this setup handles cases where the image object is passed before it's fully processed.
        });
    }

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

    if (canvas.width === 0 || canvas.height === 0) {
        // Return an empty canvas or throw an error if image dimensions are invalid
        console.error("Invalid image dimensions.");
        return canvas; // or throw new Error("Invalid image dimensions.");
    }

    ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);

    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    const data = imageData.data;
    const width = canvas.width;
    const height = canvas.height;

    const centerX = width / 2;
    const centerY = height / 2;
    // Calculate distance from center to a corner for vignette normalization
    const maxDist = Math.sqrt(centerX * centerX + centerY * centerY);

    function clamp(value) {
        return Math.max(0, Math.min(255, value));
    }

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

        // 1. Brightness adjustment
        // brightnessParam: -1 (black) to 1 (white). 0 is no change.
        if (brightnessParam !== 0) {
            const K = brightnessParam * 255; // Amount to add/subtract
            r += K;
            g += K;
            b += K;
            r = clamp(r);
            g = clamp(g);
            b = clamp(b);
        }

        // 2. Contrast adjustment
        // contrastParam: >= 0. 1.0 is no change. >1 increases contrast, <1 decreases.
        if (contrastParam !== 1.0 && contrastParam >= 0) {
            // Formula: NewColor = (OldColor - 128) * ContrastFactor + 128
            r = (r - 128) * contrastParam + 128;
            g = (g - 128) * contrastParam + 128;
            b = (b - 128) * contrastParam + 128;
            r = clamp(r);
            g = clamp(g);
            b = clamp(b);
        }
        
        // 3. Saturation adjustment
        // saturationParam: 0 (grayscale) to N (e.g., 2 for double saturation). 1 is original saturation.
        if (saturationParam !== 1.0 && saturationParam >= 0) {
            // Standard luminosity constants for grayscale conversion
            const gray = 0.299 * r + 0.587 * g + 0.114 * b;
            // Formula: NewColor = Gray + SaturationFactor * (OldColor - Gray)
            r = gray + saturationParam * (r - gray);
            g = gray + saturationParam * (g - gray);
            b = gray + saturationParam * (b - gray);
            r = clamp(r);
            g = clamp(g);
            b = clamp(b);
        }

        // 4. Temperature adjustment (Color Balance)
        // temperatureParam: -1 (very cool/blue) to 1 (very warm/red). 0 is no change.
        if (temperatureParam !== 0) {
            if (temperatureParam < 0) { // Cool: increase blue, decrease red/green
                const coolFactor = -temperatureParam; // Range 0 to 1
                r *= (1 - 0.15 * coolFactor); // Decrease red
                g *= (1 - 0.05 * coolFactor); // Slightly decrease green
                b *= (1 + 0.25 * coolFactor); // Increase blue
            } else { // Warm: increase red/green, decrease blue
                const warmFactor = temperatureParam; // Range 0 to 1
                r *= (1 + 0.25 * warmFactor); // Increase red
                g *= (1 + 0.05 * warmFactor); // Slightly increase green
                b *= (1 - 0.15 * warmFactor); // Decrease blue
            }
            r = clamp(r);
            g = clamp(g);
            b = clamp(b);
        }

        // 5. Vignette effect
        // vignetteStrengthParam: 0 (no vignette) to 1 (strong vignette).
        // vignetteExponentParam: controls falloff (e.g., 1 for linear, 2 for quadratic).
        if (vignetteStrengthParam > 0 && maxDist > 0) {
            const currentX = (i / 4) % width;
            const currentY = Math.floor((i / 4) / width);
            
            const dx = currentX - centerX;
            const dy = currentY - centerY;
            const dist = Math.sqrt(dx * dx + dy * dy);
            
            const normalizedDist = dist / maxDist;
            
            // vignetteEffect increases from 0 at center to 1 at maxDist (corner)
            // Power function controls the falloff curve
            const vignetteEffect = Math.pow(normalizedDist, vignetteExponentParam);
            
            // vignetteFactor is 1 at center, decreasing towards edges
            let vignetteFactor = 1.0 - vignetteEffect * vignetteStrengthParam;
            vignetteFactor = Math.max(0, Math.min(1, vignetteFactor)); // Clamp factor to [0, 1]

            r *= vignetteFactor;
            g *= vignetteFactor;
            b *= vignetteFactor;
            // Clamping R,G,B again is technically not needed if they were already clamped
            // and vignetteFactor is [0,1], but doesn't hurt.
            // r = clamp(r); g = clamp(g); b = clamp(b); 
        }
        
        data[i] = r;
        data[i+1] = g;
        data[i+2] = b;
        // Alpha channel data[i+3] remains unchanged
    }

    ctx.putImageData(imageData, 0, 0);
    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 Photo Moody Filter Application allows users to enhance their images using various aesthetic filters. This tool provides options to adjust parameters such as saturation, contrast, brightness, and color temperature, as well as apply a vignette effect around the edges of the image. It’s perfect for photographers and social media enthusiasts looking to add a specific mood or artistic flair to their photos, making them more visually appealing for sharing or personal collections.

Leave a Reply

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