Please bookmark this page to avoid losing your image tool!

Image Canvas Texture 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,
    opacity = 0.15,
    textureType = "noise", // "noise" or "lines"
    grainAmount = 0.2,     // For "noise" type: 0.0 to 1.0, fractional strength of noise
    monochromeNoiseStr = "true", // For "noise" type: "true" or "false" for grayscale noise
    lineColor = "rgba(0,0,0,0.05)", // For "lines" type: CSS color string for lines
    lineSpacing = 4,       // For "lines" type: Spacing between lines in pixels
    lineWidth = 1,         // For "lines" type: Width of lines in pixels
    blendMode = "overlay"  // Canvas globalCompositeOperation blend mode
) {
    // Default values for robust parameter parsing (fallback if Number(value) is NaN)
    const defaults = {
        opacity: 0.15,
        grainAmount: 0.2,
        lineSpacing: 4,
        lineWidth: 1,
        // Note: string parameters like textureType, monochromeNoiseStr, lineColor, blendMode
        // will use their provided default if argument is undefined.
        // String() conversion handles nulls to "null", etc.
    };

    let num; // Temporary variable for numeric conversion

    num = Number(opacity);
    const finalOpacity = isNaN(num) ? defaults.opacity : Math.max(0, Math.min(1, num));

    const finalTextureType = String(textureType).toLowerCase();

    num = Number(grainAmount);
    const finalGrainAmount = isNaN(num) ? defaults.grainAmount : Math.max(0, Math.min(1, num));
    
    // Only "true" (case-insensitive) enables monochrome noise. Other strings (incl. "false") disable it.
    const finalMonochromeNoise = String(monochromeNoiseStr).toLowerCase() === "true";
    
    const finalLineColor = String(lineColor); // CSS color strings are generally robust

    num = Number(lineSpacing);
    const finalLineSpacing = isNaN(num) ? defaults.lineSpacing : Math.max(1, Math.floor(num));

    num = Number(lineWidth);
    const finalLineWidth = isNaN(num) ? defaults.lineWidth : Math.max(1, Math.floor(num));
    
    const finalBlendMode = String(blendMode);

    // Main canvas setup
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

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

    if (w === 0 || h === 0) {
        canvas.width = w; // Will be 0
        canvas.height = h; // Will be 0
        return canvas; // Return empty canvas for 0-size image
    }
    canvas.width = w;
    canvas.height = h;

    // 1. Draw the original image onto the main canvas
    ctx.drawImage(originalImg, 0, 0, w, h);

    // 2. Create the texture layer on a separate (temporary) canvas
    const textureCanvas = document.createElement('canvas');
    textureCanvas.width = w;
    textureCanvas.height = h;
    const textureCtx = textureCanvas.getContext('2d');

    if (finalTextureType === "noise") {
        const noiseImageData = textureCtx.createImageData(w, h);
        const noiseData = noiseImageData.data;
        
        // Calculate noise deviation: finalGrainAmount (0-1) scales max deviation from 128.
        // Max deviation from 128 is finalGrainAmount * 127.5.
        // Random factor is in [-1, 1].
        const deviation = finalGrainAmount * 127.5; 

        for (let i = 0; i < noiseData.length; i += 4) {
            let rVal, gVal, bVal;
            const randomFactor = Math.random() * 2 - 1; // Random number in [-1, 1]

            if (finalMonochromeNoise) {
                const noise = 128 + randomFactor * deviation;
                rVal = gVal = bVal = Math.max(0, Math.min(255, noise));
            } else {
                rVal = Math.max(0, Math.min(255, 128 + (Math.random() * 2 - 1) * deviation));
                gVal = Math.max(0, Math.min(255, 128 + (Math.random() * 2 - 1) * deviation));
                bVal = Math.max(0, Math.min(255, 128 + (Math.random() * 2 - 1) * deviation));
            }
            noiseData[i] = rVal;
            noiseData[i + 1] = gVal;
            noiseData[i + 2] = bVal;
            noiseData[i + 3] = 255; // Noise layer is fully opaque
        }
        textureCtx.putImageData(noiseImageData, 0, 0);

    } else if (finalTextureType === "lines") {
        // Create a small pattern canvas for lines
        const patternCanvas = document.createElement('canvas');
        patternCanvas.width = finalLineSpacing;
        patternCanvas.height = finalLineSpacing;
        const pCtx = patternCanvas.getContext('2d');

        pCtx.fillStyle = finalLineColor; // Apply line color (can include alpha)
        
        // Draw a horizontal line at the top of the pattern tile
        pCtx.fillRect(0, 0, finalLineSpacing, finalLineWidth);
        // Draw a vertical line at the left of the pattern tile
        pCtx.fillRect(0, 0, finalLineWidth, finalLineSpacing);
        
        const pattern = textureCtx.createPattern(patternCanvas, 'repeat');
        if (pattern) { // createPattern can return null if dimensions are invalid (though guarded by Math.max(1,...))
            textureCtx.fillStyle = pattern;
            textureCtx.fillRect(0, 0, w, h); // Fill texture canvas with the repeating pattern
        }
    } else {
        // Unknown textureType or "none" specified.
        // In this case, textureCanvas remains transparent (default state).
        // console.warn(`Unknown or unsupported textureType: '${finalTextureType}'. No texture will be applied.`);
    }

    // 3. Blend the texture layer onto the main canvas
    if (finalOpacity > 0) { // No need to blend if texture is fully transparent
        ctx.globalAlpha = finalOpacity;
        // Browsers usually default to 'source-over' for invalid composite operations.
        ctx.globalCompositeOperation = finalBlendMode; 
        ctx.drawImage(textureCanvas, 0, 0, w, h);

        // 4. Reset blending properties on the main context
        ctx.globalAlpha = 1.0;
        ctx.globalCompositeOperation = 'source-over';
    }

    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 Canvas Texture Filter is a tool that allows users to enhance images by applying various texture effects such as noise or lines. Users can customize parameters like opacity, texture type, grain amount, and line characteristics to achieve their desired artistic effects. This utility can be useful for graphic designers, digital artists, or anyone looking to add stylistic textures to their images for projects, presentations, or social media. It can produce subtle noise or line patterns to give photographs or graphics a unique appearance.

Leave a Reply

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