Please bookmark this page to avoid losing your image tool!

Image Street Art 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.
function processImage(originalImg, levelsStr = "5", saturationStr = "1.2", grainStr = "0.1") {

    // 0. Parse parameters and set defaults/constraints
    let levels = parseInt(levelsStr, 10);
    if (isNaN(levels) || levels < 2) {
        levels = 5; // Default to 5 levels if invalid or less than 2. Minimum 2 levels.
    }
    // For levels = 256, posterization effectively becomes a no-op, which is fine.
    // Higher values of levels might lead to posterizationDivisor becoming very small;
    // however, "levels" implies the number of output states, so > 256 isn't meaningful for 8-bit color.

    let saturationFactor = parseFloat(saturationStr);
    if (isNaN(saturationFactor)) {
        saturationFactor = 1.2; // Default saturation boost
    }

    let grainAmount = parseFloat(grainStr);
    if (isNaN(grainAmount) || grainAmount < 0) {
        grainAmount = 0.1; // Default grain amount
    }
    grainAmount = Math.min(grainAmount, 1.0); // Cap grain amount at 1.0 for sensible range

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

    // Helper: Convert RGB to HSL color space
    // Input R, G, B are 0-255. Output H is [0, 1), S is [0, 1], L is [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: Convert HSL to RGB color space
    // Input H is [0, 1), S is [0, 1], L is [0, 1]. Output R, G, B are 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)];
    }

    // 1. Canvas Setup
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d', { willReadFrequently: true }); // Performance hint

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

    if (width === 0 || height === 0) {
        canvas.width = 0; // Ensure canvas is minimal if image is empty
        canvas.height = 0;
        return canvas; // Return empty canvas for empty image
    }

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

    // 2. Get Pixel Data
    let imageData;
    try {
        imageData = ctx.getImageData(0, 0, width, height);
    } catch (e) {
        // Handle potential security errors if image is cross-origin and canvas becomes tainted
        console.error("Error getting ImageData: ", e);
        // Return a copy of the original image on a new canvas, or the original canvas
        // For simplicity, just return the current canvas which has the image drawn but not processed
        return canvas;
    }
    const data = imageData.data;

    // 3. Iterate Pixels and Apply Effects
    // Posterization divisor calculation:
    // If levels = 1, (levels - 1) would be 0. This is prevented by `levels >= 2` check.
    // If levels = 256, divisor is 255 / (256-1) = 1. This results in no change from posterization.
    const posterizationDivisor = (levels > 1 && levels < 256) ? (255 / (levels - 1)) : 1;


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

        // a. Adjust Saturation
        if (saturationFactor !== 1.0) {
            let [h, s, l] = rgbToHsl(r, g, b);
            s = clamp(s * saturationFactor, 0, 1); // Apply factor and clamp Saturation to [0, 1]
            [r, g, b] = hslToRgb(h, s, l);
        }

        // b. Apply Posterization
        if (posterizationDivisor !== 1) { // Only apply if effective
            r = Math.round(Math.round(r / posterizationDivisor) * posterizationDivisor);
            g = Math.round(Math.round(g / posterizationDivisor) * posterizationDivisor);
            b = Math.round(Math.round(b / posterizationDivisor) * posterizationDivisor);
        }
        
        // Clamp intermediate RGB values (posterization can sometimes yield e.g. 255.0000001)
        r = clamp(r, 0, 255);
        g = clamp(g, 0, 255);
        b = clamp(b, 0, 255);

        // c. Add Grain
        if (grainAmount > 0) {
            const noise = (Math.random() - 0.5) * 255 * grainAmount;
            r = clamp(r + noise, 0, 255);
            g = clamp(g + noise, 0, 255);
            b = clamp(b + noise, 0, 255);
        }
        
        // Ensure final values are integers for pixel data
        data[i] = Math.round(r);
        data[i + 1] = Math.round(g);
        data[i + 2] = Math.round(b);
        // Alpha channel (data[i+3]) remains unchanged
    }

    // 4. Put Pixel Data Back onto Canvas
    ctx.putImageData(imageData, 0, 0);

    // 5. Return the Processed Canvas
    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 Street Art Filter Effect Tool allows users to apply a street art-inspired effect to images by adjusting properties such as color saturation, posterization levels, and graininess. This tool can enhance images by converting them into bold, stylized artwork reminiscent of street art, making it suitable for artists, graphic designers, or anyone looking to add an artistic touch to their photos. Use cases include creating graphics for social media, designing posters, or simply transforming personal photos into unique pieces of art.

Leave a Reply

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