You can edit the below JavaScript code to customize the image tool.
// Helper functions for RGB-HSL conversion
// Source: Based on standard formulas, e.g., https://www.niwa.nu/2013/05/math-behind-colorspace-conversions-rgb-hsl/
// and https://github.com/Qix-/color-convert/blob/master/conversions.js
function rgbToHsl(r, g, b) {
r /= 255; g /= 255; b /= 255;
const max = Math.max(r, g, b);
const 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];
}
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 / 2) return q;
if (t < 2 / 3) 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)];
}
/**
* Adjusts the image to simulate more balanced lighting from the left and right sides.
* This effect brightens the horizontal edges of the image, with a stronger effect
* applied to darker areas. This can help reduce the appearance of strong central
* or uni-directional lighting.
*
* @param {HTMLImageElement} originalImg The original image object. Assumed to be loaded.
* @param {number} strength A value typically between 0.0 and 1.0 that controls the
* intensity of the lighting effect. Higher values produce
* a stronger effect. Defaults to 0.15.
* @returns {HTMLCanvasElement} A canvas element with the processed image.
*/
function processImage(originalImg, strength = 0.15) {
const canvas = document.createElement('canvas');
// Using { willReadFrequently: true } hints to the browser that we'll be reading pixel data frequently,
// which can lead to performance optimizations in some browsers.
const ctx = canvas.getContext('2d', { willReadFrequently: true });
const imgWidth = originalImg.naturalWidth || originalImg.width;
const imgHeight = originalImg.naturalHeight || originalImg.height;
if (imgWidth === 0 || imgHeight === 0) {
console.warn("ImageNaturalLightingBalanceTool: Image has zero width or height. Returning empty canvas.");
canvas.width = 0;
canvas.height = 0;
return canvas;
}
canvas.width = imgWidth;
canvas.height = imgHeight;
ctx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
// Clamp strength to a reasonable range (e.g., 0 to 1) to prevent overly extreme results.
const effStrength = Math.max(0, Math.min(1, strength));
try {
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
const width = canvas.width;
const height = canvas.height;
// midX is the center horizontal coordinate.
// For width=1, midX=0. For width=2, midX=0.5. For width=3, midX=1.
const midX = (width - 1) / 2;
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const i = (y * width + x) * 4;
let r = data[i];
let g = data[i + 1];
let b = data[i + 2];
// Alpha data[i+3] is preserved by default.
// Convert RGB to HSL
let [h, s, l_original] = rgbToHsl(r, g, b);
// Calculate the geometric factor for adjustment.
// This factor is 0 at the horizontal center and 1 at the horizontal edges.
let norm_dist_from_center_sq;
if (width <= 1 || midX === 0 && width > 0) {
// No horizontal dimension to apply side lighting (e.g. 1px wide image)
// or midX is 0 (width=1), division by midX would be an issue.
norm_dist_from_center_sq = 0;
} else {
// Parabolic factor: ((x - midX) / midX)^2
// This creates a smooth gradient of effect, strongest at edges.
norm_dist_from_center_sq = ((x - midX) / midX) ** 2;
}
// Calculate the change in lightness.
// The effect is proportional to:
// - effStrength: User-controlled intensity.
// - norm_dist_from_center_sq: Geometric factor (stronger at edges).
// - (1 - l_original): How dark the pixel currently is (stronger for darker pixels).
const lightnessChange = effStrength * norm_dist_from_center_sq * (1 - l_original);
let new_l = l_original + lightnessChange;
// Clamp new_l to the valid [0, 1] HSL lightness range.
new_l = Math.max(0, Math.min(1, new_l));
// Convert back to RGB
[r, g, b] = hslToRgb(h, s, new_l);
data[i] = r;
data[i + 1] = g;
data[i + 2] = b;
}
}
ctx.putImageData(imageData, 0, 0);
} catch (e) {
// This error can occur if the image is loaded from a different origin (cross-origin)
// and the server does not send appropriate CORS headers (e.g., Access-Control-Allow-Origin).
// In such cases, the canvas becomes "tainted", and getImageData will fail.
console.error("ImageNaturalLightingBalanceTool: Error processing image data. This might be due to CORS policy if the image is from a different origin.", e);
// If getImageData fails, the canvas currently holds the original image (drawn by drawImage).
// The function will return this canvas. The user might not be able to export it (e.g. toDataURL()) if it's tainted.
}
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 Natural Lighting Balance Tool is designed to enhance the lighting balance in images by brightening the edges while maintaining the overall aesthetic. It simulates more natural lighting by reducing the prominence of strong central or directional lights, making it particularly useful for photographers and graphic designers looking to improve the visual quality of their images. This tool can be helpful in scenarios such as preparing photos for social media, enhancing images for portfolios, or adjusting visuals for presentations to create a more balanced and appealing look.