hexrgb.el 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732
  1. ;;; hexrgb.el --- Functions to manipulate colors, including RGB hex strings.
  2. ;;
  3. ;; Filename: hexrgb.el
  4. ;; Description: Functions to manipulate colors, including RGB hex strings.
  5. ;; Author: Drew Adams
  6. ;; Maintainer: Drew Adams
  7. ;; Copyright (C) 2004-2009, Drew Adams, all rights reserved.
  8. ;; Created: Mon Sep 20 22:58:45 2004
  9. ;; Version: 21.0
  10. ;; Last-Updated: Sat Nov 14 15:55:15 2009 (-0800)
  11. ;; By: dradams
  12. ;; Update #: 732
  13. ;; URL: http://www.emacswiki.org/cgi-bin/wiki/hexrgb.el
  14. ;; Keywords: number, hex, rgb, color, background, frames, display
  15. ;; Compatibility: GNU Emacs: 20.x, 21.x, 22.x, 23.x
  16. ;;
  17. ;; Features that might be required by this library:
  18. ;;
  19. ;; None
  20. ;;
  21. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  22. ;;
  23. ;;; Commentary:
  24. ;;
  25. ;; Functions to manipulate colors, including RGB hex strings.
  26. ;;
  27. ;; This library provides functions for converting between RGB (red,
  28. ;; green, blue) color components and HSV (hue, saturation, value)
  29. ;; color components. It helps you convert among Emacs color values
  30. ;; (whole numbers from 0 through 65535), RGB and HSV floating-point
  31. ;; components (0.0 through 1.0), Emacs color-name strings (such as
  32. ;; "blue"), and hex RGB color strings (such as "#FC43A7912").
  33. ;;
  34. ;; An RGB hex string, such as used as a frame `background-color'
  35. ;; property, is a string of 1 + (3 * n) characters, the first of
  36. ;; which is "#". The other characters are hexadecimal digits, in
  37. ;; three groups representing (from the left): red, green, and blue
  38. ;; hex codes.
  39. ;;
  40. ;; Constants defined here:
  41. ;;
  42. ;; `hexrgb-defined-colors', `hexrgb-defined-colors-alist',
  43. ;; `hexrgb-defined-colors-no-dups',
  44. ;; `hexrgb-defined-colors-no-dups-alist'.
  45. ;;
  46. ;; Options defined here:
  47. ;;
  48. ;; `hexrgb-canonicalize-defined-colors-flag'.
  49. ;;
  50. ;; Commands defined here:
  51. ;;
  52. ;; `hexrgb-blue', `hexrgb-complement', `hexrgb-green',
  53. ;; `hexrgb-hue', `hexrgb-read-color', `hexrgb-red',
  54. ;; `hexrgb-saturation', `hexrgb-value'.
  55. ;;
  56. ;; Non-interactive functions defined here:
  57. ;;
  58. ;; `hexrgb-approx-equal', `hexrgb-canonicalize-defined-colors',
  59. ;; `hexrgb-color-name-to-hex', `hexrgb-color-values-to-hex',
  60. ;; `hexrgb-color-value-to-float', `hexrgb-defined-colors',
  61. ;; `hexrgb-defined-colors-alist',
  62. ;; `hexrgb-delete-whitespace-from-string',
  63. ;; `hexrgb-float-to-color-value', `hexrgb-hex-char-to-integer',
  64. ;; `hexrgb-hex-to-color-values', `hexrgb-hex-to-hsv',
  65. ;; `hexrgb-hex-to-rgb', `hexrgb-hsv-to-hex', `hexrgb-hex-to-int',
  66. ;; `hexrgb-hsv-to-rgb', `hexrgb-increment-blue',
  67. ;; `hexrgb-increment-equal-rgb', `hexrgb-increment-green',
  68. ;; `hexrgb-increment-hex', `hexrgb-increment-red',
  69. ;; `hexrgb-int-to-hex', `hexrgb-rgb-hex-string-p',
  70. ;; `hexrgb-rgb-to-hex', `hexrgb-rgb-to-hsv'.
  71. ;;
  72. ;;
  73. ;; Add this to your initialization file (~/.emacs or ~/_emacs):
  74. ;;
  75. ;; (require 'hexrgb)
  76. ;;
  77. ;; Do not try to use this library without a window manager.
  78. ;; That is, do not use this with `emacs -nw'.
  79. ;;
  80. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  81. ;;
  82. ;;; Change log:
  83. ;;
  84. ;; 2009/11/14 dadams
  85. ;; hexrgb-rgb-to-hsv: Corrected hue when > 1.0. Use strict inequality for hue limit tests.
  86. ;; hexrgb-approx-equal: Convert RFUZZ and AFUZZ to their absolute values.
  87. ;; 2009/11/03 dadams
  88. ;; Added: hexrgb-delete-whitespace-from-string, hexrgb-canonicalize-defined-colors,
  89. ;; hexrgb-defined-colors(-no-dups)(-alist), hexrgb-canonicalize-defined-colors-flag.
  90. ;; hexrgb-read-color: Use function hexrgb-defined-colors-alist, not the constant.
  91. ;; 2008/12/25 dadams
  92. ;; hexrgb-rgb-to-hsv:
  93. ;; Replace (not (equal 0.0e+NaN saturation)) by standard test (= saturation saturation).
  94. ;; Thx to Michael Heerdegen for the bug report.
  95. ;; 2008-10-17 dadams
  96. ;; hexrgb-defined-colors(-alist): Prevent load-time error if user tries to use emacs -nw.
  97. ;; 2007/12/30 dadams
  98. ;; Added: hexrgb-hex-to-color-values.
  99. ;; 2007/10/20 dadams
  100. ;; hexrgb-read-color: Treat pseudo colors too (e.g. *point foreground*).
  101. ;; 2007/01/21 dadams
  102. ;; hexrgb-read-color: Error if empty string (and not allow-empty-name-p).
  103. ;; 2006/06/06 dadams
  104. ;; Added: hexrgb-defined-colors(-alist). Use instead of (x-defined-colors).
  105. ;; hexrgb-(red|green|blue): Added interactive specs.
  106. ;; 2006/06/04 dadams
  107. ;; hexrgb-read-color: Added optional arg allow-empty-name-p.
  108. ;; 2006/06/02 dadams
  109. ;; Added: hexrgb-rgb-hex-string-p. Used it.
  110. ;; 2006/05/30 dadams
  111. ;; Added: hexrgb-hex-to-(hsv|rgb), hexrgb-hsv-to-hex, hexrgb-color-name-to-hex,
  112. ;; hexrgb-complement, hexrgb-read-color, hexrgb-hue, hexrgb-saturation,
  113. ;; hexrgb-value, hexrgb-red, hexrgb-blue, hexrgb-green.
  114. ;; approx-equal: Add optional fuzz factor arguments. Changed the algorithm.
  115. ;; Renamed: approx-equal to hexrgb-approx-equal.
  116. ;; hexrgb-rgb-to-hsv: Changed test from < to <=: (when (<= hue 0.0)...).
  117. ;; hexrgb-hsv-to-rgb: Treat hue = 0.0 (int 0) the same as hue = 1.0 (int 6).
  118. ;; hexrgb-rgb-to-hex, hexrgb-increment-hex: Corrected doc strings.
  119. ;; 2006/05/22 dadams
  120. ;; Added: hexrgb-hsv-to-hex, hexrgb-rgb-to-hex. Require cl.el when byte-compile.
  121. ;; 2005/08/09 dadams
  122. ;; hexrgb-rgb-to-hsv: Side-stepped Emacs-20 bug in comparing NaN.
  123. ;; hexrgb-increment-*: Added optional arg wrap-p.
  124. ;; hexrgb-increment-hex: Prevent wrap if not wrap-p.
  125. ;; 2005/08/02 dadams
  126. ;; hexrgb-rgb-to-hes: Bug fix: If delta is zero, then so are hue and saturation.
  127. ;; 2005/06/24 dadams
  128. ;; hexrgb-rgb-to-hsv: Bug fix: test for NaN (e.g. on divide by zero).
  129. ;; 2005/02/08 dadams
  130. ;; hexrgb-hsv-to-rgb: Bug fix (typo: p, q -> pp, qq; added ww).
  131. ;; 2005/01/09 dadams
  132. ;; hexrgb-int-to-hex: Fixed bug in hexrgb-int-to-hex: nb-digits not respected.
  133. ;; Added: hexrgb-hsv-to-rgb, hexrgb-rgb-to-hsv, approx-equal.
  134. ;; Renamed old hexrgb-increment-value to hexrgb-increment-equal-rgb.
  135. ;; 2005/01/05 dadams
  136. ;; hexrgb-int-to-hex: Used a suggestion from Juri Linkov.
  137. ;;
  138. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  139. ;;
  140. ;; This program is free software; you can redistribute it and/or modify
  141. ;; it under the terms of the GNU General Public License as published by
  142. ;; the Free Software Foundation; either version 2, or (at your option)
  143. ;; any later version.
  144. ;; This program is distributed in the hope that it will be useful,
  145. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  146. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  147. ;; GNU General Public License for more details.
  148. ;; You should have received a copy of the GNU General Public License
  149. ;; along with this program; see the file COPYING. If not, write to
  150. ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  151. ;; Floor, Boston, MA 02110-1301, USA.
  152. ;;
  153. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  154. ;;
  155. ;;; Code:
  156. (eval-when-compile (require 'cl)) ;; case; plus, for Emacs < 20: when, unless
  157. ;; Unless you first load `hexrgb.el', then either `palette.el' or `eyedropper.el', you will get
  158. ;; warnings about variables and functions with prefix `eyedrop-' when you byte-compile
  159. ;; `hexrgb.el'. You can ignore these warnings.
  160. (defvar eyedrop-picked-foreground)
  161. (defvar eyedrop-picked-background)
  162. ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  163. ;;;###autoload
  164. (eval-and-compile
  165. (defun hexrgb-canonicalize-defined-colors (list)
  166. "Copy of LIST with color names canonicalized.
  167. LIST is a list of color names (strings).
  168. Canonical names are lowercase, with no whitespace.
  169. There are no duplicate names."
  170. (let ((tail list)
  171. this new)
  172. (while tail
  173. (setq this (car tail)
  174. this (hexrgb-delete-whitespace-from-string (downcase this) 0 (length this)))
  175. (unless (member this new) (push this new))
  176. (pop tail))
  177. (nreverse new)))
  178. (defun hexrgb-delete-whitespace-from-string (string &optional from to)
  179. "Remove whitespace from substring of STRING from FROM to TO.
  180. If FROM is nil, then start at the beginning of STRING (FROM = 0).
  181. If TO is nil, then end at the end of STRING (TO = length of STRING).
  182. FROM and TO are zero-based indexes into STRING.
  183. Character FROM is affected (possibly deleted). Character TO is not."
  184. (setq from (or from 0)
  185. to (or to (length string)))
  186. (with-temp-buffer
  187. (insert string)
  188. (goto-char (+ from (point-min)))
  189. (let ((count from)
  190. char)
  191. (while (and (not (eobp)) (< count to))
  192. (setq char (char-after))
  193. (if (memq char '(?\ ?\t ?\n)) (delete-char 1) (forward-char 1))
  194. (setq count (1+ count)))
  195. (buffer-string)))))
  196. ;;;###autoload
  197. (defconst hexrgb-defined-colors (eval-when-compile (and window-system (x-defined-colors)))
  198. "List of all supported colors.")
  199. ;;;###autoload
  200. (defconst hexrgb-defined-colors-no-dups
  201. (eval-when-compile
  202. (and window-system (hexrgb-canonicalize-defined-colors (x-defined-colors))))
  203. "List of all supported color names, with no duplicates.
  204. Names are all lowercase, without any spaces.")
  205. ;;;###autoload
  206. (defconst hexrgb-defined-colors-alist
  207. (eval-when-compile (and window-system (mapcar #'list (x-defined-colors))))
  208. "Alist of all supported color names, for use in completion.
  209. See also `hexrgb-defined-colors-no-dups-alist', which is the same
  210. thing, but without any duplicates, such as \"light blue\" and
  211. \"LightBlue\".")
  212. ;;;###autoload
  213. (defconst hexrgb-defined-colors-no-dups-alist
  214. (eval-when-compile
  215. (and window-system
  216. (mapcar #'list (hexrgb-canonicalize-defined-colors (x-defined-colors)))))
  217. "Alist of all supported color names, with no duplicates, for completion.
  218. Names are all lowercase, without any spaces.")
  219. ;;;###autoload
  220. (defcustom hexrgb-canonicalize-defined-colors-flag t
  221. "*Non-nil means remove duplicate color names.
  222. Names are considered duplicates if they are the same when abstracting
  223. from whitespace and letter case."
  224. :type 'boolean
  225. :group 'Icicles :group 'doremi-frame-commands :group 'faces :group 'convenience)
  226. ;; You should use these two functions, not the constants, so users can change
  227. ;; the behavior by customizing `hexrgb-canonicalize-defined-colors-flag'.
  228. (defun hexrgb-defined-colors ()
  229. "List of supported color names.
  230. If `hexrgb-canonicalize-defined-colors-flag' is non-nil, then names
  231. are lowercased, whitespace is removed, and there are no duplicates."
  232. (if hexrgb-canonicalize-defined-colors-flag
  233. hexrgb-defined-colors-no-dups
  234. hexrgb-defined-colors))
  235. (defun hexrgb-defined-colors-alist ()
  236. "Alist of supported color names. Usable for completion.
  237. If `hexrgb-canonicalize-defined-colors-flag' is non-nil, then names
  238. are lowercased, whitespace is removed, and there are no duplicates."
  239. (if hexrgb-canonicalize-defined-colors-flag
  240. hexrgb-defined-colors-no-dups-alist
  241. hexrgb-defined-colors-alist))
  242. ;; RMS added this function to Emacs (23) as `read-color', with some feature loss.
  243. ;;;###autoload
  244. (defun hexrgb-read-color (&optional convert-to-RGB-p allow-empty-name-p prompt)
  245. "Read a color name or RGB hex value: #RRRRGGGGBBBB.
  246. Completion is available for color names, but not for RGB hex strings.
  247. If you input an RGB hex string, it must have the form #XXXXXXXXXXXX or
  248. XXXXXXXXXXXX, where each X is a hex digit. The number of Xs must be a
  249. multiple of 3, with the same number of Xs for each of red, green, and
  250. blue. The order is red, green, blue.
  251. Color names that are normally considered equivalent are canonicalized:
  252. They are lowercased, whitespace is removed, and duplicates are
  253. eliminated. E.g. \"LightBlue\" and \"light blue\" are both replaced
  254. by \"lightblue\". If you do not want this behavior, but want to
  255. choose names that might contain whitespace or uppercase letters, then
  256. customize option `hexrgb-canonicalize-defined-colors-flag' to nil.
  257. In addition to standard color names and RGB hex values, the following
  258. are available as color candidates. In each case, the corresponding
  259. color is used.
  260. * `*copied foreground*' - last copied foreground, if available
  261. * `*copied background*' - last copied background, if available
  262. * `*mouse-2 foreground*' - foreground where you click `mouse-2'
  263. * `*mouse-2 background*' - background where you click `mouse-2'
  264. * `*point foreground*' - foreground under the cursor
  265. * `*point background*' - background under the cursor
  266. \(You can copy a color using eyedropper commands such as
  267. `eyedrop-pick-foreground-at-mouse'.)
  268. Checks input to be sure it represents a valid color. If not, raises
  269. an error (but see exception for empty input with non-nil
  270. ALLOW-EMPTY-NAME-P).
  271. Interactively, or with optional arg CONVERT-TO-RGB-P non-nil, converts
  272. an input color name to an RGB hex string. Returns the RGB hex string.
  273. Optional arg ALLOW-EMPTY-NAME-P controls what happens if you enter an
  274. empty color name (that is, you just hit `RET'). If non-nil, then
  275. `hexrgb-read-color' returns an empty color name, \"\". If nil, then
  276. it raises an error. Programs must test for \"\" if ALLOW-EMPTY-NAME-P
  277. is non-nil. They can then perform an appropriate action in case of
  278. empty input.
  279. Optional arg PROMPT is the prompt. Nil means use a default prompt."
  280. (interactive "p") ; Always convert to RGB interactively.
  281. (let* ((completion-ignore-case t)
  282. ;; Free variables here: `eyedrop-picked-foreground', `eyedrop-picked-background'.
  283. ;; They are defined in library `palette.el' or library `eyedropper.el'.
  284. (colors (if (fboundp 'eyedrop-foreground-at-point)
  285. (append (and eyedrop-picked-foreground
  286. '(("*copied foreground*")))
  287. (and eyedrop-picked-background
  288. '(("*copied background*")))
  289. '(("*mouse-2 foreground*")
  290. ("*mouse-2 background*")
  291. ("*point foreground*") ("*point background*"))
  292. (hexrgb-defined-colors-alist))
  293. (hexrgb-defined-colors-alist)))
  294. (color (completing-read (or prompt "Color (name or #R+G+B+): ")
  295. colors))
  296. hex-string)
  297. (when (fboundp 'eyedrop-foreground-at-point)
  298. (cond ((string= "*copied foreground*" color) (setq color eyedrop-picked-foreground))
  299. ((string= "*copied background*" color) (setq color eyedrop-picked-background))
  300. ((string= "*point foreground*" color) (setq color (eyedrop-foreground-at-point)))
  301. ((string= "*point background*" color) (setq color (eyedrop-background-at-point)))
  302. ((string= "*mouse-2 foreground*" color)
  303. (setq color (prog1 (eyedrop-foreground-at-mouse
  304. (read-event "Click `mouse-2' to choose foreground color - "))
  305. (read-event)))) ; Discard mouse up event.
  306. ((string= "*mouse-2 background*" color)
  307. (setq color (prog1 (eyedrop-background-at-mouse
  308. (read-event "Click `mouse-2' to choose background color - "))
  309. (read-event)))))) ; Discard mouse up event.
  310. (setq hex-string (or (string-match "^#\\([a-fA-F0-9][a-fA-F0-9][a-fA-F0-9]\\)+$" color)
  311. (and (string-match "^\\([a-fA-F0-9][a-fA-F0-9][a-fA-F0-9]\\)+$" color)
  312. t)))
  313. (if (and allow-empty-name-p (string= "" color))
  314. ""
  315. (when (and hex-string (not (eq 0 hex-string)))
  316. (setq color (concat "#" color))) ; No #; add it.
  317. (unless hex-string
  318. (when (or (string= "" color)
  319. (not (if (fboundp 'test-completion) ; Not defined in Emacs 20.
  320. (test-completion color colors)
  321. (try-completion color colors))))
  322. (error "No such color: %S" color))
  323. (when convert-to-RGB-p (setq color (hexrgb-color-name-to-hex color))))
  324. (when (interactive-p) (message "Color: `%s'" color))
  325. color)))
  326. ;;;###autoload
  327. (defun hexrgb-rgb-hex-string-p (color &optional laxp)
  328. "Non-nil if COLOR is an RGB string #XXXXXXXXXXXX.
  329. Each X is a hex digit. The number of Xs must be a multiple of 3, with
  330. the same number of Xs for each of red, green, and blue.
  331. Non-nil optional arg LAXP means that the initial `#' is optional. In
  332. that case, for a valid string of hex digits: when # is present 0 is
  333. returned; otherwise, t is returned."
  334. (or (string-match "^#\\([a-fA-F0-9][a-fA-F0-9][a-fA-F0-9]\\)+$" color)
  335. (and laxp (string-match "^\\([a-fA-F0-9][a-fA-F0-9][a-fA-F0-9]\\)+$" color) t)))
  336. ;;;###autoload
  337. (defun hexrgb-complement (color)
  338. "Return the color that is the complement of COLOR."
  339. (interactive (list (hexrgb-read-color)))
  340. (setq color (hexrgb-color-name-to-hex color))
  341. (let ((red (hexrgb-red color))
  342. (green (hexrgb-green color))
  343. (blue (hexrgb-blue color)))
  344. (setq color (hexrgb-rgb-to-hex (- 1.0 red) (- 1.0 green) (- 1.0 blue))))
  345. (when (interactive-p) (message "Complement: `%s'" color))
  346. color)
  347. ;;;###autoload
  348. (defun hexrgb-hue (color)
  349. "Return the hue component of COLOR, in range 0 to 1 inclusive.
  350. COLOR is a color name or hex RGB string that starts with \"#\"."
  351. (interactive (list (hexrgb-read-color)))
  352. (setq color (hexrgb-color-name-to-hex color))
  353. (car (hexrgb-rgb-to-hsv (hexrgb-red color) (hexrgb-green color) (hexrgb-blue color))))
  354. ;;;###autoload
  355. (defun hexrgb-saturation (color)
  356. "Return the saturation component of COLOR, in range 0 to 1 inclusive.
  357. COLOR is a color name or hex RGB string that starts with \"#\"."
  358. (interactive (list (hexrgb-read-color)))
  359. (setq color (hexrgb-color-name-to-hex color))
  360. (cadr (hexrgb-rgb-to-hsv (hexrgb-red color) (hexrgb-green color) (hexrgb-blue color))))
  361. ;;;###autoload
  362. (defun hexrgb-value (color)
  363. "Return the value component of COLOR, in range 0 to 1 inclusive.
  364. COLOR is a color name or hex RGB string that starts with \"#\"."
  365. (interactive (list (hexrgb-read-color)))
  366. (setq color (hexrgb-color-name-to-hex color))
  367. (caddr (hexrgb-rgb-to-hsv (hexrgb-red color) (hexrgb-green color) (hexrgb-blue color))))
  368. ;;;###autoload
  369. (defun hexrgb-red (color)
  370. "Return the red component of COLOR, in range 0 to 1 inclusive.
  371. COLOR is a color name or hex RGB string that starts with \"#\"."
  372. (interactive (list (hexrgb-read-color)))
  373. (setq color (hexrgb-color-name-to-hex color))
  374. (/ (hexrgb-hex-to-int (substring color 1 (1+ (/ (1- (length color)) 3))))
  375. (expt 16.0 (/ (1- (length color)) 3.0))))
  376. ;;;###autoload
  377. (defun hexrgb-green (color)
  378. "Return the green component of COLOR, in range 0 to 1 inclusive.
  379. COLOR is a color name or hex RGB string that starts with \"#\"."
  380. (interactive (list (hexrgb-read-color)))
  381. (setq color (hexrgb-color-name-to-hex color))
  382. (let* ((len (/ (1- (length color)) 3))
  383. (start (1+ len)))
  384. (/ (hexrgb-hex-to-int (substring color start (+ start len)))
  385. (expt 16.0 (/ (1- (length color)) 3.0)))))
  386. ;;;###autoload
  387. (defun hexrgb-blue (color)
  388. "Return the blue component of COLOR, in range 0 to 1 inclusive.
  389. COLOR is a color name or hex RGB string that starts with \"#\"."
  390. (interactive (list (hexrgb-read-color)))
  391. (setq color (hexrgb-color-name-to-hex color))
  392. (let* ((len (/ (1- (length color)) 3))
  393. (start (+ 1 len len)))
  394. (/ (hexrgb-hex-to-int (substring color start (+ start len)))
  395. (expt 16.0 (/ (1- (length color)) 3.0)))))
  396. ;;;###autoload
  397. (defun hexrgb-rgb-to-hsv (red green blue)
  398. "Convert RED, GREEN, BLUE components to HSV (hue, saturation, value).
  399. Each input component is 0.0 to 1.0, inclusive.
  400. Returns a list of HSV components of value 0.0 to 1.0, inclusive."
  401. (let* ((min (min red green blue))
  402. (max (max red green blue))
  403. (value max)
  404. (delta (- max min))
  405. hue saturation)
  406. (if (hexrgb-approx-equal 0.0 delta)
  407. (setq hue 0.0
  408. saturation 0.0) ; Gray scale - no color; only value.
  409. (if (and (condition-case nil
  410. (setq saturation (/ delta max))
  411. (arith-error nil))
  412. ;; Must be a number, not a NaN. The standard test for a NaN is (not (= N N)),
  413. ;; but an Emacs 20 bug makes (= N N) return t for a NaN also.
  414. (or (< emacs-major-version 21) (= saturation saturation)))
  415. (if (hexrgb-approx-equal 0.0 saturation)
  416. (setq hue 0.0
  417. saturation 0.0) ; Again, no color; only value.
  418. ;; Color
  419. (setq hue (if (hexrgb-approx-equal red max)
  420. (/ (- green blue) delta) ; Between yellow & magenta.
  421. (if (hexrgb-approx-equal green max)
  422. (+ 2.0 (/ (- blue red) delta)) ; Between cyan & yellow.
  423. (+ 4.0 (/ (- red green) delta)))) ; Between magenta & cyan.
  424. hue (/ hue 6.0))
  425. ;; (when (<= hue 0.0) (setq hue (+ hue 1.0))) ; $$$$$$
  426. ;; (when (>= hue 1.0) (setq hue (- hue 1.0)))) ; $$$$$$
  427. (when (< hue 0.0) (setq hue (+ hue 1.0)))
  428. (when (> hue 1.0) (setq hue (- hue 1.0))))
  429. (setq hue 0.0 ; Div by zero (max=0): H:=0, S:=0. (Hue undefined.)
  430. saturation 0.0)))
  431. (list hue saturation value)))
  432. ;;;###autoload
  433. (defun hexrgb-hsv-to-rgb (hue saturation value)
  434. "Convert HUE, SATURATION, VALUE components to RGB (red, green, blue).
  435. Each input component is 0.0 to 1.0, inclusive.
  436. Returns a list of RGB components of value 0.0 to 1.0, inclusive."
  437. (let (red green blue int-hue fract pp qq tt ww)
  438. (if (hexrgb-approx-equal 0.0 saturation)
  439. (setq red value
  440. green value
  441. blue value) ; Gray
  442. (setq hue (* hue 6.0) ; Sectors: 0 to 5
  443. int-hue (floor hue)
  444. fract (- hue int-hue)
  445. pp (* value (- 1 saturation))
  446. qq (* value (- 1 (* saturation fract)))
  447. ww (* value (- 1 (* saturation (- 1 (- hue int-hue))))))
  448. (case int-hue
  449. ((0 6) (setq red value
  450. green ww
  451. blue pp))
  452. (1 (setq red qq
  453. green value
  454. blue pp))
  455. (2 (setq red pp
  456. green value
  457. blue ww))
  458. (3 (setq red pp
  459. green qq
  460. blue value))
  461. (4 (setq red ww
  462. green pp
  463. blue value))
  464. (otherwise (setq red value
  465. green pp
  466. blue qq))))
  467. (list red green blue)))
  468. ;;;###autoload
  469. (defun hexrgb-hsv-to-hex (hue saturation value)
  470. "Return the hex RBG color string for inputs HUE, SATURATION, VALUE.
  471. The inputs are each in the range 0 to 1.
  472. The output string is of the form \"#RRRRGGGGBBBB\"."
  473. (hexrgb-color-values-to-hex
  474. (mapcar (lambda (x) (floor (* x 65535.0))) (hexrgb-hsv-to-rgb hue saturation value))))
  475. ;;;###autoload
  476. (defun hexrgb-rgb-to-hex (red green blue)
  477. "Return the hex RBG color string for inputs RED, GREEN, BLUE.
  478. The inputs are each in the range 0 to 1.
  479. The output string is of the form \"#RRRRGGGGBBBB\"."
  480. (hexrgb-color-values-to-hex
  481. (mapcar (lambda (x) (floor (* x 65535.0))) (list red green blue))))
  482. ;;;###autoload
  483. (defun hexrgb-hex-to-hsv (color)
  484. "Return a list of HSV (hue, saturation, value) color components.
  485. Each component is a value from 0.0 to 1.0, inclusive.
  486. COLOR is a color name or a hex RGB string that starts with \"#\" and
  487. is followed by an equal number of hex digits for red, green, and blue
  488. components."
  489. (let ((rgb-components (hexrgb-hex-to-rgb color)))
  490. (apply #'hexrgb-rgb-to-hsv rgb-components)))
  491. ;;;###autoload
  492. (defun hexrgb-hex-to-rgb (color)
  493. "Return a list of RGB (red, green, blue) color components.
  494. Each component is a value from 0.0 to 1.0, inclusive.
  495. COLOR is a color name or a hex RGB string that starts with \"#\" and
  496. is followed by an equal number of hex digits for red, green, and blue
  497. components."
  498. (unless (hexrgb-rgb-hex-string-p color) (setq color (hexrgb-color-name-to-hex color)))
  499. (let ((len (/ (1- (length color)) 3)))
  500. (list (/ (hexrgb-hex-to-int (substring color 1 (1+ len))) 65535.0)
  501. (/ (hexrgb-hex-to-int (substring color (1+ len) (+ 1 len len))) 65535.0)
  502. (/ (hexrgb-hex-to-int (substring color (+ 1 len len))) 65535.0))))
  503. ;;;###autoload
  504. (defun hexrgb-color-name-to-hex (color)
  505. "Return the RGB hex string for the COLOR name, starting with \"#\".
  506. If COLOR is already a string starting with \"#\", then just return it."
  507. (let ((components (x-color-values color)))
  508. (unless components (error "No such color: %S" color))
  509. (unless (hexrgb-rgb-hex-string-p color)
  510. (setq color (hexrgb-color-values-to-hex components))))
  511. color)
  512. ;; Just hard-code 4 as the number of hex digits, since `x-color-values'
  513. ;; seems to produce appropriate integer values for this value.
  514. ;;
  515. ;; Color "components" would be better in the name than color "value"
  516. ;; but this name follows the Emacs tradition (e.g. `x-color-values',
  517. ;; 'ps-color-values', `ps-e-x-color-values').
  518. ;;;###autoload
  519. (defun hexrgb-color-values-to-hex (values)
  520. "Convert list of rgb color VALUES to a hex string, #XXXXXXXXXXXX.
  521. Each X in the string is a hexadecimal digit.
  522. Input VALUES is as for the output of `x-color-values'."
  523. (concat "#" (hexrgb-int-to-hex (nth 0 values) 4) ; red
  524. (hexrgb-int-to-hex (nth 1 values) 4) ; green
  525. (hexrgb-int-to-hex (nth 2 values) 4))) ; blue
  526. ;;;###autoload
  527. (defun hexrgb-hex-to-color-values (color)
  528. "Convert hex COLOR to a list of rgb color values.
  529. COLOR is a hex rgb color string, #XXXXXXXXXXXX
  530. Each X in the string is a hexadecimal digit. There are 3N X's, N > 0.
  531. The output list is as for `x-color-values'."
  532. (let* ((hex-strgp (string-match
  533. "^\\(#\\)?\\(\\([a-fA-F0-9][a-fA-F0-9][a-fA-F0-9]\\)+\\)$"
  534. color))
  535. (ndigits (/ (if (eq (match-beginning 1) (match-end 1))
  536. (length color)
  537. (1- (length color)))
  538. 3))
  539. red green blue)
  540. (unless hex-strgp (error "Invalid RGB color string: %s" color))
  541. (setq color (substring color (match-beginning 2) (match-end 2))
  542. red (hexrgb-hex-to-int (substring color 0 ndigits))
  543. green (hexrgb-hex-to-int (substring color ndigits (* 2 ndigits)))
  544. blue (hexrgb-hex-to-int (substring color ndigits (* 3 ndigits))))
  545. (list red green blue)))
  546. ;;;###autoload
  547. (defun hexrgb-increment-red (hex nb-digits increment &optional wrap-p)
  548. "Increment red value of rgb string HEX by INCREMENT.
  549. String HEX starts with \"#\". Each color is NB-DIGITS hex digits long.
  550. If optional arg WRAP-P is non-nil, then the result wraps around zero.
  551. For example, incrementing \"#FFFFFFFFF\" by 1 will cause it to wrap
  552. around to \"#000000000\"."
  553. (concat "#"
  554. (hexrgb-increment-hex (substring hex 1 (1+ nb-digits)) increment nb-digits wrap-p)
  555. (substring hex (1+ nb-digits) (1+ (* nb-digits 2)))
  556. (substring hex (1+ (* nb-digits 2)))))
  557. ;;;###autoload
  558. (defun hexrgb-increment-green (hex nb-digits increment &optional wrap-p)
  559. "Increment green value of rgb string HEX by INCREMENT.
  560. String HEX starts with \"#\". Each color is NB-DIGITS hex digits long.
  561. For example, incrementing \"#FFFFFFFFF\" by 1 will cause it to wrap
  562. around to \"#000000000\"."
  563. (concat
  564. "#" (substring hex 1 (1+ nb-digits))
  565. (hexrgb-increment-hex (substring hex (1+ nb-digits) (1+ (* nb-digits 2)))
  566. increment
  567. nb-digits
  568. wrap-p)
  569. (substring hex (1+ (* nb-digits 2)))))
  570. ;;;###autoload
  571. (defun hexrgb-increment-blue (hex nb-digits increment &optional wrap-p)
  572. "Increment blue value of rgb string HEX by INCREMENT.
  573. String HEX starts with \"#\". Each color is NB-DIGITS hex digits long.
  574. For example, incrementing \"#FFFFFFFFF\" by 1 will cause it to wrap
  575. around to \"#000000000\"."
  576. (concat "#" (substring hex 1 (1+ (* nb-digits 2)))
  577. (hexrgb-increment-hex (substring hex (1+ (* nb-digits 2)))
  578. increment
  579. nb-digits
  580. wrap-p)))
  581. ;;;###autoload
  582. (defun hexrgb-increment-equal-rgb (hex nb-digits increment &optional wrap-p)
  583. "Increment each color value (r,g,b) of rgb string HEX by INCREMENT.
  584. String HEX starts with \"#\". Each color is NB-DIGITS hex digits long.
  585. For example, incrementing \"#FFFFFFFFF\" by 1 will cause it to wrap
  586. around to \"#000000000\"."
  587. (concat
  588. "#" (hexrgb-increment-hex (substring hex 1 (1+ nb-digits)) increment nb-digits wrap-p)
  589. (hexrgb-increment-hex (substring hex (1+ nb-digits) (1+ (* nb-digits 2)))
  590. increment
  591. nb-digits
  592. wrap-p)
  593. (hexrgb-increment-hex (substring hex (1+ (* nb-digits 2))) increment nb-digits wrap-p)))
  594. ;;;###autoload
  595. (defun hexrgb-increment-hex (hex increment nb-digits &optional wrap-p)
  596. "Increment HEX number (a string NB-DIGITS long) by INCREMENT.
  597. For example, incrementing \"FFFFFFFFF\" by 1 will cause it to wrap
  598. around to \"000000000\"."
  599. (let* ((int (hexrgb-hex-to-int hex))
  600. (new-int (+ increment int)))
  601. (if (or wrap-p
  602. (and (>= int 0) ; Not too large for the machine.
  603. (>= new-int 0) ; For the case where increment < 0.
  604. (<= (length (format (concat "%X") new-int)) nb-digits))) ; Not too long.
  605. (hexrgb-int-to-hex new-int nb-digits) ; Use incremented number.
  606. hex))) ; Don't increment.
  607. ;;;###autoload
  608. (defun hexrgb-hex-to-int (hex)
  609. "Convert HEX string argument to an integer.
  610. The characters of HEX must be hex characters."
  611. (let* ((factor 1)
  612. (len (length hex))
  613. (indx (1- len))
  614. (int 0))
  615. (while (>= indx 0)
  616. (setq int (+ int (* factor (hexrgb-hex-char-to-integer (aref hex indx))))
  617. indx (1- indx)
  618. factor (* 16 factor)))
  619. int))
  620. ;; From `hexl.el'. This is the same as `hexl-hex-char-to-integer' defined there.
  621. ;;;###autoload
  622. (defun hexrgb-hex-char-to-integer (character)
  623. "Take a CHARACTER and return its value as if it were a hex digit."
  624. (if (and (>= character ?0) (<= character ?9))
  625. (- character ?0)
  626. (let ((ch (logior character 32)))
  627. (if (and (>= ch ?a) (<= ch ?f))
  628. (- ch (- ?a 10))
  629. (error "Invalid hex digit `%c'" ch)))))
  630. ;; Originally, I used the code from `int-to-hex-string' in `float.el'.
  631. ;; This version is thanks to Juri Linkov <juri@jurta.org>.
  632. ;;
  633. ;;;###autoload
  634. (defun hexrgb-int-to-hex (int &optional nb-digits)
  635. "Convert integer argument INT to a #XXXXXXXXXXXX format hex string.
  636. Each X in the output string is a hexadecimal digit.
  637. NB-DIGITS is the number of hex digits. If INT is too large to be
  638. represented with NB-DIGITS, then the result is truncated from the
  639. left. So, for example, INT=256 and NB-DIGITS=2 returns \"00\", since
  640. the hex equivalent of 256 decimal is 100, which is more than 2 digits."
  641. (setq nb-digits (or nb-digits 4))
  642. (substring (format (concat "%0" (int-to-string nb-digits) "X") int) (- nb-digits)))
  643. ;; Inspired by Elisp Info manual, node "Comparison of Numbers".
  644. ;;;###autoload
  645. (defun hexrgb-approx-equal (x y &optional rfuzz afuzz)
  646. "Return non-nil if numbers X and Y are approximately equal.
  647. RFUZZ is a relative fuzz factor. AFUZZ is an absolute fuzz factor.
  648. RFUZZ defaults to 1.0e-8. AFUZZ defaults to (/ RFUZZ 10).
  649. RFUZZ and AFUZZ are converted to their absolute values.
  650. The algorithm is:
  651. (< (abs (- X Y)) (+ AFUZZ (* RFUZZ (+ (abs X) (abs Y)))))."
  652. (setq rfuzz (or rfuzz 1.0e-8)
  653. rfuzz (abs rfuzz)
  654. afuzz (or afuzz (/ rfuzz 10))
  655. afuzz (abs afuzz))
  656. (< (abs (- x y)) (+ afuzz (* rfuzz (+ (abs x) (abs y))))))
  657. ;;;###autoload
  658. (defun hexrgb-color-value-to-float (n)
  659. "Return the floating-point equivalent of color value N.
  660. N must be an integer between 0 and 65535, or else an error is raised."
  661. (unless (and (wholenump n) (<= n 65535))
  662. (error "Not a whole number less than 65536"))
  663. (/ (float n) 65535.0))
  664. ;;;###autoload
  665. (defun hexrgb-float-to-color-value (x)
  666. "Return the color value equivalent of floating-point number X.
  667. X must be between 0.0 and 1.0, or else an error is raised."
  668. (unless (and (numberp x) (<= 0.0 x) (<= x 1.0))
  669. (error "Not a floating-point number between 0.0 and 1.0"))
  670. (floor (* x 65535.0)))
  671. ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  672. (provide 'hexrgb)
  673. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  674. ;;; hexrgb.el ends here