Please bookmark this page to avoid losing your image tool!

Image Gradient Map 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, gradientColorsStr = "black,white") {
    // Helper function to parse color strings (e.g., "red", "#FF0000", "rgb(255,0,0)", "rgba(255,0,0,0.5)")
    // Returns an object {r, g, b, a} with components in the range 0-255.
    // Invalid color strings will typically parse as black (rgba(0,0,0,255)).
    function parseColor(colorStr) {
        const canvas = document.createElement('canvas');
        canvas.width = 1;
        canvas.height = 1;
        // Use { willReadFrequently: true } for potential performance optimization if this context is used heavily for getImageData.
        const ctx = canvas.getContext('2d', { willReadFrequently: true });
        
        ctx.fillStyle = colorStr;
        ctx.fillRect(0, 0, 1, 1);
        
        const data = ctx.getImageData(0, 0, 1, 1).data;
        return { r: data[0], g: data[1], b: data[2], a: data[3] };
    }

    // Helper function for linear interpolation between two values.
    function lerp(start, end, t) {
        return start * (1 - t) + end * t;
    }

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

    // If the image has zero width or height (e.g., not loaded or it's an empty image),
    // return the empty canvas without further processing.
    if (outputCanvas.width === 0 || outputCanvas.height === 0) {
        return outputCanvas;
    }

    const ctx = outputCanvas.getContext('2d', { 
        //willReadFrequently is a hint for the browser for optimization if available
        willReadFrequently: true 
    });

    // Draw the original image onto the output canvas.
    // This draws the image at its natural size.
    ctx.drawImage(originalImg, 0, 0);

    // Get the pixel data from the canvas.
    // This can throw a security error if the image is cross-origin and the canvas is tainted.
    // Ensure the image is served with appropriate CORS headers if it's from a different origin.
    let imageData;
    try {
        imageData = ctx.getImageData(0, 0, outputCanvas.width, outputCanvas.height);
    } catch (e) {
        console.error("Error getting ImageData: ", e);
        // Return the canvas with the original image drawn, as filtering can't proceed.
        // Or, could throw the error to let the caller handle it.
        // For this example, we'll return the canvas as is.
        return outputCanvas;
    }
    
    const data = imageData.data; // This is a Uint8ClampedArray: [R, G, B, A, R, G, B, A, ...]

    // Parse the gradientColorsStr string into an array of color objects.
    // Handles strings like "red, green, blue" or "#FF0000, #00FF00, #0000FF".
    const colorStopsInput = gradientColorsStr.split(',')
                                           .map(s => s.trim()) // Remove whitespace around color names/codes
                                           .filter(s => s !== ""); // Remove empty strings if input was e.g. "red,,blue"
    
    // If, after parsing, no valid color stops are found (e.g., empty input string),
    // default to a black-to-white gradient.
    if (colorStopsInput.length === 0) {
        colorStopsInput.push("black", "white");
    }
    
    const parsedColors = colorStopsInput.map(parseColor);

    // Apply the gradient map filter to each pixel.
    if (parsedColors.length === 1) {
        // If only one color is provided in the gradient, map all pixels to this single color.
        // The original alpha of pixels is replaced by this color's alpha.
        const singleColor = parsedColors[0];
        for (let i = 0; i < data.length; i += 4) {
            data[i]     = singleColor.r; // Red
            data[i + 1] = singleColor.g; // Green
            data[i + 2] = singleColor.b; // Blue
            data[i + 3] = singleColor.a; // Alpha
        }
    } else {
        // If multiple colors are provided, interpolate between
        // them based on each pixel's luminance.
        for (let i = 0; i < data.length; i += 4) {
            const r = data[i];
            const g = data[i + 1];
            const b = data[i + 2];
            // Calculate luminance using the NTSC/BT.601 standard formula.
            // (Values r,g,b are already in 0-255 range from ImageData)
            const luminance = (0.299 * r + 0.587 * g + 0.114 * b);
            
            // Normalize luminance to the [0, 1] range.
            const normalizedLuminance = luminance / 255.0;

            // Determine the position in the gradient array based on normalized luminance.
            // This maps normalizedLuminance [0,1] to an effective index in [0, parsedColors.length - 1].
            const gradientPos = normalizedLuminance * (parsedColors.length - 1);
            
            // Find the two colors in the gradient to interpolate between.
            const idx1 = Math.floor(gradientPos);
            // Ensure idx2 is within the bounds of the parsedColors array.
            // This handles the edge case where gradientPos is exactly parsedColors.length - 1.
            const idx2 = Math.min(parsedColors.length - 1, Math.ceil(gradientPos)); 
            
            // Calculate the interpolation factor 't'.
            // This will be 0 if gradientPos is an integer, or a fraction if between integers.
            const t = gradientPos - idx1;

            const color1 = parsedColors[idx1];
            const color2 = parsedColors[idx2];

            // Interpolate R, G, B, and Alpha components.
            data[i]     = lerp(color1.r, color2.r, t);
            data[i + 1] = lerp(color1.g, color2.g, t);
            data[i + 2] = lerp(color1.b, color2.b, t);
            data[i + 3] = lerp(color1.a, color2.a, t);
        }
    }

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

    return outputCanvas;
}

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 Gradient Map Filter tool allows users to apply a gradient color mapping to images. By providing a set of colors, users can transform their images into visually striking representations, where the brightness or luminance of each pixel is mapped to a specified color gradient. This tool is particularly useful for graphic designers, artists, and photographers who wish to enhance their images creatively, create unique visual effects, or generate artwork by applying artistic filters to their photos. Users can customize the gradient by specifying various colors, enabling a wide range of artistic possibilities.

Leave a Reply

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