Please bookmark this page to avoid losing your image tool!

Image Subtle Grain 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, grainAmountParam = 20, monochromaticStrParam = "true") {
    // Parse and validate grainAmountParam
    let grainAmount = Number(grainAmountParam);
    if (isNaN(grainAmount) || grainAmount < 0) {
        console.warn(`Invalid grainAmount: "${grainAmountParam}". It must be a non-negative number. Using default value 20.`);
        grainAmount = 20; // Default value if parsing fails or input is invalid
    }

    // Parse monochromaticStrParam
    const isMonochromatic = monochromaticStrParam.toLowerCase() === "true";

    // Create a new canvas element
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    // Determine image dimensions. Use naturalWidth/Height for intrinsic dimensions.
    // Fallback to width/height if naturalWidth/Height are 0 (e.g., image not loaded yet for some reason, or it's an SVG without intrinsic dimensions).
    const imgWidth = originalImg.naturalWidth || originalImg.width;
    const imgHeight = originalImg.naturalHeight || originalImg.height;

    // Handle cases where image dimensions are not valid (e.g., image not loaded)
    if (imgWidth === 0 || imgHeight === 0) {
        console.error("Image has zero dimensions. This may be due to the image not being loaded yet, or an invalid image source.");
        // Return a small, empty canvas as a fallback
        canvas.width = 1;
        canvas.height = 1;
        // Optionally, fill it with a color to indicate an issue, though a transparent 1x1 pixel might be less intrusive.
        // ctx.fillStyle = 'rgba(255,0,0,0.5)'; // Example: semi-transparent red
        // ctx.fillRect(0, 0, 1, 1);
        return canvas;
    }

    // Set canvas dimensions to match the image
    canvas.width = imgWidth;
    canvas.height = imgHeight;

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

    // Get the image data from the canvas
    // Note: getImageData can be slow for very large images.
    const imageData = ctx.getImageData(0, 0, imgWidth, imgHeight);
    const data = imageData.data; // This is a Uint8ClampedArray

    // Iterate over each pixel in the image data array
    // data is a flat array: [R1, G1, B1, A1, R2, G2, B2, A2, ...]
    for (let i = 0; i < data.length; i += 4) {
        // R, G, B values are at i, i+1, i+2. Alpha is at i+3.

        if (isMonochromatic) {
            // Monochromatic grain: add the same random noise value to R, G, and B
            // Math.random() returns a float between 0 (inclusive) and 1 (exclusive).
            // (Math.random() - 0.5) shifts this to [-0.5, 0.5).
            // Multiplying by grainAmount scales the noise.
            // E.g., if grainAmount is 20, noise is in [-10, 10).
            const noise = (Math.random() - 0.5) * grainAmount;
            data[i]     += noise; // Red channel
            data[i + 1] += noise; // Green channel
            data[i + 2] += noise; // Blue channel
        } else {
            // Chromatic (color) grain: add different random noise values to R, G, and B
            data[i]     += (Math.random() - 0.5) * grainAmount; // Red channel
            data[i + 1] += (Math.random() - 0.5) * grainAmount; // Green channel
            data[i + 2] += (Math.random() - 0.5) * grainAmount; // Blue channel
        }
        
        // The Alpha channel (data[i + 3]) is typically left unchanged for a grain filter.

        // Clamping: Values in a Uint8ClampedArray are automatically clamped to the 0-255 range.
        // So, explicit Math.max(0, Math.min(255, value)) is not strictly needed here.
        // If `data` were a regular Array, explicit clamping would be essential.
    }

    // Put the modified image data back onto the canvas
    ctx.putImageData(imageData, 0, 0);

    // Return the canvas with the applied grain effect
    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 Subtle Grain Texture Filter allows users to apply a subtle grain effect to their images. This tool can enhance the visual texture of photos, making them appear more cinematic or artistically aged. Users can adjust the amount of grain applied and choose between a monochromatic or chromatic grain effect. It is ideal for photographers, graphic designers, and anyone looking to add a unique stylistic touch to their digital images.

Leave a Reply

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