Please bookmark this page to avoid losing your image tool!

Image Marker Drawing 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, levels = 5, noiseStrength = 10, saturationFactor = 1.0) {
    const canvas = document.createElement('canvas');
    // Use willReadFrequently for potential performance boost with getImageData/putImageData
    const ctx = canvas.getContext('2d', { willReadFrequently: true });

    // Ensure the canvas is sized to the original image's dimensions
    // For a JavaScript Image object, .width and .height are its natural dimensions once loaded.
    canvas.width = originalImg.width;
    canvas.height = originalImg.height;

    // Draw the original image onto the canvas
    ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);

    // Get the pixel data from the canvas
    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    const data = imageData.data;

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

    // Helper: RGB to HSL
    // r, g, b are 0-255
    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; // h is 0-1
        }
        return [h, s, l]; // s is 0-1, l is 0-1
    }

    // Helper: HSL to RGB
    // h, s, l are 0-1
    function hslToRgb(h, s, l) {
        let rOut, gOut, bOut; // Use different variable names to avoid conflict
        if (s === 0) {
            rOut = gOut = bOut = 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;
            rOut = hue2rgb(p, q, h + 1 / 3);
            gOut = hue2rgb(p, q, h);
            bOut = hue2rgb(p, q, h - 1 / 3);
        }
        return [Math.round(rOut * 255), Math.round(gOut * 255), Math.round(bOut * 255)];
    }

    // Sanitize and prepare parameters
    // Convert to Number in case string "5" is passed, then apply constraints.
    const pLevels = Math.max(2, Math.floor(Number(levels))); // Posterization levels, min 2
    const pNoiseStrength = Math.max(0, Number(noiseStrength)); // Noise intensity
    const pSaturationFactor = Math.max(0, Number(saturationFactor)); // Saturation multiplier

    const posterizeStep = 255 / (pLevels - 1);

    // Process each pixel
    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 (if saturationFactor is not 1.0)
        if (pSaturationFactor !== 1.0) {
            let [h, s, l] = rgbToHsl(r, g, b);
            s = clamp(s * pSaturationFactor, 0, 1); // Adjust saturation
            [r, g, b] = hslToRgb(h, s, l);
        }

        // 2. Posterization
        // Apply to the (potentially saturated) colors
        r = Math.round(r / posterizeStep) * posterizeStep;
        g = Math.round(g / posterizeStep) * posterizeStep;
        b = Math.round(b / posterizeStep) * posterizeStep;
        
        // Clamp posterized values to ensure they are within [0, 255]
        r = clamp(r, 0, 255);
        g = clamp(g, 0, 255);
        b = clamp(b, 0, 255);

        // 3. Noise application
        // Apply noise to the posterized colors to give a textured/marker feel
        if (pNoiseStrength > 0) {
            // Generate a noise value (can be positive or negative)
            const noiseVal = (Math.random() - 0.5) * pNoiseStrength;
            r = clamp(r + noiseVal, 0, 255);
            g = clamp(g + noiseVal, 0, 255);
            b = clamp(b + noiseVal, 0, 255);
        }
        
        // Update pixel data
        data[i] = Math.round(r);
        data[i + 1] = Math.round(g);
        data[i + 2] = Math.round(b);
        // data[i + 3] is alpha, typically left unchanged for this kind of filter
    }

    // Put the modified pixel data back onto the canvas
    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 Marker Drawing Filter Effect Tool allows users to transform standard images into artistic representations that mimic marker drawings. By adjusting parameters such as the levels of posterization, noise strength, and saturation, users can create unique visuals that enhance the aesthetic of their images. This tool is useful for artists, designers, and anyone looking to add a creative touch to their photos, whether for personal projects, social media, or graphic design applications.

Leave a Reply

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