Support for RGB <-> HSL
authorAlexander Ebert <ebert@woltlab.com>
Mon, 30 May 2022 14:39:11 +0000 (16:39 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Mon, 30 May 2022 14:39:11 +0000 (16:39 +0200)
ts/WoltLabSuite/Core/ColorUtil.ts
wcfsetup/install/files/js/WoltLabSuite/Core/ColorUtil.js

index afaa0d968afcbd793e2189ae9fc186f4f510be41..cd3335a2e23ff761cdec7b725fdea28a658931cf 100644 (file)
@@ -8,6 +8,44 @@
  * @module      WoltLabSuite/Core/ColorUtil
  */
 
+type HSVL = {
+  h: number;
+  s: number;
+  v: number;
+  l: number;
+};
+
+/**
+ * Converts a HSL color into RGB.
+ *
+ * @see https://www.rapidtables.com/convert/color/hsl-to-rgb.html
+ */
+export function hslToRgb(hue: number, saturation: number, lightness: number): RGB {
+  if (hue > 359) {
+    throw new TypeError("Hue cannot be larger than 359°");
+  }
+
+  saturation /= 100;
+  lightness /= 100;
+
+  const C = (1 - Math.abs(2 * lightness - 1)) * saturation;
+  const X = C * (1 - Math.abs(((hue / 60) % 2) - 1));
+  const m = lightness - C / 2;
+
+  const [R, G, B] = ((0 <= hue && hue < 60 && [C, X, 0]) ||
+    (60 <= hue && hue < 120 && [X, C, 0]) ||
+    (120 <= hue && hue < 180 && [0, C, X]) ||
+    (180 <= hue && hue < 240 && [0, X, C]) ||
+    (240 <= hue && hue < 300 && [X, 0, C]) ||
+    (300 <= hue && hue < 360 && [C, 0, X])) as number[];
+
+  return {
+    r: Math.round((R + m) * 255),
+    g: Math.round((G + m) * 255),
+    b: Math.round((B + m) * 255),
+  };
+}
+
 /**
  * Converts a HSV color into RGB.
  *
@@ -77,11 +115,11 @@ export function hsvToRgb(h: number, s: number, v: number): RGB {
 }
 
 /**
- * Converts a RGB color into HSV.
+ * Converts a RGB color into HSVL.
  *
  * @see  https://secure.wikimedia.org/wikipedia/de/wiki/HSV-Farbraum#Transformation_von_RGB_und_HSV
  */
-export function rgbToHsv(r: number, g: number, b: number): HSV {
+function rgbToHsvl(r: number, g: number, b: number): HSVL {
   let h: number, s: number;
 
   r /= 255;
@@ -119,13 +157,34 @@ export function rgbToHsv(r: number, g: number, b: number): HSV {
     s = diff / max;
   }
 
+  const l = (max + min) / 2;
+
   return {
     h: Math.round(h),
     s: Math.round(s * 100),
     v: Math.round(max * 100),
+    l: Math.round(l * 100),
   };
 }
 
+/**
+ * Converts a RGB color into HSL.
+ */
+export function rgbToHsl(r: number, g: number, b: number): HSL {
+  const { h, s, l } = rgbToHsvl(r, g, b);
+
+  return { h, s, l };
+}
+
+/**
+ * Converts a RGB color into HSV.
+ */
+export function rgbToHsv(r: number, g: number, b: number): HSV {
+  const { h, s, v } = rgbToHsvl(r, g, b);
+
+  return { h, s, v };
+}
+
 /**
  * Converts HEX into RGB.
  */
@@ -300,33 +359,41 @@ export function stringToRgba(color: string): RGBA {
   throw new Error(`Cannot process color '${color}'.`);
 }
 
-export interface RGB {
+export type RGB = {
   r: number;
   g: number;
   b: number;
-}
+};
 
-export interface RGBA {
+export type RGBA = {
   r: number;
   g: number;
   b: number;
   a: number;
-}
+};
 
-export interface HSV {
+export type HSV = {
   h: number;
   s: number;
   v: number;
-}
+};
+
+export type HSL = {
+  h: number;
+  s: number;
+  l: number;
+};
 
 // WCF.ColorPicker compatibility (color format conversion)
 window.__wcf_bc_colorUtil = {
   hexToRgb,
+  hslToRgb,
   hsvToRgb,
   isValidColor,
   rgbaToHex,
   rgbaToString,
   rgbToHex,
   rgbToHsv,
+  rgbToHsl,
   stringToRgba,
 };
index 53b4575b6bb62a90b4a0c1b204a2ccaa2160094d..9f70e448c19309f19f3dd30dadac35ed045041a6 100644 (file)
 define(["require", "exports"], function (require, exports) {
     "use strict";
     Object.defineProperty(exports, "__esModule", { value: true });
-    exports.stringToRgba = exports.isValidColor = exports.rgbaToString = exports.rgbaToHex = exports.rgbToHex = exports.hexToRgb = exports.rgbToHsv = exports.hsvToRgb = void 0;
+    exports.stringToRgba = exports.isValidColor = exports.rgbaToString = exports.rgbaToHex = exports.rgbToHex = exports.hexToRgb = exports.rgbToHsv = exports.rgbToHsl = exports.hsvToRgb = exports.hslToRgb = void 0;
+    /**
+     * Converts a HSL color into RGB.
+     *
+     * @see https://www.rapidtables.com/convert/color/hsl-to-rgb.html
+     */
+    function hslToRgb(hue, saturation, lightness) {
+        if (hue > 359) {
+            throw new TypeError("Hue cannot be larger than 359°");
+        }
+        saturation /= 100;
+        lightness /= 100;
+        const C = (1 - Math.abs(2 * lightness - 1)) * saturation;
+        const X = C * (1 - Math.abs(((hue / 60) % 2) - 1));
+        const m = lightness - C / 2;
+        const [R, G, B] = ((0 <= hue && hue < 60 && [C, X, 0]) ||
+            (60 <= hue && hue < 120 && [X, C, 0]) ||
+            (120 <= hue && hue < 180 && [0, C, X]) ||
+            (180 <= hue && hue < 240 && [0, X, C]) ||
+            (240 <= hue && hue < 300 && [X, 0, C]) ||
+            (300 <= hue && hue < 360 && [C, 0, X]));
+        return {
+            r: Math.round((R + m) * 255),
+            g: Math.round((G + m) * 255),
+            b: Math.round((B + m) * 255),
+        };
+    }
+    exports.hslToRgb = hslToRgb;
     /**
      * Converts a HSV color into RGB.
      *
@@ -71,11 +98,11 @@ define(["require", "exports"], function (require, exports) {
     }
     exports.hsvToRgb = hsvToRgb;
     /**
-     * Converts a RGB color into HSV.
+     * Converts a RGB color into HSVL.
      *
      * @see  https://secure.wikimedia.org/wikipedia/de/wiki/HSV-Farbraum#Transformation_von_RGB_und_HSV
      */
-    function rgbToHsv(r, g, b) {
+    function rgbToHsvl(r, g, b) {
         let h, s;
         r /= 255;
         g /= 255;
@@ -106,12 +133,29 @@ define(["require", "exports"], function (require, exports) {
         else {
             s = diff / max;
         }
+        const l = (max + min) / 2;
         return {
             h: Math.round(h),
             s: Math.round(s * 100),
             v: Math.round(max * 100),
+            l: Math.round(l * 100),
         };
     }
+    /**
+     * Converts a RGB color into HSL.
+     */
+    function rgbToHsl(r, g, b) {
+        const { h, s, l } = rgbToHsvl(r, g, b);
+        return { h, s, l };
+    }
+    exports.rgbToHsl = rgbToHsl;
+    /**
+     * Converts a RGB color into HSV.
+     */
+    function rgbToHsv(r, g, b) {
+        const { h, s, v } = rgbToHsvl(r, g, b);
+        return { h, s, v };
+    }
     exports.rgbToHsv = rgbToHsv;
     /**
      * Converts HEX into RGB.
@@ -264,12 +308,14 @@ define(["require", "exports"], function (require, exports) {
     // WCF.ColorPicker compatibility (color format conversion)
     window.__wcf_bc_colorUtil = {
         hexToRgb,
+        hslToRgb,
         hsvToRgb,
         isValidColor,
         rgbaToHex,
         rgbaToString,
         rgbToHex,
         rgbToHsv,
+        rgbToHsl,
         stringToRgba,
     };
 });