aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS.org4
-rw-r--r--compat-30.el44
-rw-r--r--compat-tests.el40
-rw-r--r--compat.texi24
4 files changed, 112 insertions, 0 deletions
diff --git a/NEWS.org b/NEWS.org
index 5a5832f..34c3081 100644
--- a/NEWS.org
+++ b/NEWS.org
@@ -2,6 +2,10 @@
#+link: compat-gh https://github.com/emacs-compat/compat/issues/
#+options: toc:nil num:nil author:nil
+* Development
+
+- compat-30: Add oklab color functions.
+
* Release of "Compat" Version 30.0.2.0
- compat-30: Rename =trusted-files= to =trusted-content=.
diff --git a/compat-30.el b/compat-30.el
index cb6e442..2decb93 100644
--- a/compat-30.el
+++ b/compat-30.el
@@ -215,6 +215,50 @@ details."
(funcall completion-lazy-hilit-fn (copy-sequence str))
str))
+;;;; Defined in color.el
+
+(compat-defun color-oklab-to-xyz (l a b) ;; <compat-tests:color-oklab-to-xyz>
+ "Convert the OkLab color represented by L A B to CIE XYZ.
+Oklab is a perceptual color space created by Björn Ottosson
+<https://bottosson.github.io/posts/oklab/>. It has the property that
+changes in the hue and saturation of a color can be made while maintaining
+the same perceived lightness."
+ :feature color
+ (let ((ll (expt (+ (* 1.0 l) (* 0.39633779 a) (* 0.21580376 b)) 3))
+ (mm (expt (+ (* 1.00000001 l) (* -0.10556134 a) (* -0.06385417 b)) 3))
+ (ss (expt (+ (* 1.00000005 l) (* -0.08948418 a) (* -1.29148554 b)) 3)))
+ (list (+ (* ll 1.22701385) (* mm -0.55779998) (* ss 0.28125615))
+ (+ (* ll -0.04058018) (* mm 1.11225687) (* ss -0.07167668))
+ (+ (* ll -0.07638128) (* mm -0.42148198) (* ss 1.58616322)))))
+
+(compat-defun color-xyz-to-oklab (x y z) ;; <compat-tests:color-xyz-to-oklab>
+ "Convert the CIE XYZ color represented by X Y Z to Oklab."
+ :feature color
+ (let ((ll (+ (* x 0.8189330101) (* y 0.3618667424) (* z -0.1288597137)))
+ (mm (+ (* x 0.0329845436) (* y 0.9293118715) (* z 0.0361456387)))
+ (ss (+ (* x 0.0482003018) (* y 0.2643662691) (* z 0.6338517070))))
+ (let*
+ ((cube-root (lambda (f)
+ (if (< f 0)
+ (- (expt (- f) (/ 1.0 3.0)))
+ (expt f (/ 1.0 3.0)))))
+ (lll (funcall cube-root ll))
+ (mmm (funcall cube-root mm))
+ (sss (funcall cube-root ss)))
+ (list (+ (* lll 0.2104542553) (* mmm 0.7936177850) (* sss -0.0040720468))
+ (+ (* lll 1.9779984951) (* mmm -2.4285922050) (* sss 0.4505937099))
+ (+ (* lll 0.0259040371) (* mmm 0.7827717662) (* sss -0.8086757660))))))
+
+(compat-defun color-oklab-to-srgb (l a b) ;; <compat-tests:color-oklab-to-srgb>
+ "Convert the Oklab color represented by L A B to sRGB."
+ :feature color
+ (apply #'color-xyz-to-srgb (color-oklab-to-xyz l a b)))
+
+(compat-defun color-srgb-to-oklab (r g b) ;; <compat-tests:color-srgb-to-oklab>
+ "Convert the sRGB color R G B to Oklab."
+ :feature color
+ (apply #'color-xyz-to-oklab (color-srgb-to-xyz r g b)))
+
;;;; Defined in subr.el
(compat-defmacro static-if (condition then-form &rest else-forms) ;; <compat-tests:static-if>
diff --git a/compat-tests.el b/compat-tests.el
index 223d0dd..baba1c2 100644
--- a/compat-tests.el
+++ b/compat-tests.el
@@ -56,6 +56,7 @@
(require 'time-date)
(require 'image)
(require 'text-property-search nil t)
+(require 'color)
;; Setup tramp mock
(require 'tramp)
@@ -2681,6 +2682,45 @@
(should-not (color-values-from-color-spec "rgbi : 0/0/0"))
(should-not (color-values-from-color-spec "rgbi:0/0.5/10")))
+(defun compat--color-approx-equal (color1 color2)
+ "Return t if COLOR1 and COLOR2 are approximately equal."
+ (seq-every-p
+ (lambda (x) (< (abs x) 0.00001))
+ (cl-mapcar #'- color1 color2)))
+
+(ert-deftest compat-color-oklab-to-xyz ()
+ (should (compat--color-approx-equal (compat-call color-oklab-to-xyz 0 0 0) '(0.0 0.0 0.0)))
+ (should (compat--color-approx-equal (compat-call color-oklab-to-xyz 1.0 0.0 0.0)
+ '(0.95047005 1.0 1.0883001)))
+ (should (compat--color-approx-equal (compat-call color-oklab-to-xyz 0.450 1.236 -0.019) '(1.000604 -0.000008 -0.000038)))
+ (should (compat--color-approx-equal (compat-call color-oklab-to-xyz 0.922 -0.671 0.263) '(0.000305 1.000504 0.000898)))
+ (should (compat--color-approx-equal (compat-call color-oklab-to-xyz 0.153 -1.415 -0.449) '(0.000590 0.000057 1.001650))))
+
+(ert-deftest compat-color-xyz-to-oklab ()
+ (should (compat--color-approx-equal (compat-call color-xyz-to-oklab 0 0 0) '(0.0 0.0 0.0)))
+ (should (compat--color-approx-equal (compat-call color-xyz-to-oklab 0.95 1.0 1.089)
+ '(0.999969 -0.000258 -0.000115)))
+ (should (compat--color-approx-equal (compat-call color-xyz-to-oklab 1.0 0.0 0.0)
+ '(0.449932 1.235710 -0.019028)))
+ (should (compat--color-approx-equal (compat-call color-xyz-to-oklab 0.0 1.0 0.0)
+ '(0.921817 -0.671238 0.263324)))
+ (should (compat--color-approx-equal (compat-call color-xyz-to-oklab 0.0 0.0 1.0)
+ '(0.152603 -1.414997 -0.448927))))
+
+(ert-deftest compat-color-srgb-to-oklab ()
+ (should (equal (compat-call color-srgb-to-oklab 0 0 0) '(0.0 0.0 0.0)))
+ (should
+ (compat--color-approx-equal (compat-call color-srgb-to-oklab 0 0 1) '(0.451978 -0.032430 -0.311611)))
+ (should
+ (compat--color-approx-equal (compat-call color-srgb-to-oklab 0.1 0.2 0.3) '(0.313828 -0.019091 -0.052561))))
+
+(ert-deftest compat-color-oklab-to-srgb ()
+ (should (equal (compat-call color-oklab-to-srgb 0 0 0) '(0.0 0.0 0.0)))
+ (should
+ (compat--color-approx-equal (compat-call color-oklab-to-srgb 0.451978 -0.032430 -0.311611) '(0.0 0.0 1.0)))
+ (should
+ (compat--color-approx-equal (compat-call color-oklab-to-srgb 0.313828 -0.019091 -0.052561) '(0.1 0.2 0.3))))
+
(ert-deftest compat-lookup-key ()
(let ((a-map (make-sparse-keymap))
(b-map (make-sparse-keymap)))
diff --git a/compat.texi b/compat.texi
index c9ed82e..2e08c91 100644
--- a/compat.texi
+++ b/compat.texi
@@ -3355,6 +3355,30 @@ Return non-nil if we trust the contents of the current buffer. Here,
also @code{trusted-content}.
@end defun
+@c based on lisp/color.el
+@defun color-oklab-to-xyz l a b
+Convert the OkLab color represented by @var{l} @var{a} @var{b} to CIE XYZ.
+Oklab is a perceptual color space created by Björn Ottosson
+<https://bottosson.github.io/posts/oklab/>. It has the property that
+changes in the hue and saturation of a color can be made while maintaining
+the same perceived lightness.
+@end defun
+
+@c based on lisp/color.el
+@defun color-xyz-to-oklab x y z
+Convert the CIE XYZ color represented by @var{x} @var{y} @var{z} to Oklab.
+@end defun
+
+@c based on lisp/color.el
+@defun color-oklab-to-srgb l a b
+Convert the Oklab color represented by @var{l} @var{a} @var{b} to sRGB.
+@end defun
+
+@c based on lisp/color.el
+@defun color-srgb-to-oklab r g b
+Convert the sRGB color @var{r} @var{g} @var{b} to Oklab.
+@end defun
+
@c copied from lispref/nonascii.texi
@defun char-to-name char
This function returns the Unicode name of @var{char}. It returns