Skip to content
85 changes: 85 additions & 0 deletions Conversions/RgbHslConversion.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/**
* Given a color in RGB format, convert it to HSL format.
*
* For more info: https://www.niwa.nu/2013/05/math-behind-colorspace-conversions-rgb-hsl/
*
* @param {number[]} colorRgb - One dimensional array of integers (RGB color format).
* @returns {number[]} - One dimensional array of integers (HSL color format).
*
* @example
* const colorRgb = [24, 98, 118]
*
* const result = rgbToHsl(colorRgb)
*
* // The function returns the corresponding color in HSL format:
* // result = [193, 66, 28]
*/

const checkRgbFormat = (colorRgb) => colorRgb.every(c => c >= 0 && c <= 255);

const rgbToHsl = (colorRgb) => {
if (!checkRgbFormat(colorRgb)) {
throw new Error('Input is not a valid RGB color.');
}

let colorHsl = colorRgb

let red = Math.round(colorRgb[0])
let green = Math.round(colorRgb[1])
let blue = Math.round(colorRgb[2])

const limit = 255

colorHsl[0] = red / limit
colorHsl[1] = green / limit
colorHsl[2] = blue / limit

let minValue = Math.min(...colorHsl)
let maxValue = Math.max(...colorHsl)

let channel = 0

if (maxValue === colorHsl[1]) {
channel = 1
} else if (maxValue === colorHsl[2]) {
channel = 2
}

let luminance = (minValue + maxValue) / 2

let saturation = 0

if (minValue !== maxValue) {
if (luminance <= 0.5) {
saturation = (maxValue - minValue) / (maxValue + minValue)
} else {
saturation = (maxValue - minValue) / (2 - maxValue - minValue)
}
}

let hue = 0

if (saturation !== 0) {
if (channel === 0) {
hue = (colorHsl[1] - colorHsl[2]) / (maxValue - minValue)
} else if (channel === 1) {
hue = 2 + (colorHsl[2] - colorHsl[0]) / (maxValue - minValue)
} else {
hue = 4 + (colorHsl[0] - colorHsl[1]) / (maxValue - minValue)
}
}

hue *= 60

if (hue < 0) {
hue += 360
}

colorHsl[0] = Math.round(hue)
colorHsl[1] = Math.round(saturation * 100)
colorHsl[2] = Math.round(luminance * 100)

return colorHsl
}

export { rgbToHsl }
54 changes: 54 additions & 0 deletions Conversions/test/RgbHslConversion.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { rgbToHsl } from '../RgbHslConversion'
describe('RgbHslConversion', () => {
const validTestCases = [
[
[215, 19, 180],
[311, 84, 46]
],
[
[21, 190, 18],
[119, 83, 41]
],
[
[80, 100, 160],
[225, 33, 47]
],
[
[80, 1, 16],
[349, 98, 16]
],
[
[8, 20, 0],
[96, 100, 4]
],
[
[0, 0, 0],
[0, 0, 0]
],
[
[255, 255, 255],
[0, 0, 100]
]
]

const errorTestCases = [
[[256, 180, 9], 'Input is not a valid RGB color.'],
[[-90, 46, 8], 'Input is not a valid RGB color.'],
[[1, 39, 900], 'Input is not a valid RGB color.']
]


test.each(validTestCases)(
'Should return the color in HSL format.',
(colorRgb, expected) => {
expect(rgbToHsl(colorRgb)).toEqual(expected)
}
)

test.each(errorTestCases)(
'Should return the error message.',
(colorRgb, expected) => {
expect(() => rgbToHsl(colorRgb)).toThrowError(expected)
}
)
})