作 ▸
JavaScriptでRGB⇔HSL変換
ゲーム作ってたときに使ってたものです。計算方法は、全面的に次のサイト様を参考にさせていただきました。
- 小数の精度の都合上、完全な双方向の変換はできない場合があります。
- RGBは 0 ~ 255, 色相は 0 ~ 360, 彩度と明度は 0 ~ 100 の範囲を想定してます。
- 結果は小数にもなります。スタイルに使う場合は丸めてください。
/**
* RGBからHSLを算出して返却
* @param {Number} r - 赤 (0~255)
* @param {Number} g - 緑 (0~255)
* @param {Number} b - 青 (0~255)
* @return {Object} h: 色相 (0~360), s: 彩度 (0~100), l: 明度 (0~100)
*/
const rgb2hsl = function(r, g, b) {
const RGB_MAX = 255;
const HUE_MAX = 360;
const SATURATION_MAX = 100;
const LIGHTNESS_MAX = 100;
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
let h, s, l;
// Hue
const hp = HUE_MAX / 6;
if (max == min) {
h = 0;
} else if (r == max) {
h = hp * ((g - b) / (max - min));
} else if (g == max) {
h = hp * ((b - r) / (max - min)) + HUE_MAX / 3;
} else {
h = hp * ((r - g) / (max - min)) + HUE_MAX * 2 / 3;
}
if (h < 0) {
h += HUE_MAX;
}
// Saturation
const cnt = (max + min) / 2;
if (cnt < RGB_MAX / 2) {
if (max + min <= 0) {
s = 0;
} else {
s = (max - min) / (max + min) * SATURATION_MAX;
}
} else {
s = (max - min) / (RGB_MAX * 2 - max - min) * SATURATION_MAX;
}
// Lightness
l = (max + min) / RGB_MAX / 2 * LIGHTNESS_MAX;
return {
h: h,
s: s,
l: l
};
};
/**
* HSLからRGBを算出して返却
* @param {Number} h - 色相 (0~360)
* @param {Number} s - 彩度 (0~100)
* @param {Number} l - 明度 (0~100)
* @return {Object} r: 赤 (0~255), g: 緑 (0~255), b: 青 (0~255)
*/
const hsl2rgb = function(h, s, l) {
const RGB_MAX = 255;
const HUE_MAX = 360;
const SATURATION_MAX = 100;
const LIGHTNESS_MAX = 100;
let r, g, b, max, min;
h = h % HUE_MAX;
s = s / SATURATION_MAX;
l = l / LIGHTNESS_MAX;
if (l < 0.5) {
max = l + l * s;
min = l - l * s;
} else {
max = l + (1 - l) * s;
min = l - (1 - l) * s;
}
const hp = HUE_MAX / 6;
const q = h / hp;
if (q <= 1) {
r = max;
g = (h / hp) * (max - min) + min;
b = min;
} else if (q <= 2) {
r = ((hp * 2 - h) / hp) * (max - min) + min;
g = max;
b = min;
} else if (q <= 3) {
r = min;
g = max;
b = ((h - hp * 2) / hp) * (max - min) + min;
} else if (q <= 4) {
r = min;
g = ((hp * 4 - h) / hp) * (max - min) + min;
b = max;
} else if (q <= 5) {
r = ((h - hp * 4) / hp) * (max - min) + min;
g = min;
b = max;
} else {
r = max;
g = min;
b = ((HUE_MAX - h) / hp) * (max - min) + min;
}
return {
r: r * RGB_MAX,
g: g * RGB_MAX,
b: b * RGB_MAX
};
};
テストケース
console.log(rgb2hsl( 255, 0, 0)); // -> h: 0, s: 100, l: 50
console.log(rgb2hsl( 255, 127.5, 0)); // -> h: 30, s: 100, l: 50
console.log(rgb2hsl( 255, 255, 0)); // -> h: 60, s: 100, l: 50
console.log(rgb2hsl(127.5, 255, 0)); // -> h: 90, s: 100, l: 50
console.log(rgb2hsl( 0, 255, 0)); // -> h: 120, s: 100, l: 50
console.log(rgb2hsl( 0, 255, 127.5)); // -> h: 150, s: 100, l: 50
console.log(rgb2hsl( 0, 255, 255)); // -> h: 180, s: 100, l: 50
console.log(rgb2hsl( 0, 127.5, 255)); // -> h: 210, s: 100, l: 50
console.log(rgb2hsl( 0, 0, 255)); // -> h: 240, s: 100, l: 50
console.log(rgb2hsl(127.5, 0, 255)); // -> h: 270, s: 100, l: 50
console.log(rgb2hsl( 255, 0, 255)); // -> h: 300, s: 100, l: 50
console.log(rgb2hsl( 255, 0, 127.5)); // -> h: 330, s: 100, l: 50
console.log(rgb2hsl( 0, 0, 0)); // -> h: 0, s: 0, l: 0
console.log(rgb2hsl( 51, 51, 51)); // -> h: 0, s: 0, l: 20
console.log(rgb2hsl(127.5, 127.5, 127.5)); // -> h: 0, s: 0, l: 50
console.log(rgb2hsl( 255, 255, 255)); // -> h: 0, s: 0, l: 100
console.log(rgb2hsl( 51, 0, 0)); // -> h: 0, s: 100, l: 10
console.log(rgb2hsl( 102, 0, 0)); // -> h: 0, s: 100, l: 20
console.log(rgb2hsl( 153, 0, 0)); // -> h: 0, s: 100, l: 30
console.log(rgb2hsl( 204, 0, 0)); // -> h: 0, s: 100, l: 40
console.log(rgb2hsl( 153, 102, 102)); // -> h: 0, s: 20, l: 50
console.log(rgb2hsl(178.5, 76.5, 76.5)); // -> h: 0, s: 40, l: 50
console.log(rgb2hsl( 204, 51, 51)); // -> h: 0, s: 60, l: 50
console.log(rgb2hsl(229.5, 25.5, 25.5)); // -> h: 0, s: 80, l: 50
console.log(hsl2rgb( 0, 100, 50 )); // -> r: 255, g: 0, b: 0
console.log(hsl2rgb( 30, 100, 50 )); // -> r: 255, g: 127.5, b: 0
console.log(hsl2rgb( 60, 100, 50 )); // -> r: 255, g: 255, b: 0
console.log(hsl2rgb( 90, 100, 50 )); // -> r: 127.5, g: 255, b: 0
console.log(hsl2rgb( 120, 100, 50 )); // -> r: 0, g: 255, b: 0
console.log(hsl2rgb( 150, 100, 50 )); // -> r: 0, g: 255, b: 127.5
console.log(hsl2rgb( 180, 100, 50 )); // -> r: 0, g: 255, b: 255
console.log(hsl2rgb( 210, 100, 50 )); // -> r: 0, g: 127.5, b: 255
console.log(hsl2rgb( 240, 100, 50 )); // -> r: 0, g: 0, b: 255
console.log(hsl2rgb( 270, 100, 50 )); // -> r: 127.5, g: 0, b: 255
console.log(hsl2rgb( 300, 100, 50 )); // -> r: 255, g: 0, b: 255
console.log(hsl2rgb( 330, 100, 50 )); // -> r: 255, g: 0, b: 127.5
console.log(hsl2rgb( 360, 100, 50 )); // -> r: 255, g: 0, b: 0
console.log(hsl2rgb( 390, 100, 50 )); // -> r: 255, g: 127.5, b: 0
console.log(hsl2rgb( 99, 0, 0 )); // -> r: 0, g: 0, b: 0
console.log(hsl2rgb( 99, 0, 20 )); // -> r: 51, g: 51, b: 51
console.log(hsl2rgb( 99, 0, 50 )); // -> r: 127.5, g: 127.5, b: 127.5
console.log(hsl2rgb( 99, 0, 100 )); // -> r: 255, g: 255, b: 255
console.log(hsl2rgb( 0, 100, 10 )); // -> r: 51, g: 0, b: 0
console.log(hsl2rgb( 0, 100, 20 )); // -> r: 102, g: 0, b: 0
console.log(hsl2rgb( 0, 100, 30 )); // -> r: 153, g: 0, b: 0
console.log(hsl2rgb( 0, 100, 40 )); // -> r: 204, g: 0, b: 0
console.log(hsl2rgb( 0, 20, 50 )); // -> r: 153, g: 102, b: 102
console.log(hsl2rgb( 0, 40, 50 )); // -> r: 178.5, g: 76.5, b: 76.5
console.log(hsl2rgb( 0, 60, 50 )); // -> r: 204, g: 51, b: 51
console.log(hsl2rgb( 0, 80, 50 )); // -> r: 229.5, g: 25.499999999999993, b: 25.499999999999993
console.log(hsl2rgb( 60, 100, 10 )); // -> r: 51, g: 51, b: 0
console.log(hsl2rgb( 60, 100, 20 )); // -> r: 102, g: 102, b: 0
console.log(hsl2rgb( 60, 100, 30 )); // -> r: 153, g: 153, b: 0
console.log(hsl2rgb( 60, 100, 40 )); // -> r: 204, g: 204, b: 0
console.log(hsl2rgb( 120, 100, 10 )); // -> r: 0, g: 51, b: 0
console.log(hsl2rgb( 120, 100, 20 )); // -> r: 0, g: 102, b: 0
console.log(hsl2rgb( 120, 100, 30 )); // -> r: 0, g: 153, b: 0
console.log(hsl2rgb( 120, 100, 40 )); // -> r: 0, g: 204, b: 0
console.log(hsl2rgb( 180, 100, 10 )); // -> r: 0, g: 51, b: 51
console.log(hsl2rgb( 180, 100, 20 )); // -> r: 0, g: 102, b: 102
console.log(hsl2rgb( 180, 100, 30 )); // -> r: 0, g: 153, b: 153
console.log(hsl2rgb( 180, 100, 40 )); // -> r: 0, g: 204, b: 204
console.log(hsl2rgb( 240, 100, 10 )); // -> r: 0, g: 0, b: 51
console.log(hsl2rgb( 240, 100, 20 )); // -> r: 0, g: 0, b: 102
console.log(hsl2rgb( 240, 100, 30 )); // -> r: 0, g: 0, b: 153
console.log(hsl2rgb( 240, 100, 40 )); // -> r: 0, g: 0, b: 204
console.log(hsl2rgb( 300, 100, 10 )); // -> r: 51, g: 0, b: 51
console.log(hsl2rgb( 300, 100, 20 )); // -> r: 102, g: 0, b: 102
console.log(hsl2rgb( 300, 100, 30 )); // -> r: 153, g: 0, b: 153
console.log(hsl2rgb( 300, 100, 40 )); // -> r: 204, g: 0, b: 204