A Pen by Jake Brown on CodePen.
Created
April 15, 2023 01:38
-
-
Save jake-sl/84a47f140561f66d0dad0d5658163798 to your computer and use it in GitHub Desktop.
vYVGyyo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<body> | |
<input type="file" id="image-input" accept="image/*"> | |
<input type="range" id="hue-range" min="0" max="360" value="0"> | |
<input type="color" id="bg-color" value="#ffffff"> | |
<canvas id="image-canvas"></canvas> | |
<script src="main.js"></script> | |
</body> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const imageInput = document.getElementById('image-input'); | |
const hueRange = document.getElementById('hue-range'); | |
const bgColor = document.getElementById('bg-color'); | |
const canvas = document.getElementById('image-canvas'); | |
const ctx = canvas.getContext('2d'); | |
let img = new Image(); | |
imageInput.addEventListener('change', (e) => { | |
const reader = new FileReader(); | |
reader.onload = (event) => { | |
img.src = event.target.result; | |
img.onload = () => { | |
canvas.width = img.width; | |
canvas.height = img.height; | |
updateImage(); | |
}; | |
}; | |
reader.readAsDataURL(e.target.files[0]); | |
}); | |
hueRange.addEventListener('input', updateImage); | |
bgColor.addEventListener('input', updateBackground); | |
function updateImage() { | |
ctx.clearRect(0, 0, canvas.width, canvas.height); | |
// Draw the image in grayscale | |
ctx.filter = 'grayscale(100%)'; | |
ctx.drawImage(img, 0, 0, canvas.width, canvas.height); | |
ctx.filter = 'none'; | |
// Create an offscreen canvas to manipulate the image data | |
const offscreenCanvas = document.createElement('canvas'); | |
offscreenCanvas.width = img.width; | |
offscreenCanvas.height = img.height; | |
const offscreenCtx = offscreenCanvas.getContext('2d'); | |
// Draw the grayscale image onto the offscreen canvas | |
offscreenCtx.drawImage(img, 0, 0); | |
// Get the image data from the offscreen canvas | |
const imageData = offscreenCtx.getImageData(0, 0, offscreenCanvas.width, offscreenCanvas.height); | |
const data = imageData.data; | |
// Iterate through the pixels and adjust the hue | |
for (let i = 0; i < data.length; i += 4) { | |
const r = data[i]; | |
const g = data[i + 1]; | |
const b = data[i + 2]; | |
const [h, s, l] = rgbToHsl(r, g, b); | |
const [newR, newG, newB] = hslToRgb((h + hueRange.value / 360) % 1, s, l); | |
data[i] = newR; | |
data[i + 1] = newG; | |
data[i + 2] = newB; | |
} | |
// Put the modified image data back onto the offscreen canvas | |
offscreenCtx.putImageData(imageData, 0, 0); | |
// Draw the colorized image onto the main canvas | |
ctx.drawImage(offscreenCanvas, 0, 0, canvas.width, canvas.height); | |
} | |
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)]; | |
} | |
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]; | |
} | |
function updateBackground() { | |
canvas.style.backgroundColor = bgColor.value; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment