A Pen by Jake Brown on CodePen.
Created
April 15, 2023 01:32
-
-
Save jake-sl/06c955be1a1508d67bc713651cc5074f 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] = rgbToHsl((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 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