Please bookmark this page to avoid losing your image tool!

Image Tritone Filter 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, shadowColor = "#502D16", midtoneColor = "#A07050", highlightColor = "#F0E0D0") {

    /**
     * Parses a hex color string (e.g., "#RRGGBB" or "#RGB") into an array [R, G, B].
     * Returns [0, 0, 0] (black) for invalid input.
     */
    function parseHexColor(hexStr) {
        let hex = typeof hexStr === 'string' ? hexStr.trim() : ''; // Ensure hexStr is a string
        hex = hex.startsWith('#') ? hex.slice(1) : hex;
        
        if (hex.length === 3) {
            // Expand 3-digit hex to 6-digit hex (e.g., "F00" to "FF0000")
            hex = hex.split('').map(char => char + char).join('');
        }

        // Validate hex string format (must be 6 hex characters)
        if (hex.length !== 6 || !/^[0-9a-fA-F]{6}$/.test(hex)) {
            console.warn(`Invalid hex color string: "${hexStr}". Using black [0,0,0] as fallback.`);
            return [0, 0, 0]; 
        }

        const r = parseInt(hex.substring(0, 2), 16);
        const g = parseInt(hex.substring(2, 4), 16);
        const b = parseInt(hex.substring(4, 6), 16);

        // Check if parsing resulted in valid numbers
        if (isNaN(r) || isNaN(g) || isNaN(b)) {
            console.warn(`Failed to parse hex color components for "${hexStr}". Using black [0,0,0] as fallback.`);
            return [0, 0, 0];
        }
        return [r, g, b];
    }

    const shadowRGB = parseHexColor(shadowColor);
    const midtoneRGB = parseHexColor(midtoneColor);
    const highlightRGB = parseHexColor(highlightColor);

    const canvas = document.createElement('canvas');
    // Use naturalWidth/Height for the intrinsic dimensions of the image
    const width = originalImg.naturalWidth;
    const height = originalImg.naturalHeight;

    if (width === 0 || height === 0) {
        console.warn("Image has zero intrinsic dimensions. Returning an empty 0x0 canvas.");
        // Set canvas dimensions to 0x0 if image is not loaded or has no size
        canvas.width = 0;
        canvas.height = 0;
        return canvas;
    }

    canvas.width = width;
    canvas.height = height;
    
    // Get 2D rendering context.
    // Using { willReadFrequently: true } can be a performance hint for some browsers
    // but is not universally supported or always beneficial. Standard usage is fine.
    const ctx = canvas.getContext('2d');
    if (!ctx) {
        console.error("Could not get 2D context from canvas. Tritone filter cannot be applied.");
        return canvas; // Return empty canvas if context cannot be obtained
    }


    try {
        ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
    } catch (e) {
        console.error("Error drawing image onto canvas:", e);
        // If drawImage fails, the canvas will be blank or incomplete.
        // Return the canvas in its current state.
        return canvas; 
    }

    let imageData;
    try {
        imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    } catch (e) {
        console.warn("Could not get image data (e.g., CORS issue). Tritone filter cannot be applied. Returning canvas with original image.", e);
        // If getImageData fails (e.g., due to a tainted canvas from cross-origin image),
        // we cannot process the pixels. Return the canvas with the original image drawn on it.
        return canvas;
    }
    
    const data = imageData.data; // This is a Uint8ClampedArray

    for (let i = 0; i < data.length; i += 4) {
        const r = data[i];
        const g = data[i + 1];
        const b = data[i + 2];
        // Alpha channel (data[i + 3]) is preserved

        // Calculate luminance using the standard NTSC conversion formula (perceived brightness)
        const luminance = 0.299 * r + 0.587 * g + 0.114 * b;
        
        // Normalize luminance to a 0-1 range
        const normLuminance = luminance / 255.0; 

        let newR, newG, newB;

        if (normLuminance < 0.5) {
            // Interpolate between shadowColor and midtoneColor for the lower half of luminance
            const t = normLuminance * 2.0; // Map luminance [0, 0.5) to t [0, 1)
            newR = (1 - t) * shadowRGB[0] + t * midtoneRGB[0];
            newG = (1 - t) * shadowRGB[1] + t * midtoneRGB[1];
            newB = (1 - t) * shadowRGB[2] + t * midtoneRGB[2];
        } else {
            // Interpolate between midtoneColor and highlightColor for the upper half of luminance
            const t = (normLuminance - 0.5) * 2.0; // Map luminance [0.5, 1] to t [0, 1]
            newR = (1 - t) * midtoneRGB[0] + t * highlightRGB[0];
            newG = (1 - t) * midtoneRGB[1] + t * highlightRGB[1];
            newB = (1 - t) * midtoneRGB[2] + t * highlightRGB[2];
        }

        // Assign new RGB values, clamping and rounding to nearest integer
        data[i] = Math.round(newR);
        data[i + 1] = Math.round(newG);
        data[i + 2] = Math.round(newB);
    }

    // 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 Tritone Filter Tool allows users to apply a tritone color effect to their images. This tool takes an original image and transforms its colors into three distinct shades based on user-defined shadow, midtone, and highlight colors. It can enhance images by creating stylized effects suitable for artistic rendering, graphic design, or various creative projects. This tool is useful for anyone looking to give their images a unique look or for designers needing to match specific color palettes.

Leave a Reply

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