1 ;;; color.el --- Color manipulation laboratory routines -*- coding: utf-8; -*-
3 ;; Copyright (C) 2010-2011 Free Software Foundation, Inc.
5 ;; Author: Julien Danjou <julien@danjou.info>
8 ;; This file is part of GNU Emacs.
10 ;; GNU Emacs is free software: you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation, either version 3 of the License, or
13 ;; (at your option) any later version.
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
25 ;; This package provides color manipulation functions.
34 (unless (boundp 'float-pi
)
35 (defconst float-pi
(* 4 (atan 1)) "The value of Pi (3.1415926...).")))
37 (defun color-rgb->hex
(red green blue
)
38 "Return hexadecimal notation for RED GREEN BLUE color.
39 RED GREEN BLUE must be values between 0 and 1 inclusively."
40 (format "#%02x%02x%02x"
41 (* red
255) (* green
255) (* blue
255)))
43 (defun color-complement (color)
44 "Return the color that is the complement of COLOR."
45 (let ((color (color-rgb->normalize color
)))
46 (list (- 1.0 (car color
))
48 (- 1.0 (caddr color
)))))
50 (defun color-complement-hex (color)
51 "Return the color that is the complement of COLOR, in hexadecimal format."
52 (apply 'color-rgb-
>hex
(color-complement color
)))
54 (defun color-rgb->hsv
(red green blue
)
55 "Convert RED GREEN BLUE values to HSV representation.
56 Hue is in radians. Saturation and values are between 0 and 1
58 (let* ((r (float red
))
65 (cond ((and (= r g
) (= g b
)) 0)
68 (* 60 (/ (- g b
) (- max min
))))
71 (+ 360 (* 60 (/ (- g b
) (- max min
)))))
73 (+ 120 (* 60 (/ (- b r
) (- max min
)))))
75 (+ 240 (* 60 (/ (- r g
) (- max min
)))))))
82 (defun color-rgb->hsl
(red green blue
)
83 "Convert RED GREEN BLUE colors to their HSL representation.
84 RED, GREEN and BLUE must be between 0 and 1 inclusively."
91 (l (/ (+ max min
) 2.0)))
97 (+ (/ (- g b
) delta
) (if (< g b
) 6 0)))
99 (+ (/ (- b r
) delta
) 2))
101 (+ (/ (- r g
) delta
) 4)))
106 (/ delta
(- 2 (+ max min
)))
107 (/ delta
(+ max min
))))
110 (defun color-srgb->xyz
(red green blue
)
111 "Converts RED GREEN BLUE colors from the sRGB color space to CIE XYZ.
112 RED, BLUE and GREEN must be between 0 and 1 inclusively."
113 (let ((r (if (<= red
0.04045)
115 (expt (/ (+ red
0.055) 1.055) 2.4)))
116 (g (if (<= green
0.04045)
118 (expt (/ (+ green
0.055) 1.055) 2.4)))
119 (b (if (<= blue
0.04045)
121 (expt (/ (+ blue
0.055) 1.055) 2.4))))
122 (list (+ (* 0.4124564 r
) (* 0.3575761 g
) (* 0.1804375 b
))
123 (+ (* 0.21266729 r
) (* 0.7151522 g
) (* 0.0721750 b
))
124 (+ (* 0.0193339 r
) (* 0.1191920 g
) (* 0.9503041 b
)))))
126 (defun color-xyz->srgb
(X Y Z
)
127 "Converts CIE X Y Z colors to sRGB color space."
128 (let ((r (+ (* 3.2404542 X
) (* -
1.5371385 Y
) (* -
0.4985314 Z
)))
129 (g (+ (* -
0.9692660 X
) (* 1.8760108 Y
) (* 0.0415560 Z
)))
130 (b (+ (* 0.0556434 X
) (* -
0.2040259 Y
) (* 1.0572252 Z
))))
131 (list (if (<= r
0.0031308)
133 (- (* 1.055 (expt r
(/ 1 2.4))) 0.055))
136 (- (* 1.055 (expt g
(/ 1 2.4))) 0.055))
139 (- (* 1.055 (expt b
(/ 1 2.4))) 0.055)))))
141 (defconst color-d65-xyz
'(0.950455
1.0 1.088753)
142 "D65 white point in CIE XYZ.")
144 (defconst color-cie-ε
(/ 216 24389.0))
145 (defconst color-cie-κ
(/ 24389 27.0))
147 (defun color-xyz->lab
(X Y Z
&optional white-point
)
148 "Converts CIE XYZ to CIE L*a*b*.
149 WHITE-POINT can be specified as (X Y Z) white point to use. If
150 none is set, `color-d65-xyz' is used."
151 (destructuring-bind (Xr Yr Zr
) (or white-point color-d65-xyz
)
155 (fx (if (> xr color-cie-ε
)
157 (/ (+ (* color-cie-κ xr
) 16) 116.0)))
158 (fy (if (> yr color-cie-ε
)
160 (/ (+ (* color-cie-κ yr
) 16) 116.0)))
161 (fz (if (> zr color-cie-ε
)
163 (/ (+ (* color-cie-κ zr
) 16) 116.0))))
165 (- (* 116 fy
) 16) ; L
166 (* 500 (- fx fy
)) ; a
167 (* 200 (- fy fz
)))))) ; b
169 (defun color-lab->xyz
(L a b
&optional white-point
)
170 "Converts CIE L*a*b* to CIE XYZ.
171 WHITE-POINT can be specified as (X Y Z) white point to use. If
172 none is set, `color-d65-xyz' is used."
173 (destructuring-bind (Xr Yr Zr
) (or white-point color-d65-xyz
)
174 (let* ((fy (/ (+ L
16) 116.0))
175 (fz (- fy
(/ b
200.0)))
176 (fx (+ (/ a
500.0) fy
))
177 (xr (if (> (expt fx
3.0) color-cie-ε
)
179 (/ (- (* fx
116) 16) color-cie-κ
)))
180 (yr (if (> L
(* color-cie-κ color-cie-ε
))
181 (expt (/ (+ L
16) 116.0) 3.0)
183 (zr (if (> (expt fz
3) color-cie-ε
)
185 (/ (- (* 116 fz
) 16) color-cie-κ
))))
190 (defun color-srgb->lab
(red green blue
)
191 "Converts RGB to CIE L*a*b*."
192 (apply 'color-xyz-
>lab
(color-srgb->xyz red green blue
)))
194 (defun color-rgb->normalize
(color)
195 "Normalize a RGB color to values between 0 and 1 inclusively."
196 (mapcar (lambda (x) (/ x
65535.0)) (x-color-values color
)))
198 (defun color-lab->srgb
(L a b
)
199 "Converts CIE L*a*b* to RGB."
200 (apply 'color-xyz-
>srgb
(color-lab->xyz L a b
)))
202 (defun color-cie-de2000 (color1 color2
&optional kL kC kH
)
203 "Computes the CIEDE2000 color distance between COLOR1 and COLOR2.
204 Colors must be in CIE L*a*b* format."
205 (destructuring-bind (L₁ a₁ b₁
) color1
206 (destructuring-bind (L₂ a₂ b₂
) color2
207 (let* ((kL (or kL
1))
210 (C₁
(sqrt (+ (expt a₁
2.0) (expt b₁
2.0))))
211 (C₂
(sqrt (+ (expt a₂
2.0) (expt b₂
2.0))))
212 (C̄
(/ (+ C₁ C₂
) 2.0))
213 (G (* 0.5 (- 1 (sqrt (/ (expt C̄
7.0) (+ (expt C̄
7.0) (expt 25 7.0)))))))
216 (C′₁
(sqrt (+ (expt a′₁
2.0) (expt b₁
2.0))))
217 (C′₂
(sqrt (+ (expt a′₂
2.0) (expt b₂
2.0))))
218 (h′₁
(if (and (= b₁
0) (= a′₁
0))
220 (let ((v (atan b₁ a′₁
)))
224 (h′₂
(if (and (= b₂
0) (= a′₂
0))
226 (let ((v (atan b₂ a′₂
)))
232 (Δh′
(cond ((= (* C′₁ C′₂
) 0)
234 ((<= (abs (- h′₂ h′₁
)) float-pi
)
236 ((> (- h′₂ h′₁
) float-pi
)
237 (- (- h′₂ h′₁
) (* 2 float-pi
)))
238 ((< (- h′₂ h′₁
) (- float-pi
))
239 (+ (- h′₂ h′₁
) (* 2 float-pi
)))))
240 (ΔH′
(* 2 (sqrt (* C′₁ C′₂
)) (sin (/ Δh′
2.0))))
241 (L̄′
(/ (+ L₁ L₂
) 2.0))
242 (C̄′
(/ (+ C′₁ C′₂
) 2.0))
243 (h̄′
(cond ((= (* C′₁ C′₂
) 0)
245 ((<= (abs (- h′₁ h′₂
)) float-pi
)
247 ((< (+ h′₁ h′₂
) (* 2 float-pi
))
248 (/ (+ h′₁ h′₂
(* 2 float-pi
)) 2.0))
249 ((>= (+ h′₁ h′₂
) (* 2 float-pi
))
250 (/ (+ h′₁ h′₂
(* -
2 float-pi
)) 2.0))))
252 (- (* 0.17 (cos (- h̄′
(degrees-to-radians 30)))))
253 (* 0.24 (cos (* h̄′
2)))
254 (* 0.32 (cos (+ (* h̄′
3) (degrees-to-radians 6))))
255 (- (* 0.20 (cos (- (* h̄′
4) (degrees-to-radians 63)))))))
256 (Δθ
(* (degrees-to-radians 30) (exp (- (expt (/ (- h̄′
(degrees-to-radians 275)) (degrees-to-radians 25)) 2.0)))))
257 (Rc (* 2 (sqrt (/ (expt C̄′
7.0) (+ (expt C̄′
7.0) (expt 25.0 7.0))))))
258 (Sl (+ 1 (/ (* 0.015 (expt (- L̄′
50) 2.0)) (sqrt (+ 20 (expt (- L̄′
50) 2.0))))))
259 (Sc (+ 1 (* C̄′
0.045)))
260 (Sh (+ 1 (* 0.015 C̄′ T
)))
261 (Rt (- (* (sin (* Δθ
2)) Rc
))))
262 (sqrt (+ (expt (/ ΔL′
(* Sl kL
)) 2.0)
263 (expt (/ ΔC′
(* Sc kC
)) 2.0)
264 (expt (/ ΔH′
(* Sh kH
)) 2.0)
265 (* Rt
(/ ΔC′
(* Sc kC
)) (/ ΔH′
(* Sh kH
)))))))))
269 ;;; color.el ends here