ct.el icon indicating copy to clipboard operation
ct.el copied to clipboard

color tools for emacs

🔵 🟣 🟢 🟤 🟡 🔴 🟠

ct.el (color tools) is a color library for Emacs meant for making changes to individual colors in various color spaces. Builds on top of [[https://github.com/emacs-mirror/emacs/blob/master/lisp/color.el][color.el]] and [[https://github.com/hsluv/hsluv-emacs][hsluv-emacs]], providing a consistent interface to many color spaces, in addition to some utility functions. Visualized in [[https://notes.neeasade.net/color-spaces.html][this blog post]], used to create [[https://github.com/neeasade/tarps][tarps]]. Shouted out by [[https://protesilaos.com/codelog/2021-01-11-modus-themes-review-select-faint-colours/][prot]] (of modus themes fame).

Supported color spaces: [[#rgb][rgb]] • [[#hsl][hsl]] • [[#hsv][hsv]] • [[#hsluv][hsluv]] • [[#hpluv][hpluv]] • [[#lab][lab]] • [[#lch][lch]]

** Installation

ct.el is on [[https://melpa.org/#/ct][melpa]]. You may also install with [[https://github.com/raxod502/straight.el][straight.el]]:

#+begin_src emacs-lisp (straight-use-package '(ct :host github :repo "neeasade/ct.el" :branch "master")) #+end_src

** Conventions

  • Colorspace number range values are 0-100
    • Exception: Hue (0-360 degrees)
    • Exception: LAB (-100-100)
  • Values are clamped to valid ranges coming out of the ~ct-edit~ functions
    • Hue is clamped via modulo 360

** Functions *** Color Properties

  • [[#ct-contrast-ratio-c1-c2][ct-contrast-ratio]] ~(C1 C2)~
  • [[#ct-distance-c1-c2][ct-distance]] ~(C1 C2)~
  • [[#ct-format-argb-c-optional-opacity-end][ct-format-argb]] ~(C &optional OPACITY END)~
  • [[#ct-format-rbga-c-optional-opacity][ct-format-rbga]] ~(C &optional OPACITY)~
  • [[#ct-light-p-c-optional-scale][ct-light-p]] ~(C &optional SCALE)~ *** Color Modification
  • [[#ct-complement-c][ct-complement]] ~(C)~
  • [[#ct-gradient-step-start-end-optional-with-ends-space][ct-gradient]] ~(STEP START END &optional WITH-ENDS SPACE)~
  • [[#ct-greaten-c-optional-percent][ct-greaten]] ~(C &optional PERCENT)~
  • [[#ct-lessen-c-optional-percent][ct-lessen]] ~(C &optional PERCENT)~
  • [[#ct-iterate-start-op-condition][ct-iterate]] ~(START OP CONDITION)~
  • [[#ct-iterations-start-op-condition][ct-iterations]] ~(START OP CONDITION)~
  • [[#ct-lab-change-whitepoint-c-w1-w2][ct-lab-change-whitepoint]] ~(C W1 W2)~
  • [[#ct-mix-colors-optional-space][ct-mix]] ~(COLORS &optional SPACE)~
  • [[#ct-mix-opacity-top-bottom-opacity][ct-mix-opacity]] ~(TOP BOTTOM OPACITY)~
  • [[#ct-pastel-c-optional-smod-vmod][ct-pastel]] ~(C &optional SMOD VMOD)~
  • [[#ct-tint-ratio-foreground-background-ratio][ct-tint-ratio]] ~(FOREGROUND BACKGROUND RATIO)~
  • [[#ct-rotation-hpluv-c-interval][ct-rotation-hpluv]] ~(C INTERVAL)~
  • [[#ct-rotation-hsl-c-interval][ct-rotation-hsl]] ~(C INTERVAL)~
  • [[#ct-rotation-hsluv-c-interval][ct-rotation-hsluv]] ~(C INTERVAL)~
  • [[#ct-rotation-hsv-c-interval][ct-rotation-hsv]] ~(C INTERVAL)~
  • [[#ct-rotation-lch-c-interval][ct-rotation-lch]] ~(C INTERVAL)~ *** RGB
  • [[#ct-make-rgb-r-g-b][ct-make-rgb]] ~(R G B)~
  • [[#ct-get-rgb-c][ct-get-rgb]] ~(C)~
  • [[#ct-get-rgb-r-c][ct-get-rgb-r]] ~(C)~
  • [[#ct-get-rgb-g-c][ct-get-rgb-g]] ~(C)~
  • [[#ct-get-rgb-b-c][ct-get-rgb-b]] ~(C)~
  • [[#ct-edit-rgb-c-transform][ct-edit-rgb]] ~(C TRANSFORM)~
  • [[#ct-edit-rgb-b-c-func-or-val][ct-edit-rgb-b]] ~(C FUNC-OR-VAL)~
  • [[#ct-edit-rgb-b-dec-c-optional-v][ct-edit-rgb-b-dec]] ~(C &optional V)~
  • [[#ct-edit-rgb-b-inc-c-optional-v][ct-edit-rgb-b-inc]] ~(C &optional V)~
  • [[#ct-edit-rgb-g-c-func-or-val][ct-edit-rgb-g]] ~(C FUNC-OR-VAL)~
  • [[#ct-edit-rgb-g-dec-c-optional-v][ct-edit-rgb-g-dec]] ~(C &optional V)~
  • [[#ct-edit-rgb-g-inc-c-optional-v][ct-edit-rgb-g-inc]] ~(C &optional V)~
  • [[#ct-edit-rgb-r-c-func-or-val][ct-edit-rgb-r]] ~(C FUNC-OR-VAL)~
  • [[#ct-edit-rgb-r-dec-c-optional-v][ct-edit-rgb-r-dec]] ~(C &optional V)~
  • [[#ct-edit-rgb-r-inc-c-optional-v][ct-edit-rgb-r-inc]] ~(C &optional V)~ *** LAB
  • [[#ct-make-lab-l-a-b][ct-make-lab]] ~(L A B)~
  • [[#ct-get-lab-c][ct-get-lab]] ~(C)~
  • [[#ct-get-lab-l-c][ct-get-lab-l]] ~(C)~
  • [[#ct-get-lab-b-c][ct-get-lab-b]] ~(C)~
  • [[#ct-get-lab-a-c][ct-get-lab-a]] ~(C)~
  • [[#ct-edit-lab-c-transform][ct-edit-lab]] ~(C TRANSFORM)~
  • [[#ct-edit-lab-a-c-func-or-val][ct-edit-lab-a]] ~(C FUNC-OR-VAL)~
  • [[#ct-edit-lab-a-dec-c-optional-v][ct-edit-lab-a-dec]] ~(C &optional V)~
  • [[#ct-edit-lab-a-inc-c-optional-v][ct-edit-lab-a-inc]] ~(C &optional V)~
  • [[#ct-edit-lab-b-c-func-or-val][ct-edit-lab-b]] ~(C FUNC-OR-VAL)~
  • [[#ct-edit-lab-b-dec-c-optional-v][ct-edit-lab-b-dec]] ~(C &optional V)~
  • [[#ct-edit-lab-b-inc-c-optional-v][ct-edit-lab-b-inc]] ~(C &optional V)~
  • [[#ct-edit-lab-l-c-func-or-val][ct-edit-lab-l]] ~(C FUNC-OR-VAL)~
  • [[#ct-edit-lab-l-dec-c-optional-v][ct-edit-lab-l-dec]] ~(C &optional V)~
  • [[#ct-edit-lab-l-inc-c-optional-v][ct-edit-lab-l-inc]] ~(C &optional V)~ *** HSL
  • [[#ct-make-hsl-h-s-l][ct-make-hsl]] ~(H S L)~
  • [[#ct-get-hsl-c][ct-get-hsl]] ~(C)~
  • [[#ct-get-hsl-s-c][ct-get-hsl-s]] ~(C)~
  • [[#ct-get-hsl-l-c][ct-get-hsl-l]] ~(C)~
  • [[#ct-get-hsl-h-c][ct-get-hsl-h]] ~(C)~
  • [[#ct-edit-hsl-c-transform][ct-edit-hsl]] ~(C TRANSFORM)~
  • [[#ct-edit-hsl-h-c-func-or-val][ct-edit-hsl-h]] ~(C FUNC-OR-VAL)~
  • [[#ct-edit-hsl-h-dec-c-optional-v][ct-edit-hsl-h-dec]] ~(C &optional V)~
  • [[#ct-edit-hsl-h-inc-c-optional-v][ct-edit-hsl-h-inc]] ~(C &optional V)~
  • [[#ct-edit-hsl-l-c-func-or-val][ct-edit-hsl-l]] ~(C FUNC-OR-VAL)~
  • [[#ct-edit-hsl-l-dec-c-optional-v][ct-edit-hsl-l-dec]] ~(C &optional V)~
  • [[#ct-edit-hsl-l-inc-c-optional-v][ct-edit-hsl-l-inc]] ~(C &optional V)~
  • [[#ct-edit-hsl-s-c-func-or-val][ct-edit-hsl-s]] ~(C FUNC-OR-VAL)~
  • [[#ct-edit-hsl-s-dec-c-optional-v][ct-edit-hsl-s-dec]] ~(C &optional V)~
  • [[#ct-edit-hsl-s-inc-c-optional-v][ct-edit-hsl-s-inc]] ~(C &optional V)~ *** HSLuv
  • [[#ct-make-hsluv-h-s-l][ct-make-hsluv]] ~(H S L)~
  • [[#ct-get-hsluv-c][ct-get-hsluv]] ~(C)~
  • [[#ct-get-hsluv-s-c][ct-get-hsluv-s]] ~(C)~
  • [[#ct-get-hsluv-l-c][ct-get-hsluv-l]] ~(C)~
  • [[#ct-get-hsluv-h-c][ct-get-hsluv-h]] ~(C)~
  • [[#ct-edit-hsluv-c-transform][ct-edit-hsluv]] ~(C TRANSFORM)~
  • [[#ct-edit-hsluv-h-c-func-or-val][ct-edit-hsluv-h]] ~(C FUNC-OR-VAL)~
  • [[#ct-edit-hsluv-h-dec-c-optional-v][ct-edit-hsluv-h-dec]] ~(C &optional V)~
  • [[#ct-edit-hsluv-h-inc-c-optional-v][ct-edit-hsluv-h-inc]] ~(C &optional V)~
  • [[#ct-edit-hsluv-l-c-func-or-val][ct-edit-hsluv-l]] ~(C FUNC-OR-VAL)~
  • [[#ct-edit-hsluv-l-dec-c-optional-v][ct-edit-hsluv-l-dec]] ~(C &optional V)~
  • [[#ct-edit-hsluv-l-inc-c-optional-v][ct-edit-hsluv-l-inc]] ~(C &optional V)~
  • [[#ct-edit-hsluv-s-c-func-or-val][ct-edit-hsluv-s]] ~(C FUNC-OR-VAL)~
  • [[#ct-edit-hsluv-s-dec-c-optional-v][ct-edit-hsluv-s-dec]] ~(C &optional V)~
  • [[#ct-edit-hsluv-s-inc-c-optional-v][ct-edit-hsluv-s-inc]] ~(C &optional V)~ *** LCH
  • [[#ct-make-lch-l-c-h][ct-make-lch]] ~(L C H)~
  • [[#ct-get-lch-c][ct-get-lch]] ~(C)~
  • [[#ct-get-lch-l-c][ct-get-lch-l]] ~(C)~
  • [[#ct-get-lch-h-c][ct-get-lch-h]] ~(C)~
  • [[#ct-get-lch-c-c][ct-get-lch-c]] ~(C)~
  • [[#ct-edit-lch-c-transform][ct-edit-lch]] ~(C TRANSFORM)~
  • [[#ct-edit-lch-c-c-func-or-val][ct-edit-lch-c]] ~(C FUNC-OR-VAL)~
  • [[#ct-edit-lch-c-dec-c-optional-v][ct-edit-lch-c-dec]] ~(C &optional V)~
  • [[#ct-edit-lch-c-inc-c-optional-v][ct-edit-lch-c-inc]] ~(C &optional V)~
  • [[#ct-edit-lch-h-c-func-or-val][ct-edit-lch-h]] ~(C FUNC-OR-VAL)~
  • [[#ct-edit-lch-h-dec-c-optional-v][ct-edit-lch-h-dec]] ~(C &optional V)~
  • [[#ct-edit-lch-h-inc-c-optional-v][ct-edit-lch-h-inc]] ~(C &optional V)~
  • [[#ct-edit-lch-l-c-func-or-val][ct-edit-lch-l]] ~(C FUNC-OR-VAL)~
  • [[#ct-edit-lch-l-dec-c-optional-v][ct-edit-lch-l-dec]] ~(C &optional V)~
  • [[#ct-edit-lch-l-inc-c-optional-v][ct-edit-lch-l-inc]] ~(C &optional V)~ *** HSV
  • [[#ct-make-hsv-h-s-v][ct-make-hsv]] ~(H S V)~
  • [[#ct-get-hsv-c][ct-get-hsv]] ~(C)~
  • [[#ct-get-hsv-v-c][ct-get-hsv-v]] ~(C)~
  • [[#ct-get-hsv-s-c][ct-get-hsv-s]] ~(C)~
  • [[#ct-get-hsv-h-c][ct-get-hsv-h]] ~(C)~
  • [[#ct-edit-hsv-c-transform][ct-edit-hsv]] ~(C TRANSFORM)~
  • [[#ct-edit-hsv-h-c-func-or-val][ct-edit-hsv-h]] ~(C FUNC-OR-VAL)~
  • [[#ct-edit-hsv-h-dec-c-optional-v][ct-edit-hsv-h-dec]] ~(C &optional V)~
  • [[#ct-edit-hsv-h-inc-c-optional-v][ct-edit-hsv-h-inc]] ~(C &optional V)~
  • [[#ct-edit-hsv-s-c-func-or-val][ct-edit-hsv-s]] ~(C FUNC-OR-VAL)~
  • [[#ct-edit-hsv-s-dec-c-optional-v][ct-edit-hsv-s-dec]] ~(C &optional V)~
  • [[#ct-edit-hsv-s-inc-c-optional-v][ct-edit-hsv-s-inc]] ~(C &optional V)~
  • [[#ct-edit-hsv-v-c-func-or-val][ct-edit-hsv-v]] ~(C FUNC-OR-VAL)~
  • [[#ct-edit-hsv-v-dec-c-optional-v][ct-edit-hsv-v-dec]] ~(C &optional V)~
  • [[#ct-edit-hsv-v-inc-c-optional-v][ct-edit-hsv-v-inc]] ~(C &optional V)~ *** HPLUV
  • [[#ct-make-hpluv-h-p-l][ct-make-hpluv]] ~(H P L)~
  • [[#ct-get-hpluv-c][ct-get-hpluv]] ~(C)~
  • [[#ct-get-hpluv-p-c][ct-get-hpluv-p]] ~(C)~
  • [[#ct-get-hpluv-l-c][ct-get-hpluv-l]] ~(C)~
  • [[#ct-get-hpluv-h-c][ct-get-hpluv-h]] ~(C)~
  • [[#ct-edit-hpluv-c-transform][ct-edit-hpluv]] ~(C TRANSFORM)~
  • [[#ct-edit-hpluv-h-c-func-or-val][ct-edit-hpluv-h]] ~(C FUNC-OR-VAL)~
  • [[#ct-edit-hpluv-h-dec-c-optional-v][ct-edit-hpluv-h-dec]] ~(C &optional V)~
  • [[#ct-edit-hpluv-h-inc-c-optional-v][ct-edit-hpluv-h-inc]] ~(C &optional V)~
  • [[#ct-edit-hpluv-l-c-func-or-val][ct-edit-hpluv-l]] ~(C FUNC-OR-VAL)~
  • [[#ct-edit-hpluv-l-dec-c-optional-v][ct-edit-hpluv-l-dec]] ~(C &optional V)~
  • [[#ct-edit-hpluv-l-inc-c-optional-v][ct-edit-hpluv-l-inc]] ~(C &optional V)~
  • [[#ct-edit-hpluv-p-c-func-or-val][ct-edit-hpluv-p]] ~(C FUNC-OR-VAL)~
  • [[#ct-edit-hpluv-p-dec-c-optional-v][ct-edit-hpluv-p-dec]] ~(C &optional V)~
  • [[#ct-edit-hpluv-p-inc-c-optional-v][ct-edit-hpluv-p-inc]] ~(C &optional V)~ ** Color Properties Functions for seeing properties of colors not necessarily related to a particular color space. **** ct-contrast-ratio ~(C1 C2)~ Get the contrast ratio between C1 and C2. #+BEGIN_src elisp (ct-contrast-ratio "#bbbbbb" "#4fa5e8") ;; => 1.3881996647056503 #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/bbbbbb/000000.png?text=+]],[[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → 1.3881996647056503 #+END_quote **** ct-distance ~(C1 C2)~ Get cie-DE2000 distance between C1 and C2 -- value is 0-100. #+BEGIN_src elisp (ct-distance "#4fa5e8" "#bc9a43") ;; => 53.05461635462344 #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]],[[https://via.placeholder.com/16/bc9a43/000000.png?text=+]] → 53.05461635462344 #+END_quote **** ct-format-argb ~(C &optional OPACITY END)~ Argb formatting: Pass in C and OPACITY 0-100, get a string representation of C as follows: '#AAFFFFFF', where AA is a hex pair for the alpha, followed by FF times 3 hex pairs for red, green, blue. If END is truthy, then format will be '#FFFFFFAA'. #+BEGIN_src elisp (ct-format-argb "#4fa5e8" 80 t) ;; => "#4fa5e8cc" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → #4fa5e8cc #+END_quote **** ct-format-rbga ~(C &optional OPACITY)~ RGBA formatting: Pass in C and OPACITY 0-100, get a string representation of C as follows: 'rgba(R, G, B, OPACITY)', where values RGB are 0-255, and OPACITY is 0-1.0 (default 1.0). #+BEGIN_src elisp (ct-format-rbga "#4fa5e8" 80) ;; => "rgba(79, 165, 232, 0.8)" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → rgba(79, 165, 232, 0.8) #+END_quote **** ct-light-p ~(C &optional SCALE)~ Determine if C is a light color with lightness in the LAB space. Optionally override SCALE comparison value. #+BEGIN_src elisp (ct-light-p "#4fa5e8") ;; => t #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → t #+END_quote ** Color Modification Functions for modifying colors in some way potentially unrelated to a specific colorspace **** ct-complement ~(C)~ Return a complement color of C in the HSLUV space. #+BEGIN_src elisp (ct-complement "#4fa5e8") ;; => "#bc9a43" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/bc9a43/000000.png?text=+]] #+END_quote **** ct-gradient ~(STEP START END &optional WITH-ENDS SPACE)~ Create a gradient from color START to color END in STEP parts. Optionally include START and END in results using WITH-ENDS. Optionally choose a colorspace with SPACE (see 'ct--colorspace-map'). Hue-inclusive colorspaces may see mixed results. #+BEGIN_src elisp (ct-gradient 5 "#4fa5e8" "#bc9a43" t) ;; => ("#4fa5e8" "#6aa2be" "#859f95" "#a09c6c" "#bc9a43") #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]],[[https://via.placeholder.com/16/bc9a43/000000.png?text=+]] → [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]],[[https://via.placeholder.com/16/6aa2be/000000.png?text=+]],[[https://via.placeholder.com/16/859f95/000000.png?text=+]],[[https://via.placeholder.com/16/a09c6c/000000.png?text=+]],[[https://via.placeholder.com/16/bc9a43/000000.png?text=+]] #+END_quote **** ct-greaten ~(C &optional PERCENT)~ Make a light color C lighter, a dark color C darker (by PERCENT). #+BEGIN_src elisp (ct-greaten "#4fa5e8" 20) ;; => "#8ddbff" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/8ddbff/000000.png?text=+]] #+END_quote **** ct-lessen ~(C &optional PERCENT)~ Make a light color C darker, a dark color C lighter (by PERCENT). #+BEGIN_src elisp (ct-lessen "#4fa5e8" 20) ;; => "#0071af" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/0071af/000000.png?text=+]] #+END_quote **** ct-iterate ~(START OP CONDITION)~ Do OP on START color until CONDITION is met or op has no effect. #+BEGIN_src elisp (ct-iterate "#4fa5e8" 'ct-edit-hsv-v-inc (lambda (c) (> (ct-distance c "#4fa5e8") 10))) ;; => "#4f98ff" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/4f98ff/000000.png?text=+]] #+END_quote **** ct-iterations ~(START OP CONDITION)~ Do OP on START color until CONDITION is met or op has no effect - return all intermediate parts. #+BEGIN_src elisp (ct-iterations "#4fa5e8" 'ct-edit-hsv-v-inc (lambda (c) (> (ct-distance c "#4fa5e8") 10))) ;; => ("#4fa5e8" "#4fa5e9" "#4fa5ea" "#4fa5eb" "#4fa5ec" "#4fa5ed" "#4fa5ee" "#4fa5ef" "#4fa5f0" "#4fa5f1" "#4fa5f2" "#4fa5f3" "#4fa5f4" "#4fa5f5" "#4fa5f6" "#4fa5f7" "#4fa5f8" "#4fa5f9" "#4fa5fa" "#4fa5fb" "#4fa5fc" "#4fa5fd" "#4fa5fe" "#4fa5ff" "#4fa4ff" "#4fa3ff" "#4fa2ff" "#4fa1ff" "#4fa0ff" "#4f9fff" "#4f9eff" "#4f9dff" "#4f9cff" "#4f9bff" "#4f9aff" "#4f99ff" "#4f98ff") #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]],[[https://via.placeholder.com/16/4fa5e9/000000.png?text=+]],[[https://via.placeholder.com/16/4fa5ea/000000.png?text=+]],[[https://via.placeholder.com/16/4fa5eb/000000.png?text=+]],[[https://via.placeholder.com/16/4fa5ec/000000.png?text=+]],[[https://via.placeholder.com/16/4fa5ed/000000.png?text=+]],[[https://via.placeholder.com/16/4fa5ee/000000.png?text=+]],[[https://via.placeholder.com/16/4fa5ef/000000.png?text=+]],[[https://via.placeholder.com/16/4fa5f0/000000.png?text=+]],[[https://via.placeholder.com/16/4fa5f1/000000.png?text=+]],[[https://via.placeholder.com/16/4fa5f2/000000.png?text=+]],[[https://via.placeholder.com/16/4fa5f3/000000.png?text=+]],[[https://via.placeholder.com/16/4fa5f4/000000.png?text=+]],[[https://via.placeholder.com/16/4fa5f5/000000.png?text=+]],[[https://via.placeholder.com/16/4fa5f6/000000.png?text=+]],[[https://via.placeholder.com/16/4fa5f7/000000.png?text=+]],[[https://via.placeholder.com/16/4fa5f8/000000.png?text=+]],[[https://via.placeholder.com/16/4fa5f9/000000.png?text=+]],[[https://via.placeholder.com/16/4fa5fa/000000.png?text=+]],[[https://via.placeholder.com/16/4fa5fb/000000.png?text=+]],[[https://via.placeholder.com/16/4fa5fc/000000.png?text=+]],[[https://via.placeholder.com/16/4fa5fd/000000.png?text=+]],[[https://via.placeholder.com/16/4fa5fe/000000.png?text=+]],[[https://via.placeholder.com/16/4fa5ff/000000.png?text=+]],[[https://via.placeholder.com/16/4fa4ff/000000.png?text=+]],[[https://via.placeholder.com/16/4fa3ff/000000.png?text=+]],[[https://via.placeholder.com/16/4fa2ff/000000.png?text=+]],[[https://via.placeholder.com/16/4fa1ff/000000.png?text=+]],[[https://via.placeholder.com/16/4fa0ff/000000.png?text=+]],[[https://via.placeholder.com/16/4f9fff/000000.png?text=+]],[[https://via.placeholder.com/16/4f9eff/000000.png?text=+]],[[https://via.placeholder.com/16/4f9dff/000000.png?text=+]],[[https://via.placeholder.com/16/4f9cff/000000.png?text=+]],[[https://via.placeholder.com/16/4f9bff/000000.png?text=+]],[[https://via.placeholder.com/16/4f9aff/000000.png?text=+]],[[https://via.placeholder.com/16/4f99ff/000000.png?text=+]],[[https://via.placeholder.com/16/4f98ff/000000.png?text=+]] #+END_quote **** ct-lab-change-whitepoint ~(C W1 W2)~ Convert a color C wrt white points W1 and W2 through the lab colorspace. #+BEGIN_src elisp (ct-lab-change-whitepoint "#4fa5e8" color-d50-xyz color-d55-xyz) ;; => "#29a6f4" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/29a6f4/000000.png?text=+]] #+END_quote **** ct-mix ~(COLORS &optional SPACE)~ Mix COLORS in space SPACE. See also: 'ct--colorspace-map'. #+BEGIN_src elisp (ct-mix (list "#4fa5e8" "#bbbbbb" "#bc9a43")) ;; => "#a0a48a" #+END_src #+BEGIN_quote → [[https://via.placeholder.com/16/a0a48a/000000.png?text=+]] #+END_quote **** ct-mix-opacity ~(TOP BOTTOM OPACITY)~ Get resulting color of TOP color with OPACITY overlayed against BOTTOM. Opacity is expected to be 0.0-1.0. #+BEGIN_src elisp (ct-mix-opacity "#4fa5e8" "#bbbbbb" 80) ;; => "#0000ff" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]],[[https://via.placeholder.com/16/bbbbbb/000000.png?text=+]] → [[https://via.placeholder.com/16/0000ff/000000.png?text=+]] #+END_quote **** ct-pastel ~(C &optional SMOD VMOD)~ Make a color C more 'pastel' in the hsluv space -- optionally change the rate of change with SMOD and VMOD. #+BEGIN_src elisp (ct-pastel "#4fa5e8") ;; => "#77a2c4" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/77a2c4/000000.png?text=+]] #+END_quote **** ct-tint-ratio ~(FOREGROUND BACKGROUND RATIO)~ Tint a FOREGROUND against BACKGROUND until contrast RATIO minimum is reached. #+BEGIN_src elisp (ct-tint-ratio "#4fa5e8" "#bbbbbb" 3) ;; => "#1369ac" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]],[[https://via.placeholder.com/16/bbbbbb/000000.png?text=+]] → [[https://via.placeholder.com/16/1369ac/000000.png?text=+]] #+END_quote **** ct-rotation-hpluv ~(C INTERVAL)~ Perform a hue rotation in hpluv space starting with color C by INTERVAL degrees. #+BEGIN_src elisp (ct-rotation-hpluv "#4fa5e8" 60) ;; => ("#72a2d2" "#c48acb" "#d78895" "#b89a59" "#74ac68" "#03b1a7") #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/72a2d2/000000.png?text=+]],[[https://via.placeholder.com/16/c48acb/000000.png?text=+]],[[https://via.placeholder.com/16/d78895/000000.png?text=+]],[[https://via.placeholder.com/16/b89a59/000000.png?text=+]],[[https://via.placeholder.com/16/74ac68/000000.png?text=+]],[[https://via.placeholder.com/16/03b1a7/000000.png?text=+]] #+END_quote **** ct-rotation-hsl ~(C INTERVAL)~ Perform a hue rotation in hsl space starting with color C by INTERVAL degrees. #+BEGIN_src elisp (ct-rotation-hsl "#4fa5e8" 60) ;; => ("#4fa4e8" "#914fe8" "#e84fa4" "#e8914f" "#a5e84f" "#4fe892") #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/4fa4e8/000000.png?text=+]],[[https://via.placeholder.com/16/914fe8/000000.png?text=+]],[[https://via.placeholder.com/16/e84fa4/000000.png?text=+]],[[https://via.placeholder.com/16/e8914f/000000.png?text=+]],[[https://via.placeholder.com/16/a5e84f/000000.png?text=+]],[[https://via.placeholder.com/16/4fe892/000000.png?text=+]] #+END_quote **** ct-rotation-hsluv ~(C INTERVAL)~ Perform a hue rotation in hsluv space starting with color C by INTERVAL degrees. #+BEGIN_src elisp (ct-rotation-hsluv "#4fa5e8" 60) ;; => ("#4ea5e7" "#e173ec" "#f0798f" "#bc9a43" "#5cb143" "#48ada5") #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/4ea5e7/000000.png?text=+]],[[https://via.placeholder.com/16/e173ec/000000.png?text=+]],[[https://via.placeholder.com/16/f0798f/000000.png?text=+]],[[https://via.placeholder.com/16/bc9a43/000000.png?text=+]],[[https://via.placeholder.com/16/5cb143/000000.png?text=+]],[[https://via.placeholder.com/16/48ada5/000000.png?text=+]] #+END_quote **** ct-rotation-hsv ~(C INTERVAL)~ Perform a hue rotation in hsv space starting with color C by INTERVAL degrees. #+BEGIN_src elisp (ct-rotation-hsv "#4fa5e8" 60) ;; => ("#4ea5e8" "#914ee8" "#e84ea5" "#e8924e" "#a5e84e" "#4ee892") #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/4ea5e8/000000.png?text=+]],[[https://via.placeholder.com/16/914ee8/000000.png?text=+]],[[https://via.placeholder.com/16/e84ea5/000000.png?text=+]],[[https://via.placeholder.com/16/e8924e/000000.png?text=+]],[[https://via.placeholder.com/16/a5e84e/000000.png?text=+]],[[https://via.placeholder.com/16/4ee892/000000.png?text=+]] #+END_quote **** ct-rotation-lch ~(C INTERVAL)~ Perform a hue rotation in lch space starting with color C by INTERVAL degrees. #+BEGIN_src elisp (ct-rotation-lch "#4fa5e8" 60) ;; => ("#4fa4e8" "#c48acc" "#e58183" "#bd9953" "#6dad6f" "#00b1ba") #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/4fa4e8/000000.png?text=+]],[[https://via.placeholder.com/16/c48acc/000000.png?text=+]],[[https://via.placeholder.com/16/e58183/000000.png?text=+]],[[https://via.placeholder.com/16/bd9953/000000.png?text=+]],[[https://via.placeholder.com/16/6dad6f/000000.png?text=+]],[[https://via.placeholder.com/16/00b1ba/000000.png?text=+]] #+END_quote ** RGB https://notes.neeasade.net/color-spaces.html#h-99356355-d54c-41d8-bc1a-6e14e29f42c8 **** ct-make-rgb ~(R G B)~ Make a color using RGB properties. #+BEGIN_src elisp (ct-make-rgb 30.980392156862745 64.70588235294117 90.98039215686275) ;; => "#4fa4e8" #+END_src #+BEGIN_quote → [[https://via.placeholder.com/16/4fa4e8/000000.png?text=+]] #+END_quote **** ct-get-rgb ~(C)~ Get rgb representation of color C. #+BEGIN_src elisp (ct-get-rgb "#4fa5e8") ;; => (30.980392156862745 64.70588235294117 90.98039215686275) #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → (30.980392156862745 64.70588235294117 90.98039215686275) #+END_quote **** ct-get-rgb-r ~(C)~ Get rgb-r representation of color C. #+BEGIN_src elisp (ct-get-rgb-r "#4fa5e8") ;; => 30.980392156862745 #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → 30.980392156862745 #+END_quote **** ct-get-rgb-g ~(C)~ Get rgb-g representation of color C. #+BEGIN_src elisp (ct-get-rgb-g "#4fa5e8") ;; => 64.70588235294117 #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → 64.70588235294117 #+END_quote **** ct-get-rgb-b ~(C)~ Get rgb-b representation of color C. #+BEGIN_src elisp (ct-get-rgb-b "#4fa5e8") ;; => 90.98039215686275 #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → 90.98039215686275 #+END_quote **** ct-edit-rgb ~(C TRANSFORM)~ Work with a color C in the RGB space using function TRANSFORM. Ranges for RGB are all 0-100. #+BEGIN_src elisp (ct-edit-rgb "#4fa5e8" (lambda (R G B) (list R 0 0))) ;; => "#4f0000" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/4f0000/000000.png?text=+]] #+END_quote **** ct-edit-rgb-b ~(C FUNC-OR-VAL)~ Transform property rgb-b of C using FUNC-OR-VAL. #+BEGIN_src elisp (ct-edit-rgb-b "#4fa5e8" (lambda (b) (+ b 50))) ;; => "#4fa4ff" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/4fa4ff/000000.png?text=+]] #+END_quote **** ct-edit-rgb-b-dec ~(C &optional V)~ Decrease rgb-b value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-rgb-b-dec "#bbbbbb" 10) ;; => "#bbbba1" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/bbbbbb/000000.png?text=+]] → [[https://via.placeholder.com/16/bbbba1/000000.png?text=+]] #+END_quote **** ct-edit-rgb-b-inc ~(C &optional V)~ Increase rgb-b value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-rgb-b-inc "#bbbbbb") ;; => "#bbbbbc" #+END_src **** ct-edit-rgb-g ~(C FUNC-OR-VAL)~ Transform property rgb-g of C using FUNC-OR-VAL. #+BEGIN_src elisp (ct-edit-rgb-g "#4fa5e8" 100) ;; => "#4fffe8" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/4fffe8/000000.png?text=+]] #+END_quote **** ct-edit-rgb-g-dec ~(C &optional V)~ Decrease rgb-g value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-rgb-g-dec "#bbbbbb" 10) ;; => "#bba1bb" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/bbbbbb/000000.png?text=+]] → [[https://via.placeholder.com/16/bba1bb/000000.png?text=+]] #+END_quote **** ct-edit-rgb-g-inc ~(C &optional V)~ Increase rgb-g value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-rgb-g-inc "#bbbbbb") ;; => "#bbbcbb" #+END_src **** ct-edit-rgb-r ~(C FUNC-OR-VAL)~ Transform property rgb-r of C using FUNC-OR-VAL. #+BEGIN_src elisp (ct-edit-rgb-r "#4fa5e8" 100) ;; => "#ffa4e8" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/ffa4e8/000000.png?text=+]] #+END_quote **** ct-edit-rgb-r-dec ~(C &optional V)~ Decrease rgb-r value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-rgb-r-dec "#bbbbbb" 10) ;; => "#a1bbbb" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/bbbbbb/000000.png?text=+]] → [[https://via.placeholder.com/16/a1bbbb/000000.png?text=+]] #+END_quote **** ct-edit-rgb-r-inc ~(C &optional V)~ Increase rgb-r value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-rgb-r-inc "#bbbbbb") ;; => "#bcbbbb" #+END_src ** LAB https://notes.neeasade.net/color-spaces.html#h-9d5a1a9a-75d3-48f5-bf00-85332d9b023e **** ct-make-lab ~(L A B)~ Make a color using LAB properties. #+BEGIN_src elisp (ct-make-lab 65.27524119433272 -5.264411618969234 -41.33308089969405) ;; => "#4fa4e8" #+END_src #+BEGIN_quote → [[https://via.placeholder.com/16/4fa4e8/000000.png?text=+]] #+END_quote **** ct-get-lab ~(C)~ Get lab representation of color C. #+BEGIN_src elisp (ct-get-lab "#4fa5e8") ;; => (65.27524119433272 -5.264411618969234 -41.33308089969405) #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → (65.27524119433272 -5.264411618969234 -41.33308089969405) #+END_quote **** ct-get-lab-l ~(C)~ Get lab-l representation of color C. #+BEGIN_src elisp (ct-get-lab-l "#4fa5e8") ;; => 65.27524119433272 #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → 65.27524119433272 #+END_quote **** ct-get-lab-b ~(C)~ Get lab-b representation of color C. #+BEGIN_src elisp (ct-get-lab-b "#4fa5e8") ;; => -41.33308089969405 #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → -41.33308089969405 #+END_quote **** ct-get-lab-a ~(C)~ Get lab-a representation of color C. #+BEGIN_src elisp (ct-get-lab-a "#4fa5e8") ;; => -5.264411618969234 #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → -5.264411618969234 #+END_quote **** ct-edit-lab ~(C TRANSFORM)~ Work with a color C in the LAB space using function TRANSFORM. Ranges for LAB are {0-100,-100-100,-100-100}. #+BEGIN_src elisp (ct-edit-lab "#4fa5e8" (lambda (L A B) (list L -100 -100))) ;; => "#00ccff" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/00ccff/000000.png?text=+]] #+END_quote **** ct-edit-lab-a ~(C FUNC-OR-VAL)~ Transform property lab-a of C using FUNC-OR-VAL. #+BEGIN_src elisp (ct-edit-lab-a "#4fa5e8" (lambda (a) (- a 20))) ;; => "#00aee7" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/00aee7/000000.png?text=+]] #+END_quote **** ct-edit-lab-a-dec ~(C &optional V)~ Decrease lab-a value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-lab-a-dec "#4fa5e8" 20) ;; => "#00aee7" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/00aee7/000000.png?text=+]] #+END_quote **** ct-edit-lab-a-inc ~(C &optional V)~ Increase lab-a value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-lab-a-inc "#4fa5e8" 20) ;; => "#8c99e8" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/8c99e8/000000.png?text=+]] #+END_quote **** ct-edit-lab-b ~(C FUNC-OR-VAL)~ Transform property lab-b of C using FUNC-OR-VAL. #+BEGIN_src elisp (ct-edit-lab-b "#4fa5e8" 100) ;; => "#b79e00" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/b79e00/000000.png?text=+]] #+END_quote **** ct-edit-lab-b-dec ~(C &optional V)~ Decrease lab-b value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-lab-b-dec "#4fa5e8" 20) ;; => "#00a7ff" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/00a7ff/000000.png?text=+]] #+END_quote **** ct-edit-lab-b-inc ~(C &optional V)~ Increase lab-b value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-lab-b-inc "#4fa5e8" 20) ;; => "#7aa3c4" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/7aa3c4/000000.png?text=+]] #+END_quote **** ct-edit-lab-l ~(C FUNC-OR-VAL)~ Transform property lab-l of C using FUNC-OR-VAL. #+BEGIN_src elisp (ct-edit-lab-l "#4fa5e8" 0) ;; => "#000a3d" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/000a3d/000000.png?text=+]] #+END_quote **** ct-edit-lab-l-dec ~(C &optional V)~ Decrease lab-l value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-lab-l-dec "#4fa5e8") ;; => "#4ea4e7" #+END_src **** ct-edit-lab-l-inc ~(C &optional V)~ Increase lab-l value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-lab-l-inc "#4fa5e8") ;; => "#50a5e8" #+END_src ** HSL https://notes.neeasade.net/color-spaces.html#h-43869bc7-a7d1-410f-9341-521974751dac **** ct-make-hsl ~(H S L)~ Make a color using HSL properties. #+BEGIN_src elisp (ct-make-hsl 206.27450980392157 76.88442211055275 60.98039215686275) ;; => "#4fa4e8" #+END_src #+BEGIN_quote → [[https://via.placeholder.com/16/4fa4e8/000000.png?text=+]] #+END_quote **** ct-get-hsl ~(C)~ Get hsl representation of color C. #+BEGIN_src elisp (ct-get-hsl "#4fa5e8") ;; => (206.27450980392157 76.88442211055275 60.98039215686275) #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → (206.27450980392157 76.88442211055275 60.98039215686275) #+END_quote **** ct-get-hsl-s ~(C)~ Get hsl-s representation of color C. #+BEGIN_src elisp (ct-get-hsl-s "#4fa5e8") ;; => 76.88442211055275 #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → 76.88442211055275 #+END_quote **** ct-get-hsl-l ~(C)~ Get hsl-l representation of color C. #+BEGIN_src elisp (ct-get-hsl-l "#4fa5e8") ;; => 60.98039215686275 #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → 60.98039215686275 #+END_quote **** ct-get-hsl-h ~(C)~ Get hsl-h representation of color C. #+BEGIN_src elisp (ct-get-hsl-h "#4fa5e8") ;; => 206.27450980392157 #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → 206.27450980392157 #+END_quote **** ct-edit-hsl ~(C TRANSFORM)~ Work with a color C in the HSL space using function TRANSFORM. Ranges for HSL are {0-360,0-100,0-100}. #+BEGIN_src elisp (ct-edit-hsl "#4fa5e8" (lambda (H S L) (list (+ H 60) 100 L))) ;; => "#8f38ff" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/8f38ff/000000.png?text=+]] #+END_quote **** ct-edit-hsl-h ~(C FUNC-OR-VAL)~ Transform property hsl-h of C using FUNC-OR-VAL. #+BEGIN_src elisp (ct-edit-hsl-h "#4fa5e8" (lambda (H) (+ H 60))) ;; => "#914fe8" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/914fe8/000000.png?text=+]] #+END_quote **** ct-edit-hsl-h-dec ~(C &optional V)~ Decrease hsl-h value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-hsl-h-dec "#4fa5e8") ;; => "#4fa6e8" #+END_src **** ct-edit-hsl-h-inc ~(C &optional V)~ Increase hsl-h value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-hsl-h-inc "#4fa5e8") ;; => "#4fa4e8" #+END_src **** ct-edit-hsl-l ~(C FUNC-OR-VAL)~ Transform property hsl-l of C using FUNC-OR-VAL. #+BEGIN_src elisp (ct-edit-hsl-l "#4fa5e8" 0) ;; => "#000000" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/000000/000000.png?text=+]] #+END_quote **** ct-edit-hsl-l-dec ~(C &optional V)~ Decrease hsl-l value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-hsl-l-dec "#4fa5e8") ;; => "#4ea4e7" #+END_src **** ct-edit-hsl-l-inc ~(C &optional V)~ Increase hsl-l value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-hsl-l-inc "#4fa5e8") ;; => "#50a5e8" #+END_src **** ct-edit-hsl-s ~(C FUNC-OR-VAL)~ Transform property hsl-s of C using FUNC-OR-VAL. #+BEGIN_src elisp (ct-edit-hsl-s "#4fa5e8" 100) ;; => "#38a7ff" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/38a7ff/000000.png?text=+]] #+END_quote **** ct-edit-hsl-s-dec ~(C &optional V)~ Decrease hsl-s value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-hsl-s-dec "#4fa5e8") ;; => "#4fa4e7" #+END_src **** ct-edit-hsl-s-inc ~(C &optional V)~ Increase hsl-s value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-hsl-s-inc "#4fa5e8") ;; => "#4ea5e8" #+END_src ** HSLuv https://notes.neeasade.net/color-spaces.html#h-c147b84d-d95b-4d2d-8426-2f96529a8428 **** ct-make-hsluv ~(H S L)~ Make a color using HSLuv properties. #+BEGIN_src elisp (ct-make-hsluv 242.63535329133538 81.00935604214261 65.27665592005344) ;; => "#4ea5e7" #+END_src #+BEGIN_quote → [[https://via.placeholder.com/16/4ea5e7/000000.png?text=+]] #+END_quote **** ct-get-hsluv ~(C)~ Get hsluv representation of color C. #+BEGIN_src elisp (ct-get-hsluv "#4fa5e8") ;; => (242.63535329133538 81.00935604214261 65.27665592005344) #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → (242.63535329133538 81.00935604214261 65.27665592005344) #+END_quote **** ct-get-hsluv-s ~(C)~ Get hsluv-s representation of color C. #+BEGIN_src elisp (ct-get-hsluv-s "#4fa5e8") ;; => 81.00935604214261 #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → 81.00935604214261 #+END_quote **** ct-get-hsluv-l ~(C)~ Get hsluv-l representation of color C. #+BEGIN_src elisp (ct-get-hsluv-l "#4fa5e8") ;; => 65.27665592005344 #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → 65.27665592005344 #+END_quote **** ct-get-hsluv-h ~(C)~ Get hsluv-h representation of color C. #+BEGIN_src elisp (ct-get-hsluv-h "#4fa5e8") ;; => 242.63535329133538 #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → 242.63535329133538 #+END_quote **** ct-edit-hsluv ~(C TRANSFORM)~ Work with a color C in the HSLUV space using function TRANSFORM. Ranges for HSLUV are {0-360,0-100,0-100}. #+BEGIN_src elisp (ct-edit-hsluv "#4fa5e8" (lambda (H S L) (list (+ H 60) 100 L))) ;; => "#f160ff" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/f160ff/000000.png?text=+]] #+END_quote **** ct-edit-hsluv-h ~(C FUNC-OR-VAL)~ Transform property hsluv-h of C using FUNC-OR-VAL. #+BEGIN_src elisp (ct-edit-hsluv-h "#4fa5e8" (lambda (H) (+ H 60))) ;; => "#e173ec" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/e173ec/000000.png?text=+]] #+END_quote **** ct-edit-hsluv-h-dec ~(C &optional V)~ Decrease hsluv-h value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-hsluv-h-dec "#4fa5e8") ;; => "#4ea5e7" #+END_src **** ct-edit-hsluv-h-inc ~(C &optional V)~ Increase hsluv-h value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-hsluv-h-inc "#4fa5e8") ;; => "#4fa4e8" #+END_src **** ct-edit-hsluv-l ~(C FUNC-OR-VAL)~ Transform property hsluv-l of C using FUNC-OR-VAL. #+BEGIN_src elisp (ct-edit-hsluv-l "#4fa5e8" 0) ;; => "#000000" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/000000/000000.png?text=+]] #+END_quote **** ct-edit-hsluv-l-dec ~(C &optional V)~ Decrease hsluv-l value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-hsluv-l-dec "#4fa5e8") ;; => "#4ea4e7" #+END_src **** ct-edit-hsluv-l-inc ~(C &optional V)~ Increase hsluv-l value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-hsluv-l-inc "#4fa5e8") ;; => "#4fa5e9" #+END_src **** ct-edit-hsluv-s ~(C FUNC-OR-VAL)~ Transform property hsluv-s of C using FUNC-OR-VAL. #+BEGIN_src elisp (ct-edit-hsluv-s "#4fa5e8" 100) ;; => "#00a6f8" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/00a6f8/000000.png?text=+]] #+END_quote **** ct-edit-hsluv-s-dec ~(C &optional V)~ Decrease hsluv-s value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-hsluv-s-dec "#4fa5e8") ;; => "#4fa4e7" #+END_src **** ct-edit-hsluv-s-inc ~(C &optional V)~ Increase hsluv-s value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-hsluv-s-inc "#4fa5e8") ;; => "#4ea5e8" #+END_src ** LCH https://notes.neeasade.net/color-spaces.html#h-c4f93e1f-4fa6-4ebc-99c1-18b6de0ef413 **** ct-make-lch ~(L C H)~ Make a color using LCH properties. #+BEGIN_src elisp (ct-make-lch 65.27524119433272 41.666984608375394 -97.25842954163491) ;; => "#4fa4e8" #+END_src #+BEGIN_quote → [[https://via.placeholder.com/16/4fa4e8/000000.png?text=+]] #+END_quote **** ct-get-lch ~(C)~ Get lch representation of color C. #+BEGIN_src elisp (ct-get-lch "#4fa5e8") ;; => (65.27524119433272 41.666984608375394 -97.25842954163491) #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → (65.27524119433272 41.666984608375394 -97.25842954163491) #+END_quote **** ct-get-lch-l ~(C)~ Get lch-l representation of color C. #+BEGIN_src elisp (ct-get-lch-l "#4fa5e8") ;; => 65.27524119433272 #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → 65.27524119433272 #+END_quote **** ct-get-lch-h ~(C)~ Get lch-h representation of color C. #+BEGIN_src elisp (ct-get-lch-h "#4fa5e8") ;; => -97.25842954163491 #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → -97.25842954163491 #+END_quote **** ct-get-lch-c ~(C)~ Get lch-c representation of color C. #+BEGIN_src elisp (ct-get-lch-c "#4fa5e8") ;; => 41.666984608375394 #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → 41.666984608375394 #+END_quote **** ct-edit-lch ~(C TRANSFORM)~ Work with a color C in the LCH space using function TRANSFORM. Ranges for LCH are {0-100,0-100,0-360}. #+BEGIN_src elisp (ct-edit-lch "#4fa5e8" (lambda (L C H) (list L 100 (+ H 90)))) ;; => "#ff00b8" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/ff00b8/000000.png?text=+]] #+END_quote **** ct-edit-lch-c ~(C FUNC-OR-VAL)~ Transform property lch-c of C using FUNC-OR-VAL. #+BEGIN_src elisp (ct-edit-lch-c "#4fa5e8" 100) ;; => "#00b0ff" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/00b0ff/000000.png?text=+]] #+END_quote **** ct-edit-lch-c-dec ~(C &optional V)~ Decrease lch-c value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-lch-c-dec "#4fa5e8") ;; => "#4fa4e7" #+END_src **** ct-edit-lch-c-inc ~(C &optional V)~ Increase lch-c value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-lch-c-inc "#4fa5e8") ;; => "#4ea5e8" #+END_src **** ct-edit-lch-h ~(C FUNC-OR-VAL)~ Transform property lch-h of C using FUNC-OR-VAL. #+BEGIN_src elisp (ct-edit-lch-h "#4fa5e8" (lambda (H) (+ H 90))) ;; => "#df81a9" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/df81a9/000000.png?text=+]] #+END_quote **** ct-edit-lch-h-dec ~(C &optional V)~ Decrease lch-h value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-lch-h-dec "#4fa5e8") ;; => "#4ea5e7" #+END_src **** ct-edit-lch-h-inc ~(C &optional V)~ Increase lch-h value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-lch-h-inc "#4fa5e8") ;; => "#4fa4e8" #+END_src **** ct-edit-lch-l ~(C FUNC-OR-VAL)~ Transform property lch-l of C using FUNC-OR-VAL. #+BEGIN_src elisp (ct-edit-lch-l "#4fa5e8" 100) ;; => "#baffff" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/baffff/000000.png?text=+]] #+END_quote **** ct-edit-lch-l-dec ~(C &optional V)~ Decrease lch-l value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-lch-l-dec "#4fa5e8") ;; => "#4ea4e7" #+END_src **** ct-edit-lch-l-inc ~(C &optional V)~ Increase lch-l value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-lch-l-inc "#4fa5e8") ;; => "#50a5e8" #+END_src ** HSV https://en.wikipedia.org/wiki/HSL_and_HSV **** ct-make-hsv ~(H S V)~ Make a color using HSV properties. #+BEGIN_src elisp (ct-make-hsv 206.27450980392157 65.94827586206897 90.98039215686275) ;; => "#4ea5e8" #+END_src #+BEGIN_quote → [[https://via.placeholder.com/16/4ea5e8/000000.png?text=+]] #+END_quote **** ct-get-hsv ~(C)~ Get hsv representation of color C. #+BEGIN_src elisp (ct-get-hsv "#4fa5e8") ;; => (206.27450980392157 65.94827586206897 90.98039215686275) #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → (206.27450980392157 65.94827586206897 90.98039215686275) #+END_quote **** ct-get-hsv-v ~(C)~ Get hsv-v representation of color C. #+BEGIN_src elisp (ct-get-hsv-v "#4fa5e8") ;; => 90.98039215686275 #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → 90.98039215686275 #+END_quote **** ct-get-hsv-s ~(C)~ Get hsv-s representation of color C. #+BEGIN_src elisp (ct-get-hsv-s "#4fa5e8") ;; => 65.94827586206897 #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → 65.94827586206897 #+END_quote **** ct-get-hsv-h ~(C)~ Get hsv-h representation of color C. #+BEGIN_src elisp (ct-get-hsv-h "#4fa5e8") ;; => 206.27450980392157 #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → 206.27450980392157 #+END_quote **** ct-edit-hsv ~(C TRANSFORM)~ Work with a color C in the HSV space using function TRANSFORM. Ranges for HSV are {0-360,0-100,0-100}. #+BEGIN_src elisp (ct-edit-hsv "#4fa5e8" (lambda (H S V) (list H 20 100))) ;; => "#cce8ff" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/cce8ff/000000.png?text=+]] #+END_quote **** ct-edit-hsv-h ~(C FUNC-OR-VAL)~ Transform property hsv-h of C using FUNC-OR-VAL. #+BEGIN_src elisp (ct-edit-hsv-h "#4fa5e8" (-partial #'+ 30)) ;; => "#4e58e8" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/4e58e8/000000.png?text=+]] #+END_quote **** ct-edit-hsv-h-dec ~(C &optional V)~ Decrease hsv-h value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-hsv-h-dec "#4fa5e8") ;; => "#4ea5e8" #+END_src **** ct-edit-hsv-h-inc ~(C &optional V)~ Increase hsv-h value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-hsv-h-inc "#4fa5e8") ;; => "#4ea4e8" #+END_src **** ct-edit-hsv-s ~(C FUNC-OR-VAL)~ Transform property hsv-s of C using FUNC-OR-VAL. #+BEGIN_src elisp (ct-edit-hsv-s "#4fa5e8" 20) ;; => "#b9d3e8" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/b9d3e8/000000.png?text=+]] #+END_quote **** ct-edit-hsv-s-dec ~(C &optional V)~ Decrease hsv-s value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-hsv-s-dec "#4fa5e8") ;; => "#50a5e8" #+END_src **** ct-edit-hsv-s-inc ~(C &optional V)~ Increase hsv-s value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-hsv-s-inc "#4fa5e8") ;; => "#4ea4e8" #+END_src **** ct-edit-hsv-v ~(C FUNC-OR-VAL)~ Transform property hsv-v of C using FUNC-OR-VAL. #+BEGIN_src elisp (ct-edit-hsv-v "#4fa5e8" 100) ;; => "#56b5ff" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/56b5ff/000000.png?text=+]] #+END_quote **** ct-edit-hsv-v-dec ~(C &optional V)~ Decrease hsv-v value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-hsv-v-dec "#4fa5e8") ;; => "#4ea4e7" #+END_src **** ct-edit-hsv-v-inc ~(C &optional V)~ Increase hsv-v value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-hsv-v-inc "#4fa5e8") ;; => "#4fa5e9" #+END_src ** HPLUV https://ajalt.github.io/colormath/api/colormath/com.github.ajalt.colormath.model/-h-p-luv/index.html **** ct-make-hpluv ~(H P L)~ Make a color using HPLuv properties. #+BEGIN_src elisp (ct-make-hpluv 242.63535329133538 143.13047428079187 65.27665592005344) ;; => "#72a2d2" #+END_src #+BEGIN_quote → [[https://via.placeholder.com/16/72a2d2/000000.png?text=+]] #+END_quote **** ct-get-hpluv ~(C)~ Get hpluv representation of color C. #+BEGIN_src elisp (ct-get-hpluv "#4fa5e8") ;; => (242.63535329133538 143.13047428079187 65.27665592005344) #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → (242.63535329133538 143.13047428079187 65.27665592005344) #+END_quote **** ct-get-hpluv-p ~(C)~ Get hpluv-p representation of color C. #+BEGIN_src elisp (ct-get-hpluv-p "#4fa5e8") ;; => 143.13047428079187 #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → 143.13047428079187 #+END_quote **** ct-get-hpluv-l ~(C)~ Get hpluv-l representation of color C. #+BEGIN_src elisp (ct-get-hpluv-l "#4fa5e8") ;; => 65.27665592005344 #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → 65.27665592005344 #+END_quote **** ct-get-hpluv-h ~(C)~ Get hpluv-h representation of color C. #+BEGIN_src elisp (ct-get-hpluv-h "#4fa5e8") ;; => 242.63535329133538 #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → 242.63535329133538 #+END_quote **** ct-edit-hpluv ~(C TRANSFORM)~ Work with a color C in the HPLUV space using function TRANSFORM. Ranges for HPLUV are {0-360,0-100,0-100}. #+BEGIN_src elisp (ct-edit-hpluv "#4fa5e8" (lambda (H P L) (list H 100 L))) ;; => "#72a2d2" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/72a2d2/000000.png?text=+]] #+END_quote **** ct-edit-hpluv-h ~(C FUNC-OR-VAL)~ Transform property hpluv-h of C using FUNC-OR-VAL. #+BEGIN_src elisp (ct-edit-hpluv-h "#4fa5e8" 0) ;; => "#d78798" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/d78798/000000.png?text=+]] #+END_quote **** ct-edit-hpluv-h-dec ~(C &optional V)~ Decrease hpluv-h value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-hpluv-h-dec "#4fa5e8") ;; => "#71a2d2" #+END_src **** ct-edit-hpluv-h-inc ~(C &optional V)~ Increase hpluv-h value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-hpluv-h-inc "#4fa5e8") ;; => "#72a2d2" #+END_src **** ct-edit-hpluv-l ~(C FUNC-OR-VAL)~ Transform property hpluv-l of C using FUNC-OR-VAL. #+BEGIN_src elisp (ct-edit-hpluv-l "#4fa5e8" 100) ;; => "#feffff" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/feffff/000000.png?text=+]] #+END_quote **** ct-edit-hpluv-l-dec ~(C &optional V)~ Decrease hpluv-l value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-hpluv-l-dec "#4fa5e8") ;; => "#71a2d2" #+END_src **** ct-edit-hpluv-l-inc ~(C &optional V)~ Increase hpluv-l value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-hpluv-l-inc "#4fa5e8") ;; => "#72a3d3" #+END_src **** ct-edit-hpluv-p ~(C FUNC-OR-VAL)~ Transform property hpluv-p of C using FUNC-OR-VAL. #+BEGIN_src elisp (ct-edit-hpluv-p "#4fa5e8" 100) ;; => "#72a2d2" #+END_src #+BEGIN_quote [[https://via.placeholder.com/16/4fa5e8/000000.png?text=+]] → [[https://via.placeholder.com/16/72a2d2/000000.png?text=+]] #+END_quote **** ct-edit-hpluv-p-dec ~(C &optional V)~ Decrease hpluv-p value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-hpluv-p-dec "#4fa5e8") ;; => "#72a2d2" #+END_src **** ct-edit-hpluv-p-inc ~(C &optional V)~ Increase hpluv-p value of C by V (defaults to the minimum amount needed to change C). #+BEGIN_src elisp (ct-edit-hpluv-p-inc "#4fa5e8") ;; => "#72a2d2" #+END_src

** Gotchas

Some colors as defined in color spaces may not be represented in the RGB space (and vice versa). The edit functions clamp values going out. One example is the narrowly scoped ~hpluv~ space:

#+begin_src emacs-lisp (ct-get-hpluv "#dd00cc")

;; That p value is way out of range! ;; => (314.3830496716472 282.01497572464575 51.53528501195089)

;; notice we ask for the same color back, but the transform functions clamp the output to maximum HPL values: (ct-edit-hpluv "#dd00cc" 'list)

;; => "#9f6898" #+end_src

** Testing

Right now testing happens by using the ct-make-* functions(these use the transform functions, which make up the basis for all the color space functions) against:

  • https://css.land/lch/
  • http://colorizer.org/

** Related links

Emacs color libraries:

  • https://github.com/emacs-mirror/emacs/blob/master/lisp/color.el
  • https://github.com/emacsfodder/kurecolor
  • https://github.com/yurikhan/yk-color
  • https://github.com/hsluv/hsluv-emacs

General color knowledge:

  • http://colorizer.org/
  • https://peteroupc.github.io/colorgen.html
  • https://www.w3.org/TR/WCAG20/#relativeluminancedef
  • https://en.wikipedia.org/wiki/CIELAB_color_space