You can edit the below JavaScript code to customize the image tool.
/**
* Changes the color of a specific color region in an image, intended for hair color modification.
*
* This function works by identifying pixels that are close to a specified `sourceColor`
* and replacing them with a `newColor`, while attempting to preserve the original image's
* highlights and shadows for a more realistic effect.
*
* @param {Image} originalImg The original Image object to process.
* @param {string} sourceColor The hex color string representing the hair color to be changed in the original image (e.g., '#4d2d1f' for brown).
* @param {string} newColor The target hex color string for the new hair color (e.g., '#9d179d' for purple).
* @param {number} tolerance A value from 0 to 255 determining how close a pixel's color must be to the `sourceColor` to be replaced. Higher values affect a wider range of colors.
* @param {number} blend A value from 0.0 to 1.0 that controls the blend between the original pixel's brightness and the new color's brightness. 1.0 fully preserves original brightness, 0.0 uses the new color's brightness.
* @returns {HTMLCanvasElement} A canvas element with the modified image.
*/
function processImage(originalImg, sourceColor = '#4d2d1f', newColor = '#9d179d', tolerance = 50, blend = 0.85) {
// --- Helper Functions ---
/** Converts a HEX color string to an RGB object. */
function hexToRgb(hex) {
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
hex = hex.replace(shorthandRegex, (m, r, g, b) => r + r + g + g + b + b);
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
}
/** Converts an RGB color value to HSL. */
function rgbToHsl(r, g, b) {
r /= 255, g /= 255, b /= 255;
const max = Math.max(r, g, b),
min = Math.min(r, g, b);
let h, s, l = (max + min) / 2;
if (max === min) {
h = s = 0; // achromatic
} else {
const d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return [h, s, l];
}
/** Converts an HSL color value to RGB. */
function hslToRgb(h, s, l) {
let r, g, b;
if (s === 0) {
r = g = b = l; // achromatic
} else {
const hue2rgb = (p, q, t) => {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 3) return q;
if (t < 1 / 2) return p + (q - p) * (2 / 3 - t) * 6;
return p;
};
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
// --- Main Logic ---
const canvas = document.createElement('canvas');
// Use { willReadFrequently: true } for performance optimization with repeated getImageData/putImageData calls.
const ctx = canvas.getContext('2d', { willReadFrequently: true });
canvas.width = originalImg.naturalWidth;
canvas.height = originalImg.naturalHeight;
ctx.drawImage(originalImg, 0, 0);
const sourceRgb = hexToRgb(sourceColor);
const newRgb = hexToRgb(newColor);
if (!sourceRgb || !newRgb) {
console.error("Invalid hex color provided. Please use format like '#RRGGBB'.");
return canvas; // Return the original image on canvas
}
const newHsl = rgbToHsl(newRgb.r, newRgb.g, newRgb.b);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
// Calculate the color distance between the current pixel and the source color.
// A simple Euclidean distance in the RGB space works well.
const distance = Math.sqrt(
Math.pow(r - sourceRgb.r, 2) +
Math.pow(g - sourceRgb.g, 2) +
Math.pow(b - sourceRgb.b, 2)
);
if (distance < tolerance) {
const originalHsl = rgbToHsl(r, g, b);
// Create the new color while preserving the original pixel's lightness.
// This is key to keeping shadows and highlights realistic.
const blendedLightness = originalHsl[2] * blend + newHsl[2] * (1 - blend);
const finalRgb = hslToRgb(newHsl[0], newHsl[1], blendedLightness);
data[i] = finalRgb[0];
data[i + 1] = finalRgb[1];
data[i + 2] = finalRgb[2];
}
}
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!
The Image Hair Color Change Tool allows users to modify the hair color in an image with ease. By selecting a source hair color and a new color, users can instantly change the appearance of hair in photos while ensuring that highlights and shadows are preserved for a more realistic look. This tool is useful for people looking to visualize hair color changes, for hair stylists showcasing different color options to clients, or for social media users wanting to enhance their images creatively.