Image Adjustment in the Browser — Brightness, Contrast, Saturation Without Libraries
Image Adjustment in the Browser — Brightness, Contrast, Saturation Without Libraries CSS filter handles simple visual effects. For pixel-level control — downloadable output, real adjustment values — you need Canvas and
Image Adjustment in the Browser — Brightness, Contrast, Saturation Without Libraries
CSS filter handles simple visual effects. For pixel-level control — downloadable output, real adjustment values — you need Canvas and pixel manipulation.
Getting Pixel Data
async function getImageData(file) {
const img = await loadImage(file);
const canvas = document.createElement('canvas');
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
canvas.getContext('2d').drawImage(img, 0, 0);
return canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height);
}
Brightness
Brightness adds or subtracts from each channel:
function applyBrightness(data, value) {
// value: -100 to +100
const factor = value * 2.55;
for (let i = 0; i < data.length; i += 4) {
data[i] = Math.min(255, Math.max(0, data[i] + factor));
data[i + 1] = Math.min(255, Math.max(0, data[i + 1] + factor));
data[i + 2] = Math.min(255, Math.max(0, data[i + 2] + factor));
}
}
Contrast
Contrast expands or compresses the range around the midpoint (128):
function applyContrast(data, value) {
// value: -100 to +100
const factor = (259 * (value + 255)) / (255 * (259 - value));
for (let i = 0; i < data.length; i += 4) {
data[i] = Math.min(255, Math.max(0, factor * (data[i] - 128) + 128));
data[i + 1] = Math.min(255, Math.max(0, factor * (data[i + 1] - 128) + 128));
data[i + 2] = Math.min(255, Math.max(0, factor * (data[i + 2] - 128) + 128));
}
}
Saturation
Saturation requires converting to HSL, adjusting S, and converting back:
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; }
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)) / 6; break;
case g: h = ((b - r) / d + 2) / 6; break;
case b: h = ((r - g) / d + 4) / 6; break;
}
}
return [h, s, l];
}
Sharpness (Unsharp Mask)
Sharpness isn't a simple per-pixel operation — it requires a convolution:
function applySharpness(imageData, strength) {
const kernel = [
0, -strength, 0,
-strength, 1 + 4 * strength, -strength,
0, -strength, 0
];
return convolve(imageData, kernel);
}
Performance
Processing a 4000×3000 image (48MB of raw pixel data) takes ~200ms in JavaScript. For a preview, work at 1/4 resolution and only process full resolution on download.
Adjust images at toolzip.app/tools/image-adjust.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.