Please bookmark this page to avoid losing your image tool!

Image Duotone 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, color1Str = '#581C87', color2Str = '#FDBA74') {
    
    /**
     * Parses a CSS color string into an {r, g, b} object.
     * Supports hex (#RRGGBB, #RGB), rgb(R,G,B), rgba(R,G,B,A),
     * and color names by using the browser's parsing capabilities.
     * Alpha from rgba is ignored for duotone color definition.
     * RGB components are clamped to the 0-255 range.
     * @param {string} colorString - The CSS color string.
     * @returns {{r: number, g: number, b: number}} RGB object, or black if parsing fails.
     */
    function parseColorToRGB(colorString) {
        // 1. Try direct hex parsing (#RRGGBB or #RGB)
        if (colorString.startsWith('#')) {
            let hex = colorString.slice(1);
            if (hex.length === 3) {
                hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
            }
            if (hex.length === 6) {
                const num = parseInt(hex, 16);
                if (!isNaN(num)) {
                    return {
                        r: (num >> 16) & 0xFF,
                        g: (num >> 8) & 0xFF,
                        b: num & 0xFF
                    };
                }
            }
        }

        // 2. Try direct rgb()/rgba() parsing
        // Supports "rgb(R,G,B)" and "rgba(R,G,B,A)"
        // Ignores Alpha from rgba as duotone colors are typically opaque.
        // Clamps values to 0-255.
        let match = colorString.match(/^rgba?\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})(?:,\s*[\d\.]+)?\)$/);
        if (match) {
            const r = Math.max(0, Math.min(255, parseInt(match[1], 10)));
            const g = Math.max(0, Math.min(255, parseInt(match[2], 10)));
            const b = Math.max(0, Math.min(255, parseInt(match[3], 10)));
            return { r, g, b };
        }

        // 3. Fallback to DOM method for color names and other complex formats (hsl, etc.)
        // This is the most robust way to leverage browser's own color parsing.
        // Create a temporary DOM element to apply the color.
        const tempEl = document.createElement('div');
        tempEl.style.color = colorString; 
        // Element must be in the DOM for getComputedStyle to work reliably in all browsers.
        document.body.appendChild(tempEl);
        
        const computedColor = window.getComputedStyle(tempEl).color; // e.g., "rgb(255, 0, 0)" or "rgba(0, 0, 255, 1)"
        document.body.removeChild(tempEl); // Clean up the temporary element

        // Parse the computed color string (which is standardized to rgb or rgba by the browser).
        match = computedColor.match(/^rgba?\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})(?:,\s*[\d\.]+)?\)$/);
        if (match) {
             // Values from getComputedStyle are already valid (0-255).
             const r = parseInt(match[1], 10);
             const g = parseInt(match[2], 10);
             const b = parseInt(match[3], 10);
             return { r, g, b };
        }
        
        // If all parsing attempts fail, issue a warning and default to black.
        console.warn(`Could not parse color: "${colorString}". Defaulting to black.`);
        return { r: 0, g: 0, b: 0 };
    }

    const c1 = parseColorToRGB(color1Str); // Color for dark tones/shadows
    const c2 = parseColorToRGB(color2Str); // Color for light tones/highlights

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

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

    // Handle cases where the image might not be loaded or has no dimensions.
    if (width === 0 || height === 0) {
        // Optionally, log a warning. For now, just return an empty canvas.
        // console.warn("Image has zero width or height. Returning an empty canvas.");
        canvas.width = 0;
        canvas.height = 0;
        return canvas;
    }

    canvas.width = width;
    canvas.height = height;

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

    // Get the pixel data from the canvas.
    const imageData = ctx.getImageData(0, 0, width, height);
    const data = imageData.data; // This is a Uint8ClampedArray: [R, G, B, A, R, G, B, A, ...]

    // Iterate over each pixel (4 bytes: R, G, B, A).
    for (let i = 0; i < data.length; i += 4) {
        const r_orig = data[i];
        const g_orig = data[i + 1];
        const b_orig = data[i + 2];
        // The alpha channel (data[i + 3]) is preserved.

        // Calculate luminance (perceived brightness) using the BT.709 luma coefficients.
        // This converts the pixel to a grayscale value in the range 0-255.
        const luminance = 0.2126 * r_orig + 0.7152 * g_orig + 0.0722 * b_orig;
        
        // Normalize luminance to a 0-1 range.
        // 0 represents black, 1 represents white.
        const grayNormalized = luminance / 255;

        // Interpolate between color1 and color2 based on the normalized luminance.
        // color1 is mapped to the darkest parts of the image (black).
        // color2 is mapped to the lightest parts of the image (white).
        data[i]     = c1.r * (1 - grayNormalized) + c2.r * grayNormalized; // New Red
        data[i + 1] = c1.g * (1 - grayNormalized) + c2.g * grayNormalized; // New Green
        data[i + 2] = c1.b * (1 - grayNormalized) + c2.b * grayNormalized; // New Blue
        // data[i + 3] (alpha) remains unchanged.
    }

    // 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 Duotone Filter Application allows users to apply a duotone color filter to images, transforming them into striking two-color visuals. By specifying two colors, one for the dark tones and another for the light tones, users can create unique artistic effects suitable for graphic design, social media posts, or personal projects. This tool is ideal for enhancing images, creating stylized graphics, or adding a modern aesthetic to photographs.

Leave a Reply

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

Other Image Tools:

Image Cinematic Filter Application

Image Noir Filter Application

Image Vintage Effect Applicator

Image Lens Flare Effect Applicator

Image Vignette Effect Application Tool

Image To Black And White Converter

Image Motion Blur Applicator

Image Glow Effect Applicator

Image Retro Effect Applicator

Image Film Effect Creator

Image Wanted Poster Generator

Image To ASCII Art Converter

Image To The Pink Panther Show Episode Details Finder

Image To Pink Panther Show Episode Details Finder

Image To Big Hero 6 The Series 2017-2021 Show Details Finder

Image To Illumination Entertainment Movie Details Finder

Image To Walt Disney Animation Studios Movie Details Finder

Image To THX Logo History 1983-2023 Search Tool

Image To Thx 1983-2023 Search Tool

20th Century Fox 1935-2020 Variants Image Viewer

Image To Detailed Audio Description Generator

Detailed Dreamworks Image Variant Generator

Image To The Pink Panther Show Episode 1-124 Search Tool

Image To Tubi September 2026 Coming Soon Movie Search Tool

Image To Tubi Sep 2026 Movie Search Tool

Image To Dottie Chicken Movie Search Tool

Image To Gahlina Pintadinha Movie Search Tool

Image and Video Big Hero 6 The Series Search Tool

Image To Illumination Entertainment Movie Search Tool

Image Soft Bubble Overlay Adder

Image Aspect Ratio 20:9 Stretch Tool

Image To Music Search Finder

Image To Movie Details Finder

Image To Walt Disney Animation Studios Movie Search Tool

Beauty and the Beast Special Extended Edition 1991 Movie Info Tool

See All →