Please bookmark this page to avoid losing your image tool!

Image Art Nouveau Filter Effect

(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, tintColor_str = "#9A8B74", tintStrength_num = 0.35, saturation_num = -0.3, contrast_num = 15, posterizeLevels_num = 6) {

    /**
     * Converts a HEX color string to an RGB object.
     * Fallbacks to black and logs a warning if the hex string is invalid.
     * @param {string} hex - The hex color string (e.g., "#RRGGBB" or "#RGB").
     * @returns {{r: number, g: number, b: number}} RGB object.
     */
    function hexToRgb(hex) {
        if (typeof hex !== 'string') {
            console.warn(`Invalid hex color string (not a string): "${String(hex)}". Using black as fallback.`);
            return { r: 0, g: 0, b: 0 };
        }
        let normalizedHex = hex.replace(/^#/, '');

        if (!/^[0-9A-Fa-f]{3}$|^[0-9A-Fa-f]{6}$/.test(normalizedHex)) {
            console.warn(`Invalid hex color string (format error): "${hex}". Using black as fallback.`);
            return { r: 0, g: 0, b: 0 };
        }

        if (normalizedHex.length === 3) {
            normalizedHex = normalizedHex[0] + normalizedHex[0] + normalizedHex[1] + normalizedHex[1] + normalizedHex[2] + normalizedHex[2];
        }

        const bigint = parseInt(normalizedHex, 16);
        if (isNaN(bigint)) {
             console.warn(`Invalid hex color string (parse error): "${hex}". Using black as fallback.`);
            return { r: 0, g: 0, b: 0 };
        }
        const r = (bigint >> 16) & 255;
        const g = (bigint >> 8) & 255;
        const b = bigint & 255;
        return { r, g, b };
    }

    /**
     * Clamps a value between a minimum and maximum.
     * @param {number} value - The value to clamp.
     * @param {number} [min=0] - The minimum value.
     * @param {number} [max=255] - The maximum value.
     * @returns {number} The clamped value.
     */
    function clamp(value, min = 0, max = 255) {
        return Math.max(min, Math.min(max, value));
    }

    const canvas = document.createElement('canvas');
    // Use willReadFrequently for potential performance improvements if the canvas is read back often.
    const ctx = canvas.getContext('2d', { willReadFrequently: true }); 

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

    if (canvas.width === 0 || canvas.height === 0) {
        console.warn("Image has zero width or height. Returning an empty canvas.");
        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 tintRGB = hexToRgb(tintColor_str);
    
    // Process and validate parameters for safe use
    const safeContrastNum = clamp(contrast_num, -254.9, 254.9); // Avoid division by nearly zero for factor
    const contrastFactor = (259 * (safeContrastNum + 255)) / (255 * (259 - safeContrastNum));
    const effectiveTintStrength = clamp(tintStrength_num, 0, 1);
    const pLevels = Math.round(posterizeLevels_num); // Ensure integer levels for posterization

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

        // 1. Saturation Adjustment
        const gray = 0.299 * r + 0.587 * g + 0.114 * b;
        const satFactor = 1 + saturation_num; // Allow saturation_num to be any number
                                             // Negative values desaturate, positive values saturate.
        r = gray + (r - gray) * satFactor;
        g = gray + (g - gray) * satFactor;
        b = gray + (b - gray) * satFactor;
        r = clamp(r); 
        g = clamp(g); 
        b = clamp(b);

        // 2. Contrast Adjustment
        r = contrastFactor * (r - 128) + 128;
        g = contrastFactor * (g - 128) + 128;
        b = contrastFactor * (b - 128) + 128;
        r = clamp(r); 
        g = clamp(g); 
        b = clamp(b);

        // 3. Posterization
        if (pLevels >= 2 && pLevels <= 255) {
            const step = 255 / (pLevels - 1);
            r = Math.round(r / step) * step;
            g = Math.round(g / step) * step;
            b = Math.round(b / step) * step;
            // Values might be floats like 127.5 if step is not integer. They will be rounded at the end.
            // Clamping here is good practice, though mathematically they should stay in range if input was clamped.
            r = clamp(r); 
            g = clamp(g); 
            b = clamp(b);
        }

        // 4. Tint Application
        if (effectiveTintStrength > 0) {
            r = r * (1 - effectiveTintStrength) + tintRGB.r * effectiveTintStrength;
            g = g * (1 - effectiveTintStrength) + tintRGB.g * effectiveTintStrength;
            b = b * (1 - effectiveTintStrength) + tintRGB.b * effectiveTintStrength;
            // Final clamping is done before rounding and assignment.
        }
        
        // Final clamping and rounding for pixel data assignment
        data[i] = Math.round(clamp(r));
        data[i + 1] = Math.round(clamp(g));
        data[i + 2] = Math.round(clamp(b));
        // data[i + 3] (alpha) 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 Image Art Nouveau Filter Effect tool allows users to transform images using artistic filter effects reminiscent of the Art Nouveau style. By adjusting parameters such as tint color, saturation, contrast, and posterization levels, users can create unique visual effects that enhance the aesthetic appeal of their images. This tool is ideal for digital artists, graphic designers, and anyone looking to add a creative touch to their photographs or artwork.

Leave a Reply

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