Please bookmark this page to avoid losing your image tool!

Adventure Mood Photo Filter

(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, contrastValue = 0.15, brightnessValue = 0.05, warmOverlayStrength = 0.2, desaturationValue = 0.1, vignetteStrength = 0.4) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

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

    if (width === 0 || height === 0) {
        console.error("Image dimensions are zero. Ensure the image is loaded and valid.");
        // Return a small, empty canvas or handle as an error appropriately
        canvas.width = 1;
        canvas.height = 1;
        return canvas;
    }

    canvas.width = width;
    canvas.height = height;

    try {
        ctx.drawImage(originalImg, 0, 0, width, height);
    } catch (e) {
        console.error("Error drawing image onto canvas. Ensure image is valid:", e);
        // Fallback for drawing error
        ctx.fillStyle = 'lightgray';
        ctx.fillRect(0, 0, width, height);
        ctx.font = "16px Arial";
        ctx.fillStyle = "black";
        ctx.textAlign = "center";
        ctx.fillText("Error: Could not draw image.", width / 2, height / 2);
        return canvas;
    }
    
    let imageData;
    try {
        imageData = ctx.getImageData(0, 0, width, height);
    } catch (e) {
        // This can happen due to CORS issues if the image is from another domain and canvas is tainted
        console.error("Could not get image data, possibly due to CORS policy:", e);
        // Draw a placeholder indicating the error.
        ctx.fillStyle = 'rgba(255, 0, 0, 0.7)'; // Semi-transparent red
        ctx.fillRect(0, 0, width, height);
        ctx.font = "bold 16px Arial";
        ctx.fillStyle = "white";
        ctx.textAlign = "center";
        const message = "Error: Cannot process cross-origin image.";
        const textY = height / 2  - (message.split('\n').length -1) * 8 ; // Adjust for multi-line
        ctx.fillText(message, width / 2, textY);
        ctx.font =_UTIL.HELPER_FUNCTIONS.canvasDrawMultilineText = function(ctx, text, x, y, maxWidth, lineHeight) {
    const words = text.split(' ');
    let line = '';
    let currentY = y;
    for (let n = 0; n < words.length; n++) {
        const testLine = line + words[n] + ' ';
        const metrics = ctx.measureText(testLine);
        const testWidth = metrics.width;
        if (testWidth > maxWidth && n > 0) {
            ctx.fillText(line, x, currentY);
            line = words[n] + ' ';
            currentY += lineHeight;
        } else {
            line = testLine;
        }
    }
    ctx.fillText(line, x, currentY);
}
        return canvas;
    }
    
    const data = imageData.data;

    const centerX = width / 2;
    const centerY = height / 2;
    // Distance from center to a corner, used for normalizing vignette distance
    const maxDistToCorner = (width === 0 && height === 0) ? 0 : Math.sqrt(centerX * centerX + centerY * centerY);


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

    // Convert parameter ranges (typically 0-1) to effect magnitudes
    const brightnessOffset = brightnessValue * 50; // e.g., 0.05 -> 2.5 offset
    
    // For contrast, map 0-1 to a 0-100 scale for the formula.
    // 0 means no change (factor 1), positive values increase contrast.
    const contrastInput = contrastValue * 100; 
    const contrastFactor = (259 * (contrastInput + 255)) / (255 * (259 - contrastInput));

    // Warm overlay color (orangey-yellow)
    const warmColorR = 255; 
    const warmColorG = 200;
    const warmColorB = 100;

    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
        if (brightnessOffset !== 0) {
            r += brightnessOffset;
            g += brightnessOffset;
            b += brightnessOffset;
        }

        // 2. Contrast Adjustment
        // Only apply if contrastInput is not 0. If 0, factor is 1, no change.
        if (contrastInput !== 0) { 
            r = contrastFactor * (r - 128) + 128;
            g = contrastFactor * (g - 128) + 128;
            b = contrastFactor * (b - 128) + 128;
        }
        
        // Clamp after combined brightness and contrast
        r = clamp(r);
        g = clamp(g);
        b = clamp(b);

        // 3. Desaturation
        // If desaturationValue is 0, this step is skipped.
        if (desaturationValue > 0) {
            const gray = 0.299 * r + 0.587 * g + 0.114 * b;
            r = r * (1 - desaturationValue) + gray * desaturationValue;
            g = g * (1 - desaturationValue) + gray * desaturationValue;
            b = b * (1 - desaturationValue) + gray * desaturationValue;
            // No clamp needed: r,g,b are already clamped, gray is weighted avg, result is interpolation.
        }

        // 4. Warm Overlay
        // If warmOverlayStrength is 0, this step is skipped.
        if (warmOverlayStrength > 0) {
            r = r * (1 - warmOverlayStrength) + warmColorR * warmOverlayStrength;
            g = g * (1 - warmOverlayStrength) + warmColorG * warmOverlayStrength;
            b = b * (1 - warmOverlayStrength) + warmColorB * warmOverlayStrength;
            // Clamp after overlay, as warm color components can push values > 255
            r = clamp(r);
            g = clamp(g);
            b = clamp(b);
        }
        
        // 5. Vignette
        // If vignetteStrength is 0 or image is too small, skip.
        if (vignetteStrength > 0 && maxDistToCorner > 0) {
            const pixelX = (i / 4) % width;
            const pixelY = Math.floor((i / 4) / width);
            
            const dx = pixelX - centerX;
            const dy = pixelY - centerY;
            const distFromCenter = Math.sqrt(dx * dx + dy * dy);
            
            // Normalized distance: 0 at center, 1 at corners.
            const normalizedDist = distFromCenter / maxDistToCorner; 

            let vignetteAmount = 0;
            const vignetteStartRatio = 0.2; // Vignette starts affecting pixels beyond 20% of radius from center
            const vignetteFullRatio = 0.85; // Vignette reaches full strength at 85% of radius

            if (normalizedDist > vignetteStartRatio) {
                // Calculate how far into the vignette band (startRatio to fullRatio) this pixel is
                vignetteAmount = (normalizedDist - vignetteStartRatio) / (vignetteFullRatio - vignetteStartRatio);
                vignetteAmount = clamp(vignetteAmount, 0, 1); // Intensity of vignette for this pixel (0 to 1)
            }
            
            const darkenFactor = 1.0 - vignetteAmount * vignetteStrength;
            
            r *= darkenFactor;
            g *= darkenFactor;
            b *= darkenFactor;
            
            // Clamp after darkening
            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]) is preserved
    }

    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 Adventure Mood Photo Filter is an online tool designed to enhance your images with a variety of customizable photo effects. It allows you to adjust the contrast, brightness, and color saturation, apply a warm overlay, and add a vignette effect to create a more immersive visual experience. This tool is ideal for photographers, social media enthusiasts, and anyone looking to elevate their image aesthetics for personal or professional use.

Leave a Reply

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