Please bookmark this page to avoid losing your image tool!

Image Monochrome Color Filter Application

(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, colorStr = "255,255,255") {

    // Helper function to parse color string (e.g., "r,g,b", "#RRGGBB", "RRGGBB", "#RGB", "RGB")
    // Defaults to R=255, G=255, B=255 if parsing fails or input is invalid/empty.
    // This default (white as target) will make the monochrome filter produce a grayscale image.
    function _parseMonochromeTargetColor(inputColorStr) {
        let r = 255, g = 255, b = 255; // Default: white (results in grayscale)

        // Handle cases where inputColorStr is not a string or is an empty/whitespace string
        if (typeof inputColorStr !== 'string' || inputColorStr.trim() === "") {
            // This path is taken if colorStr was not provided to processImage (which means it uses its default "255,255,255"),
            // or if it was explicitly null, undefined, or an empty/whitespace string.
            // No warning needed here, just use the already set default {r:255, g:255, b:255}.
            return { r, g, b };
        }

        const trimmedStr = inputColorStr.trim().toLowerCase();

        // Try parsing "r,g,b" format
        if (trimmedStr.includes(',')) {
            const parts = trimmedStr.split(',');
            if (parts.length === 3) {
                const pr = parseInt(parts[0], 10);
                const pg = parseInt(parts[1], 10);
                const pb = parseInt(parts[2], 10);
                // Check if all parts were valid numbers
                if (!isNaN(pr) && !isNaN(pg) && !isNaN(pb)) {
                    // Clamp values to 0-255 range
                    r = Math.max(0, Math.min(255, pr));
                    g = Math.max(0, Math.min(255, pg));
                    b = Math.max(0, Math.min(255, pb));
                    return { r, g, b };
                }
            }
        } else { // Try parsing hex format
            let hex = trimmedStr;
            if (hex.startsWith('#')) {
                hex = hex.substring(1);
            }

            // Check if it's a valid hex string (consists of hex characters)
            if (/^[0-9a-f]+$/.test(hex)) { // Test against lowercase hex
                if (hex.length === 6) { // RRGGBB
                    r = parseInt(hex.substring(0, 2), 16);
                    g = parseInt(hex.substring(2, 4), 16);
                    b = parseInt(hex.substring(4, 6), 16);
                    return { r, g, b };
                } else if (hex.length === 3) { // RGB
                    r = parseInt(hex.charAt(0) + hex.charAt(0), 16);
                    g = parseInt(hex.charAt(1) + hex.charAt(1), 16);
                    b = parseInt(hex.charAt(2) + hex.charAt(2), 16);
                    return { r, g, b };
                }
            }
        }
        
        // If parsing failed for a non-empty, non-null, string that wasn't recognized
        console.warn(`Invalid color string format: "${inputColorStr}". Defaulting to monochrome target R=255,G=255,B=255 (this will result in a grayscale image).`);
        return { r: 255, g: 255, b: 255 }; // Return default for parsing failure
    }

    const targetColor = _parseMonochromeTargetColor(colorStr);
    const TR = targetColor.r;
    const TG = targetColor.g;
    const TB = targetColor.b;

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

    if (!ctx) {
        // This should not happen in modern browsers that support canvas.
        console.error("Canvas 2D context is not available. This tool requires a browser with Canvas support.");
        const errorElement = document.createElement('p');
        errorElement.textContent = "Error: Canvas 2D context is not supported in your browser.";
        return errorElement;
    }
    
    // Use naturalWidth/Height for actual image dimensions, fallback to width/height
    // This ensures we process the image at its native resolution if available.
    const imgWidth = originalImg.naturalWidth || originalImg.width;
    const imgHeight = originalImg.naturalHeight || originalImg.height;

    // Handle cases where the image might not be loaded or has no dimensions
    if (imgWidth === 0 || imgHeight === 0) {
        console.warn("Input image has zero width or height. This might be due to the image not being fully loaded or an invalid image source. Returning an empty canvas.");
        canvas.width = 0;
        canvas.height = 0;
        return canvas; // Return an empty but valid canvas
    }

    canvas.width = imgWidth;
    canvas.height = imgHeight;

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

    let imageData;
    try {
        // Get pixel data from the canvas
        imageData = ctx.getImageData(0, 0, imgWidth, imgHeight);
    } catch (e) {
        // This error can occur if the canvas is "tainted", e.g., by drawing a cross-origin image
        // without proper CORS headers.
        console.error("Failed to get image data from canvas. This may be due to cross-origin restrictions (CORS). Error: ", e.message);
        const errorElement = document.createElement('p');
        // Provide mildly more informative error message for display.
        errorElement.innerHTML = `Error processing image: Could not access pixel data. <br>If you are using an image from another website, please ensure it allows cross-origin access. <br><small>Technical details: ${e.message}</small>`;
        return errorElement;
    }
    
    const data = imageData.data; // This is a Uint8ClampedArray: [R,G,B,A, R,G,B,A, ...]

    // Iterate over each pixel (each pixel is 4 components: R,G,B,A)
    for (let i = 0; i < data.length; i += 4) {
        const r = data[i];     // Red component of the original pixel
        const g = data[i + 1]; // Green component
        const b = data[i + 2]; // Blue component
        const a = data[i + 3]; // Alpha (opacity) component

        // Calculate luminance using the standard Rec. 601 formula (commonly used for NTSC color perception)
        // L = 0.299*R + 0.587*G + 0.114*B
        // Luminance effectively represents the brightness of the pixel.
        const luminance = (0.299 * r + 0.587 * g + 0.114 * b);
        
        // The new color for the pixel will be shades of the targetColor,
        // scaled by the luminance of the original pixel.
        // (luminance / 255) gives a scaling factor between 0 (for black) and 1 (for white).
        data[i]   = Math.round((luminance / 255) * TR); // New Red
        data[i+1] = Math.round((luminance / 255) * TG); // New Green
        data[i+2] = Math.round((luminance / 255) * TB); // New Blue
        // Alpha channel is preserved from the original image
        data[i+3] = a; 
    }

    // Write the modified pixel data back to 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 Monochrome Color Filter Application allows users to apply a monochrome color filter to images, converting them into shades of a selected color. By specifying a target color, either in RGB format or hex code, users can customize the monochrome effect, which is useful for artistic editing, branding visuals, or creating thematic images. The tool automatically defaults to a grayscale filter if no target color is provided. This can be particularly advantageous for graphic designers, photographers, and content creators looking to enhance their imagery with a distinct monochrome style.

Leave a Reply

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