Please bookmark this page to avoid losing your image tool!

Image Color Curves Adjuster

(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.
/**
 * Adjusts the color curves of an image based on control points for each color channel.
 * This function processes the image pixel by pixel, applying a transformation for each
 * R, G, B, and A channel based on a curve defined by a set of points. The curve
 * is constructed by linearly interpolating between the provided control points.
 *
 * @param {Image} originalImg The original HTML Image object.
 * @param {string} [redPoints="0,0;255,255"] A string of semicolon-separated control points for the red channel, e.g., "0,0;128,150;255,255". Each point is "x,y", where x is the input intensity (0-255) and y is the output intensity (0-255).
 * @param {string} [greenPoints="0,0;255,255"] Control points for the green channel.
 * @param {string} [bluePoints="0,0;255,255"] Control points for the blue channel.
 * @param {string} [alphaPoints="0,0;255,255"] Control points for the alpha channel.
 * @returns {HTMLCanvasElement} A new canvas element with the color curve adjustments applied.
 */
function processImage(originalImg, redPoints = "0,0;255,255", greenPoints = "0,0;255,255", bluePoints = "0,0;255,255", alphaPoints = "0,0;255,255") {

    /**
     * Generates a Look-Up Table (LUT) from a string of control points.
     * The LUT is a 256-element array that maps an input value (index) to an output value.
     * @param {string} pointsStr - A string of points like "x1,y1;x2,y2;...".
     * @returns {Uint8ClampedArray} - A 256-element array for value mapping.
     */
    const generateLUT = (pointsStr) => {
        // 1. Parse string into an array of {x, y} point objects.
        let points = pointsStr.split(';')
            .map(p => {
                const parts = p.split(',').map(Number);
                if (parts.length === 2 && !isNaN(parts[0]) && !isNaN(parts[1])) {
                    // Clamp input points to the valid 0-255 range
                    return {
                        x: Math.max(0, Math.min(255, Math.round(parts[0]))),
                        y: Math.max(0, Math.min(255, Math.round(parts[1])))
                    };
                }
                return null;
            })
            .filter(p => p !== null);

        // 2. Ensure the curve starts at x=0 and ends at x=255.
        // Add default start/end points if they aren't defined by the user.
        if (!points.some(p => p.x === 0)) {
            points.push({ x: 0, y: 0 });
        }
        if (!points.some(p => p.x === 255)) {
            points.push({ x: 255, y: 255 });
        }
        
        // 3. Remove duplicate x-values, keeping the last one specified.
        points = Object.values(points.reduce((acc, point) => {
            acc[point.x] = point;
            return acc;
        }, {}));

        // 4. Sort points by x-coordinate to prepare for interpolation.
        points.sort((a, b) => a.x - b.x);

        const lut = new Uint8ClampedArray(256);
        let p1_idx = 0;

        // 5. Populate the LUT by interpolating between control points.
        for (let i = 0; i < 256; i++) {
            // Find the segment [p1, p2] that the current level `i` falls into.
            if (i > points[p1_idx + 1].x) {
                p1_idx++;
            }
            const p1 = points[p1_idx];
            const p2 = points[p1_idx + 1];

            if (p2.x === p1.x) { // Avoid division by zero for vertical segments.
                lut[i] = p1.y;
            } else {
                // `t` is the progression (from 0 to 1) of `i` between p1.x and p2.x.
                const t = (i - p1.x) / (p2.x - p1.x);
                // Linearly interpolate the y-value.
                const value = p1.y * (1 - t) + p2.y * t;
                lut[i] = value; // Uint8ClampedArray automatically clamps value to 0-255.
            }
        }
        return lut;
    };

    // --- Main function execution ---

    const canvas = document.createElement('canvas');
    // Using { willReadFrequently: true } can optimize repeated getImageData calls.
    const ctx = canvas.getContext('2d', { willReadFrequently: true });
    canvas.width = originalImg.naturalWidth || originalImg.width;
    canvas.height = originalImg.naturalHeight || originalImg.height;

    ctx.drawImage(originalImg, 0, 0);

    let imageData;
    try {
        imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    } catch (e) {
        console.error("Could not get image data. This may be due to a cross-origin (CORS) issue if the image is from a different domain.", e);
        // Display an error message on the canvas.
        ctx.font = "16px sans-serif";
        ctx.fillStyle = "red";
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = "white";
        ctx.textAlign = "center";
        ctx.fillText("Could not process image due to CORS policy.", canvas.width / 2, canvas.height / 2);
        return canvas;
    }

    const data = imageData.data;

    // Generate a LUT for each color channel.
    const redLUT = generateLUT(redPoints);
    const greenLUT = generateLUT(greenPoints);
    const blueLUT = generateLUT(bluePoints);
    const alphaLUT = generateLUT(alphaPoints);

    // Apply the LUTs to each pixel in the image.
    for (let i = 0; i < data.length; i += 4) {
        data[i] = redLUT[data[i]];           // Red channel
        data[i + 1] = greenLUT[data[i + 1]]; // Green channel
        data[i + 2] = blueLUT[data[i + 2]];   // Blue channel
        data[i + 3] = alphaLUT[data[i + 3]];   // Alpha channel
    }

    // 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 Color Curves Adjuster is a web-based tool that allows users to modify the color curves of images by adjusting the intensity of the red, green, blue, and alpha channels through a series of control points. By specifying these control points, users can create customized color transformations, enhancing or altering the visual appearance of their images. This tool is useful for photographers and graphic designers looking to fine-tune color grading, create stylized effects, or correct color imbalances in their images.

Leave a Reply

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