Please bookmark this page to avoid losing your image tool!

Image Baroque Filter Effect 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, contrast = 1.5, saturation = 0.2, warmth = 0.15, vignette = 0.4) {

    // Helper function: RGB to HSL
    // r, g, b are in [0, 255]
    // Returns h, s, l in [0, 1]
    function rgbToHsl(r, g, b) {
        r /= 255; g /= 255; b /= 255;
        const max = Math.max(r, g, b), min = Math.min(r, g, b);
        let h, s, l = (max + min) / 2;

        if (max === min) {
            h = s = 0; // achromatic
        } else {
            const d = max - min;
            s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
            switch (max) {
                case r: h = (g - b) / d + (g < b ? 6 : 0); break;
                case g: h = (b - r) / d + 2; break;
                case b: h = (r - g) / d + 4; break;
            }
            h /= 6;
        }
        return [h, s, l];
    }

    // Helper function: HSL to RGB
    // h, s, l are in [0, 1]
    // Returns r, g, b in [0, 255]
    function hslToRgb(h, s, l) {
        let r, g, b;
        if (s === 0) {
            r = g = b = l; // achromatic
        } else {
            const hue2rgb = (p, q, t) => {
                if (t < 0) t += 1;
                if (t > 1) t -= 1;
                if (t < 1 / 6) return p + (q - p) * 6 * t;
                if (t < 1 / 2) return q;
                if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
                return p;
            };
            const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
            const p = 2 * l - q;
            r = hue2rgb(p, q, h + 1 / 3);
            g = hue2rgb(p, q, h);
            b = hue2rgb(p, q, h - 1 / 3);
        }
        return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
    }

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

    // Use naturalWidth/Height to get intrinsic dimensions of the image
    canvas.width = originalImg.naturalWidth || originalImg.width;
    canvas.height = originalImg.naturalHeight || originalImg.height;

    if (canvas.width === 0 || canvas.height === 0) {
        console.error("Image has zero width or height. Ensure the image is loaded and valid.");
        // Return an empty canvas or a canvas with a small size indicating an error
        canvas.width = canvas.width || 1; // Avoid 0x0 canvas if original dimensions were 0
        canvas.height = canvas.height || 1;
        return canvas;
    }

    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;
    const maxDist = Math.sqrt(centerX * centerX + centerY * centerY); // Dist from center to a corner

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

        // 1. Contrast adjustment
        // contrast = 1.0 means no change. > 1 increases contrast, < 1 decreases.
        if (contrast !== 1.0) {
            r = (r - 128) * contrast + 128;
            g = (g - 128) * contrast + 128;
            b = (b - 128) * contrast + 128;
        }

        // Clamp values after contrast
        r = Math.max(0, Math.min(255, r));
        g = Math.max(0, Math.min(255, g));
        b = Math.max(0, Math.min(255, b));

        // 2. Saturation adjustment
        // saturation = 0 means no change. Positive values increase saturation, negative values decrease.
        // e.g., saturation = 0.5 means 50% boost, saturation = -0.5 means 50% desaturation.
        if (saturation !== 0) {
            let [h_hsl, s_hsl, l_hsl] = rgbToHsl(r, g, b);
            s_hsl = s_hsl * (1 + saturation);
            s_hsl = Math.max(0, Math.min(1, s_hsl)); // Clamp saturation to [0, 1]
            [r, g, b] = hslToRgb(h_hsl, s_hsl, l_hsl);
        }
        // hslToRgb result is already [0, 255] due to Math.round(X*255)

        // 3. Warmth (Sepia-like tint)
        // warmth = 0 means no change. warmth = 1 means full sepia.
        if (warmth > 0) {
            const originalR = r, originalG = g, originalB = b;
            const sepiaR = 0.393 * originalR + 0.769 * originalG + 0.189 * originalB;
            const sepiaG = 0.349 * originalR + 0.686 * originalG + 0.168 * originalB;
            const sepiaB = 0.272 * originalR + 0.534 * originalG + 0.131 * originalB;

            r = (1 - warmth) * originalR + warmth * sepiaR;
            g = (1 - warmth) * originalG + warmth * sepiaG;
            b = (1 - warmth) * originalB + warmth * sepiaB;
        }
        
        // Clamp values after warmth
        r = Math.max(0, Math.min(255, r));
        g = Math.max(0, Math.min(255, g));
        b = Math.max(0, Math.min(255, b));

        // 4. Vignette
        // vignette = 0 means no vignette. vignette = 1 means edges can be fully black.
        if (vignette > 0 && maxDist > 0) { // maxDist check for 1x1 or invalid tiny images
            const x = (i / 4) % width; // Current pixel's x coordinate
            const y = Math.floor((i / 4) / width); // Current pixel's y coordinate
            
            const dx = x - centerX;
            const dy = y - centerY;
            const dist = Math.sqrt(dx * dx + dy * dy);
            
            // normDist is 0 at center, 1 at the furthest corner
            const normDist = dist / maxDist; 
            
            // Vignette intensity has a quadratic falloff (power=2)
            // `vignette` parameter controls the maximum darkening effect at the edges
            const vignettePower = 2; 
            const vignetteAmount = Math.pow(normDist, vignettePower) * vignette;
            const vignetteMultiplier = Math.max(0, 1.0 - vignetteAmount); // Ensure multiplier is not negative
            
            r *= vignetteMultiplier;
            g *= vignetteMultiplier;
            b *= vignetteMultiplier;
        }

        // Final clamp and assignment
        data[i] = Math.round(Math.max(0, Math.min(255, r)));
        data[i + 1] = Math.round(Math.max(0, Math.min(255, g)));
        data[i + 2] = Math.round(Math.max(0, Math.min(255, 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 Image Baroque Filter Effect Application is an online tool that allows users to apply a sophisticated filter to their images, enhancing them with a distinctive artistic style that mimics the Baroque aesthetic. This tool offers customizable adjustments for contrast, saturation, warmth, and vignette effects, enabling users to create visually appealing images. It is ideal for photographers, graphic designers, or anyone looking to add a vintage or artistic flair to their photos, making it perfect for personal projects, social media content, or professional portfolios.

Leave a Reply

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