PageRenderTime 42ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/grapefruit.py

http://grapefruit.googlecode.com/
Python | 1973 lines | 1719 code | 55 blank | 199 comment | 43 complexity | e871a4cd88b7c280d3de5fe27eef8604 MD5 | raw file
Possible License(s): Apache-2.0
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-#
  3. # Copyright (c) 2008, Xavier Basty
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. '''GrapeFruit - Color manipulation in Python'''
  17. # $Id: grapefruit.py 31 2008-06-15 10:48:06Z xbasty $
  18. __author__ = 'Xavier Basty <xbasty@gmail.com>'
  19. __version__ = '0.1a3'
  20. # The default white reference, use 2° Standard Observer, D65 (daylight)
  21. _DEFAULT_WREF = (0.95043, 1.00000, 1.08890)
  22. _oneThird = 1.0 / 3
  23. _srgbGammaCorrInv = 0.03928 / 12.92
  24. _sixteenHundredsixteenth = 16.0 / 116
  25. _RybWheel = (
  26. 0, 26, 52,
  27. 83, 120, 130,
  28. 141, 151, 162,
  29. 177, 190, 204,
  30. 218, 232, 246,
  31. 261, 275, 288,
  32. 303, 317, 330,
  33. 338, 345, 352,
  34. 360)
  35. _RgbWheel = (
  36. 0, 8, 17,
  37. 26, 34, 41,
  38. 48, 54, 60,
  39. 81, 103, 123,
  40. 138, 155, 171,
  41. 187, 204, 219,
  42. 234, 251, 267,
  43. 282, 298, 329,
  44. 360)
  45. class Color:
  46. '''Hold a color value.
  47. Example usage:
  48. To create an instance of the grapefruit.Color from RGB values:
  49. >>> import grapefruit
  50. >>> r, g, b = 1, 0.5, 0
  51. >>> col = grapefruit.Color.NewFromRgb(r, g, b)
  52. To get the values of the color in another colorspace:
  53. >>> h, s, v = col.hsv
  54. >>> l, a, b = col.lab
  55. To get the complementary of a color:
  56. >>> compl = col.ComplementaryColor()
  57. >>> print compl.hsl
  58. (210.0, 1.0, 0.5)
  59. To directly convert RGB values to their HSL equivalent:
  60. >>> h, s, l = Color.RgbToHsl(r, g, b)
  61. '''
  62. WHITE_REFERENCE = {
  63. 'std_A' : (1.09847, 1.00000, 0.35582),
  64. 'std_B' : (0.99093, 1.00000, 0.85313),
  65. 'std_C' : (0.98071, 1.00000, 1.18225),
  66. 'std_D50' : (0.96421, 1.00000, 0.82519),
  67. 'std_D55' : (0.95680, 1.00000, 0.92148),
  68. 'std_D65' : (0.95043, 1.00000, 1.08890),
  69. 'std_D75' : (0.94972, 1.00000, 1.22639),
  70. 'std_E' : (1.00000, 1.00000, 1.00000),
  71. 'std_F1' : (0.92834, 1.00000, 1.03665),
  72. 'std_F2' : (0.99145, 1.00000, 0.67316),
  73. 'std_F3' : (1.03753, 1.00000, 0.49861),
  74. 'std_F4' : (1.09147, 1.00000, 0.38813),
  75. 'std_F5' : (0.90872, 1.00000, 0.98723),
  76. 'std_F6' : (0.97309, 1.00000, 0.60191),
  77. 'std_F7' : (0.95017, 1.00000, 1.08630),
  78. 'std_F8' : (0.96413, 1.00000, 0.82333),
  79. 'std_F9' : (1.00365, 1.00000, 0.67868),
  80. 'std_F10' : (0.96174, 1.00000, 0.81712),
  81. 'std_F11' : (1.00899, 1.00000, 0.64262),
  82. 'std_F12' : (1.08046, 1.00000, 0.39228),
  83. 'sup_A' : (1.11142, 1.00000, 0.35200),
  84. 'sup_B' : (0.99178, 1.00000, 0.84349),
  85. 'sup_C' : (0.97286, 1.00000, 1.16145),
  86. 'sup_D50' : (0.96721, 1.00000, 0.81428),
  87. 'sup_D55' : (0.95797, 1.00000, 0.90925),
  88. 'sup_D65' : (0.94810, 1.00000, 1.07305),
  89. 'sup_D75' : (0.94417, 1.00000, 1.20643),
  90. 'sup_E' : (1.00000, 1.00000, 1.00000),
  91. 'sup_F1' : (0.94791, 1.00000, 1.03191),
  92. 'sup_F2' : (1.03245, 1.00000, 0.68990),
  93. 'sup_F3' : (1.08968, 1.00000, 0.51965),
  94. 'sup_F4' : (1.14961, 1.00000, 0.40963),
  95. 'sup_F5' : (0.93369, 1.00000, 0.98636),
  96. 'sup_F6' : (1.02148, 1.00000, 0.62074),
  97. 'sup_F7' : (0.95780, 1.00000, 1.07618),
  98. 'sup_F8' : (0.97115, 1.00000, 0.81135),
  99. 'sup_F9' : (1.02116, 1.00000, 0.67826),
  100. 'sup_F10' : (0.99001, 1.00000, 0.83134),
  101. 'sup_F11' : (1.03820, 1.00000, 0.65555),
  102. 'sup_F12' : (1.11428, 1.00000, 0.40353)}
  103. NAMED_COLOR = {
  104. 'aliceblue': '#f0f8ff',
  105. 'antiquewhite': '#faebd7',
  106. 'aqua': '#00ffff',
  107. 'aquamarine': '#7fffd4',
  108. 'azure': '#f0ffff',
  109. 'beige': '#f5f5dc',
  110. 'bisque': '#ffe4c4',
  111. 'black': '#000000',
  112. 'blanchedalmond': '#ffebcd',
  113. 'blue': '#0000ff',
  114. 'blueviolet': '#8a2be2',
  115. 'brown': '#a52a2a',
  116. 'burlywood': '#deb887',
  117. 'cadetblue': '#5f9ea0',
  118. 'chartreuse': '#7fff00',
  119. 'chocolate': '#d2691e',
  120. 'coral': '#ff7f50',
  121. 'cornflowerblue': '#6495ed',
  122. 'cornsilk': '#fff8dc',
  123. 'crimson': '#dc143c',
  124. 'cyan': '#00ffff',
  125. 'darkblue': '#00008b',
  126. 'darkcyan': '#008b8b',
  127. 'darkgoldenrod': '#b8860b',
  128. 'darkgray': '#a9a9a9',
  129. 'darkgrey': '#a9a9a9',
  130. 'darkgreen': '#006400',
  131. 'darkkhaki': '#bdb76b',
  132. 'darkmagenta': '#8b008b',
  133. 'darkolivegreen': '#556b2f',
  134. 'darkorange': '#ff8c00',
  135. 'darkorchid': '#9932cc',
  136. 'darkred': '#8b0000',
  137. 'darksalmon': '#e9967a',
  138. 'darkseagreen': '#8fbc8f',
  139. 'darkslateblue': '#483d8b',
  140. 'darkslategray': '#2f4f4f',
  141. 'darkslategrey': '#2f4f4f',
  142. 'darkturquoise': '#00ced1',
  143. 'darkviolet': '#9400d3',
  144. 'deeppink': '#ff1493',
  145. 'deepskyblue': '#00bfff',
  146. 'dimgray': '#696969',
  147. 'dimgrey': '#696969',
  148. 'dodgerblue': '#1e90ff',
  149. 'firebrick': '#b22222',
  150. 'floralwhite': '#fffaf0',
  151. 'forestgreen': '#228b22',
  152. 'fuchsia': '#ff00ff',
  153. 'gainsboro': '#dcdcdc',
  154. 'ghostwhite': '#f8f8ff',
  155. 'gold': '#ffd700',
  156. 'goldenrod': '#daa520',
  157. 'gray': '#808080',
  158. 'grey': '#808080',
  159. 'green': '#008000',
  160. 'greenyellow': '#adff2f',
  161. 'honeydew': '#f0fff0',
  162. 'hotpink': '#ff69b4',
  163. 'indianred': '#cd5c5c',
  164. 'indigo': '#4b0082',
  165. 'ivory': '#fffff0',
  166. 'khaki': '#f0e68c',
  167. 'lavender': '#e6e6fa',
  168. 'lavenderblush': '#fff0f5',
  169. 'lawngreen': '#7cfc00',
  170. 'lemonchiffon': '#fffacd',
  171. 'lightblue': '#add8e6',
  172. 'lightcoral': '#f08080',
  173. 'lightcyan': '#e0ffff',
  174. 'lightgoldenrodyellow': '#fafad2',
  175. 'lightgreen': '#90ee90',
  176. 'lightgray': '#d3d3d3',
  177. 'lightgrey': '#d3d3d3',
  178. 'lightpink': '#ffb6c1',
  179. 'lightsalmon': '#ffa07a',
  180. 'lightseagreen': '#20b2aa',
  181. 'lightskyblue': '#87cefa',
  182. 'lightslategray': '#778899',
  183. 'lightslategrey': '#778899',
  184. 'lightsteelblue': '#b0c4de',
  185. 'lightyellow': '#ffffe0',
  186. 'lime': '#00ff00',
  187. 'limegreen': '#32cd32',
  188. 'linen': '#faf0e6',
  189. 'magenta': '#ff00ff',
  190. 'maroon': '#800000',
  191. 'mediumaquamarine': '#66cdaa',
  192. 'mediumblue': '#0000cd',
  193. 'mediumorchid': '#ba55d3',
  194. 'mediumpurple': '#9370db',
  195. 'mediumseagreen': '#3cb371',
  196. 'mediumslateblue': '#7b68ee',
  197. 'mediumspringgreen': '#00fa9a',
  198. 'mediumturquoise': '#48d1cc',
  199. 'mediumvioletred': '#c71585',
  200. 'midnightblue': '#191970',
  201. 'mintcream': '#f5fffa',
  202. 'mistyrose': '#ffe4e1',
  203. 'moccasin': '#ffe4b5',
  204. 'navajowhite': '#ffdead',
  205. 'navy': '#000080',
  206. 'oldlace': '#fdf5e6',
  207. 'olive': '#808000',
  208. 'olivedrab': '#6b8e23',
  209. 'orange': '#ffa500',
  210. 'orangered': '#ff4500',
  211. 'orchid': '#da70d6',
  212. 'palegoldenrod': '#eee8aa',
  213. 'palegreen': '#98fb98',
  214. 'paleturquoise': '#afeeee',
  215. 'palevioletred': '#db7093',
  216. 'papayawhip': '#ffefd5',
  217. 'peachpuff': '#ffdab9',
  218. 'peru': '#cd853f',
  219. 'pink': '#ffc0cb',
  220. 'plum': '#dda0dd',
  221. 'powderblue': '#b0e0e6',
  222. 'purple': '#800080',
  223. 'red': '#ff0000',
  224. 'rosybrown': '#bc8f8f',
  225. 'royalblue': '#4169e1',
  226. 'saddlebrown': '#8b4513',
  227. 'salmon': '#fa8072',
  228. 'sandybrown': '#f4a460',
  229. 'seagreen': '#2e8b57',
  230. 'seashell': '#fff5ee',
  231. 'sienna': '#a0522d',
  232. 'silver': '#c0c0c0',
  233. 'skyblue': '#87ceeb',
  234. 'slateblue': '#6a5acd',
  235. 'slategray': '#708090',
  236. 'slategrey': '#708090',
  237. 'snow': '#fffafa',
  238. 'springgreen': '#00ff7f',
  239. 'steelblue': '#4682b4',
  240. 'tan': '#d2b48c',
  241. 'teal': '#008080',
  242. 'thistle': '#d8bfd8',
  243. 'tomato': '#ff6347',
  244. 'turquoise': '#40e0d0',
  245. 'violet': '#ee82ee',
  246. 'wheat': '#f5deb3',
  247. 'white': '#ffffff',
  248. 'whitesmoke': '#f5f5f5',
  249. 'yellow': '#ffff00',
  250. 'yellowgreen': '#9acd32'}
  251. def __init__(self, values, mode='rgb', alpha=1.0, wref=_DEFAULT_WREF):
  252. '''Instantiate a new grapefruit.Color object.
  253. Parameters:
  254. :values:
  255. The values of this color, in the specified representation.
  256. :mode:
  257. The representation mode used for values.
  258. :alpha:
  259. the alpha value (transparency) of this color.
  260. :wref:
  261. The whitepoint reference, default is 2° D65.
  262. '''
  263. if not(isinstance(values, tuple)):
  264. raise TypeError, 'values must be a tuple'
  265. if mode=='rgb':
  266. self.__rgb = values
  267. self.__hsl = Color.RgbToHsl(*values)
  268. elif mode=='hsl':
  269. self.__hsl = values
  270. self.__rgb = Color.HslToRgb(*values)
  271. else:
  272. raise ValueError('Invalid color mode: ' + mode)
  273. self.__a = alpha
  274. self.__wref = wref
  275. def __ne__(self, other):
  276. return not self.__eq__(other)
  277. def __eq__(self, other):
  278. try:
  279. if isinstance(other, Color):
  280. return (self.__rgb==other.__rgb) and (self.__a==other.__a)
  281. if len(other) != 4:
  282. return False
  283. rgba = self.__rgb + (self.__a,)
  284. return reduce(lambda x, y: x and (y[0]==y[1]), zip(rgba, other), True)
  285. except TypeError:
  286. return False
  287. except AttributeError:
  288. return False
  289. def __repr__(self):
  290. return str(self.__rgb + (self.__a,))
  291. def __str__(self):
  292. '''A string representation of this grapefruit.Color instance.
  293. Returns:
  294. The RGBA representation of this grapefruit.Color instance.
  295. '''
  296. return '(%g, %g, %g, %g)' % (self.__rgb + (self.__a,))
  297. def __unicode__(self):
  298. '''A unicode string representation of this grapefruit.Color instance.
  299. Returns:
  300. The RGBA representation of this grapefruit.Color instance.
  301. '''
  302. return u'(%g, %g, %g, %g)' % (self.__rgb + (self.__a,))
  303. def __iter__(self):
  304. return iter(self.__rgb + (self.__a,))
  305. def __len__(self):
  306. return 4
  307. @staticmethod
  308. def RgbToHsl(r, g, b):
  309. '''Convert the color from RGB coordinates to HSL.
  310. Parameters:
  311. :r:
  312. The Red component value [0...1]
  313. :g:
  314. The Green component value [0...1]
  315. :b:
  316. The Blue component value [0...1]
  317. Returns:
  318. The color as an (h, s, l) tuple in the range:
  319. h[0...360],
  320. s[0...1],
  321. l[0...1]
  322. >>> Color.RgbToHsl(1, 0.5, 0)
  323. (30.0, 1.0, 0.5)
  324. '''
  325. minVal = min(r, g, b) # min RGB value
  326. maxVal = max(r, g, b) # max RGB value
  327. l = (maxVal + minVal) / 2.0
  328. if minVal==maxVal:
  329. return (0.0, 0.0, l) # achromatic (gray)
  330. d = maxVal - minVal # delta RGB value
  331. if l < 0.5: s = d / (maxVal + minVal)
  332. else: s = d / (2.0 - maxVal - minVal)
  333. dr, dg, db = [(maxVal-val) / d for val in (r, g, b)]
  334. if r==maxVal:
  335. h = db - dg
  336. elif g==maxVal:
  337. h = 2.0 + dr - db
  338. else:
  339. h = 4.0 + dg - dr
  340. h = (h*60.0) % 360.0
  341. return (h, s, l)
  342. @staticmethod
  343. def _HueToRgb(n1, n2, h):
  344. h %= 6.0
  345. if h < 1.0: return n1 + ((n2-n1) * h)
  346. if h < 3.0: return n2
  347. if h < 4.0: return n1 + ((n2-n1) * (4.0 - h))
  348. return n1
  349. @staticmethod
  350. def HslToRgb(h, s, l):
  351. '''Convert the color from HSL coordinates to RGB.
  352. Parameters:
  353. :h:
  354. The Hue component value [0...1]
  355. :s:
  356. The Saturation component value [0...1]
  357. :l:
  358. The Lightness component value [0...1]
  359. Returns:
  360. The color as an (r, g, b) tuple in the range:
  361. r[0...1],
  362. g[0...1],
  363. b[0...1]
  364. >>> Color.HslToRgb(30.0, 1.0, 0.5)
  365. (1.0, 0.5, 0.0)
  366. '''
  367. if s==0: return (l, l, l) # achromatic (gray)
  368. if l<0.5: n2 = l * (1.0 + s)
  369. else: n2 = l+s - (l*s)
  370. n1 = (2.0 * l) - n2
  371. h /= 60.0
  372. hueToRgb = Color._HueToRgb
  373. r = hueToRgb(n1, n2, h + 2)
  374. g = hueToRgb(n1, n2, h)
  375. b = hueToRgb(n1, n2, h - 2)
  376. return (r, g, b)
  377. @staticmethod
  378. def RgbToHsv(r, g, b):
  379. '''Convert the color from RGB coordinates to HSV.
  380. Parameters:
  381. :r:
  382. The Red component value [0...1]
  383. :g:
  384. The Green component value [0...1]
  385. :b:
  386. The Blue component value [0...1]
  387. Returns:
  388. The color as an (h, s, v) tuple in the range:
  389. h[0...360],
  390. s[0...1],
  391. v[0...1]
  392. >>> Color.RgbToHsv(1, 0.5, 0)
  393. (30.0, 1, 1)
  394. '''
  395. v = max(r, g, b)
  396. d = v - min(r, g, b)
  397. if d==0: return (0.0, 0.0, v)
  398. s = d / v
  399. dr, dg, db = [(v - val) / d for val in (r, g, b)]
  400. if r==v:
  401. h = db - dg # between yellow & magenta
  402. elif g==v:
  403. h = 2.0 + dr - db # between cyan & yellow
  404. else: # b==v
  405. h = 4.0 + dg - dr # between magenta & cyan
  406. h = (h*60.0) % 360.0
  407. return (h, s, v)
  408. @staticmethod
  409. def HsvToRgb(h, s, v):
  410. '''Convert the color from RGB coordinates to HSV.
  411. Parameters:
  412. :h:
  413. The Hus component value [0...1]
  414. :s:
  415. The Saturation component value [0...1]
  416. :v:
  417. The Value component [0...1]
  418. Returns:
  419. The color as an (r, g, b) tuple in the range:
  420. r[0...1],
  421. g[0...1],
  422. b[0...1]
  423. >>> Color.HslToRgb(30.0, 1.0, 0.5)
  424. (1.0, 0.5, 0.0)
  425. '''
  426. if s==0: return (v, v, v) # achromatic (gray)
  427. h /= 60.0
  428. h = h % 6.0
  429. i = int(h)
  430. f = h - i
  431. if not(i&1): f = 1-f # if i is even
  432. m = v * (1.0 - s)
  433. n = v * (1.0 - (s * f))
  434. if i==0: return (v, n, m)
  435. if i==1: return (n, v, m)
  436. if i==2: return (m, v, n)
  437. if i==3: return (m, n, v)
  438. if i==4: return (n, m, v)
  439. return (v, m, n)
  440. @staticmethod
  441. def RgbToYiq(r, g, b):
  442. '''Convert the color from RGB to YIQ.
  443. Parameters:
  444. :r:
  445. The Red component value [0...1]
  446. :g:
  447. The Green component value [0...1]
  448. :b:
  449. The Blue component value [0...1]
  450. Returns:
  451. The color as an (y, i, q) tuple in the range:
  452. y[0...1],
  453. i[0...1],
  454. q[0...1]
  455. >>> '(%g, %g, %g)' % Color.RgbToYiq(1, 0.5, 0)
  456. '(0.592263, 0.458874, -0.0499818)'
  457. '''
  458. y = (r * 0.29895808) + (g * 0.58660979) + (b *0.11443213)
  459. i = (r * 0.59590296) - (g * 0.27405705) - (b *0.32184591)
  460. q = (r * 0.21133576) - (g * 0.52263517) + (b *0.31129940)
  461. return (y, i, q)
  462. @staticmethod
  463. def YiqToRgb(y, i, q):
  464. '''Convert the color from YIQ coordinates to RGB.
  465. Parameters:
  466. :y:
  467. Tte Y component value [0...1]
  468. :i:
  469. The I component value [0...1]
  470. :q:
  471. The Q component value [0...1]
  472. Returns:
  473. The color as an (r, g, b) tuple in the range:
  474. r[0...1],
  475. g[0...1],
  476. b[0...1]
  477. >>> '(%g, %g, %g)' % Color.YiqToRgb(0.592263, 0.458874, -0.0499818)
  478. '(1, 0.5, 5.442e-007)'
  479. '''
  480. r = y + (i * 0.9562) + (q * 0.6210)
  481. g = y - (i * 0.2717) - (q * 0.6485)
  482. b = y - (i * 1.1053) + (q * 1.7020)
  483. return (r, g, b)
  484. @staticmethod
  485. def RgbToYuv(r, g, b):
  486. '''Convert the color from RGB coordinates to YUV.
  487. Parameters:
  488. :r:
  489. The Red component value [0...1]
  490. :g:
  491. The Green component value [0...1]
  492. :b:
  493. The Blue component value [0...1]
  494. Returns:
  495. The color as an (y, u, v) tuple in the range:
  496. y[0...1],
  497. u[-0.436...0.436],
  498. v[-0.615...0.615]
  499. >>> '(%g, %g, %g)' % Color.RgbToYuv(1, 0.5, 0)
  500. '(0.5925, -0.29156, 0.357505)'
  501. '''
  502. y = (r * 0.29900) + (g * 0.58700) + (b * 0.11400)
  503. u = -(r * 0.14713) - (g * 0.28886) + (b * 0.43600)
  504. v = (r * 0.61500) - (g * 0.51499) - (b * 0.10001)
  505. return (y, u, v)
  506. @staticmethod
  507. def YuvToRgb(y, u, v):
  508. '''Convert the color from YUV coordinates to RGB.
  509. Parameters:
  510. :y:
  511. The Y component value [0...1]
  512. :u:
  513. The U component value [-0.436...0.436]
  514. :v:
  515. The V component value [-0.615...0.615]
  516. Returns:
  517. The color as an (r, g, b) tuple in the range:
  518. r[0...1],
  519. g[0...1],
  520. b[0...1]
  521. >>> '(%g, %g, %g)' % Color.YuvToRgb(0.5925, -0.2916, 0.3575)
  522. '(0.999989, 0.500015, -6.3276e-005)'
  523. '''
  524. r = y + (v * 1.13983)
  525. g = y - (u * 0.39465) - (v * 0.58060)
  526. b = y + (u * 2.03211)
  527. return (r, g, b)
  528. @staticmethod
  529. def RgbToXyz(r, g, b):
  530. '''Convert the color from sRGB to CIE XYZ.
  531. The methods assumes that the RGB coordinates are given in the sRGB
  532. colorspace (D65).
  533. .. note::
  534. Compensation for the sRGB gamma correction is applied before converting.
  535. Parameters:
  536. :r:
  537. The Red component value [0...1]
  538. :g:
  539. The Green component value [0...1]
  540. :b:
  541. The Blue component value [0...1]
  542. Returns:
  543. The color as an (x, y, z) tuple in the range:
  544. x[0...1],
  545. y[0...1],
  546. z[0...1]
  547. >>> '(%g, %g, %g)' % Color.RgbToXyz(1, 0.5, 0)
  548. '(0.488941, 0.365682, 0.0448137)'
  549. '''
  550. r, g, b = [((v <= 0.03928) and [v / 12.92] or [((v+0.055) / 1.055) **2.4])[0] for v in (r, g, b)]
  551. x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805)
  552. y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722)
  553. z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505)
  554. return (x, y, z)
  555. @staticmethod
  556. def XyzToRgb(x, y, z):
  557. '''Convert the color from CIE XYZ coordinates to sRGB.
  558. .. note::
  559. Compensation for sRGB gamma correction is applied before converting.
  560. Parameters:
  561. :x:
  562. The X component value [0...1]
  563. :y:
  564. The Y component value [0...1]
  565. :z:
  566. The Z component value [0...1]
  567. Returns:
  568. The color as an (r, g, b) tuple in the range:
  569. r[0...1],
  570. g[0...1],
  571. b[0...1]
  572. >>> '(%g, %g, %g)' % Color.XyzToRgb(0.488941, 0.365682, 0.0448137)
  573. '(1, 0.5, 6.81883e-008)'
  574. '''
  575. r = (x * 3.2406255) - (y * 1.5372080) - (z * 0.4986286)
  576. g = -(x * 0.9689307) + (y * 1.8757561) + (z * 0.0415175)
  577. b = (x * 0.0557101) - (y * 0.2040211) + (z * 1.0569959)
  578. return tuple((((v <= _srgbGammaCorrInv) and [v * 12.92] or [(1.055 * (v ** (1/2.4))) - 0.055])[0] for v in (r, g, b)))
  579. @staticmethod
  580. def XyzToLab(x, y, z, wref=_DEFAULT_WREF):
  581. '''Convert the color from CIE XYZ to CIE L*a*b*.
  582. Parameters:
  583. :x:
  584. The X component value [0...1]
  585. :y:
  586. The Y component value [0...1]
  587. :z:
  588. The Z component value [0...1]
  589. :wref:
  590. The whitepoint reference, default is 2° D65.
  591. Returns:
  592. The color as an (L, a, b) tuple in the range:
  593. L[0...100],
  594. a[-1...1],
  595. b[-1...1]
  596. >>> '(%g, %g, %g)' % Color.XyzToLab(0.488941, 0.365682, 0.0448137)
  597. '(66.9518, 0.43084, 0.739692)'
  598. >>> '(%g, %g, %g)' % Color.XyzToLab(0.488941, 0.365682, 0.0448137, Color.WHITE_REFERENCE['std_D50'])
  599. '(66.9518, 0.411663, 0.67282)'
  600. '''
  601. # White point correction
  602. x /= wref[0]
  603. y /= wref[1]
  604. z /= wref[2]
  605. # Nonlinear distortion and linear transformation
  606. x, y, z = [((v > 0.008856) and [v**_oneThird] or [(7.787 * v) + _sixteenHundredsixteenth])[0] for v in (x, y, z)]
  607. # Vector scaling
  608. l = (116 * y) - 16
  609. a = 5.0 * (x - y)
  610. b = 2.0 * (y - z)
  611. return (l, a, b)
  612. @staticmethod
  613. def LabToXyz(l, a, b, wref=_DEFAULT_WREF):
  614. '''Convert the color from CIE L*a*b* to CIE 1931 XYZ.
  615. Parameters:
  616. :l:
  617. The L component [0...100]
  618. :a:
  619. The a component [-1...1]
  620. :b:
  621. The a component [-1...1]
  622. :wref:
  623. The whitepoint reference, default is 2° D65.
  624. Returns:
  625. The color as an (x, y, z) tuple in the range:
  626. x[0...q],
  627. y[0...1],
  628. z[0...1]
  629. >>> '(%g, %g, %g)' % Color.LabToXyz(66.9518, 0.43084, 0.739692)
  630. '(0.488941, 0.365682, 0.0448137)'
  631. >>> '(%g, %g, %g)' % Color.LabToXyz(66.9518, 0.411663, 0.67282, Color.WHITE_REFERENCE['std_D50'])
  632. '(0.488941, 0.365682, 0.0448138)'
  633. '''
  634. y = (l + 16) / 116
  635. x = (a / 5.0) + y
  636. z = y - (b / 2.0)
  637. return tuple((((v > 0.206893) and [v**3] or [(v - _sixteenHundredsixteenth) / 7.787])[0] * w for v, w in zip((x, y, z), wref)))
  638. @staticmethod
  639. def CmykToCmy(c, m, y, k):
  640. '''Convert the color from CMYK coordinates to CMY.
  641. Parameters:
  642. :c:
  643. The Cyan component value [0...1]
  644. :m:
  645. The Magenta component value [0...1]
  646. :y:
  647. The Yellow component value [0...1]
  648. :k:
  649. The Black component value [0...1]
  650. Returns:
  651. The color as an (c, m, y) tuple in the range:
  652. c[0...1],
  653. m[0...1],
  654. y[0...1]
  655. >>> '(%g, %g, %g)' % Color.CmykToCmy(1, 0.32, 0, 0.5)
  656. '(1, 0.66, 0.5)'
  657. '''
  658. mk = 1-k
  659. return ((c*mk + k), (m*mk + k), (y*mk + k))
  660. @staticmethod
  661. def CmyToCmyk(c, m, y):
  662. '''Convert the color from CMY coordinates to CMYK.
  663. Parameters:
  664. :c:
  665. The Cyan component value [0...1]
  666. :m:
  667. The Magenta component value [0...1]
  668. :y:
  669. The Yellow component value [0...1]
  670. Returns:
  671. The color as an (c, m, y, k) tuple in the range:
  672. c[0...1],
  673. m[0...1],
  674. y[0...1],
  675. k[0...1]
  676. >>> '(%g, %g, %g, %g)' % Color.CmyToCmyk(1, 0.66, 0.5)
  677. '(1, 0.32, 0, 0.5)'
  678. '''
  679. k = min(c, m, y)
  680. if k==1.0: return (0.0, 0.0, 0.0, 1.0)
  681. mk = 1-k
  682. return ((c-k) / mk, (m-k) / mk, (y-k) / mk, k)
  683. @staticmethod
  684. def RgbToCmy(r, g, b):
  685. '''Convert the color from RGB coordinates to CMY.
  686. Parameters:
  687. :r:
  688. The Red component value [0...1]
  689. :g:
  690. The Green component value [0...1]
  691. :b:
  692. The Blue component value [0...1]
  693. Returns:
  694. The color as an (c, m, y) tuple in the range:
  695. c[0...1],
  696. m[0...1],
  697. y[0...1]
  698. >>> Color.RgbToCmy(1, 0.5, 0)
  699. (0, 0.5, 1)
  700. '''
  701. return (1-r, 1-g, 1-b)
  702. @staticmethod
  703. def CmyToRgb(c, m, y):
  704. '''Convert the color from CMY coordinates to RGB.
  705. Parameters:
  706. :c:
  707. The Cyan component value [0...1]
  708. :m:
  709. The Magenta component value [0...1]
  710. :y:
  711. The Yellow component value [0...1]
  712. Returns:
  713. The color as an (r, g, b) tuple in the range:
  714. r[0...1],
  715. g[0...1],
  716. b[0...1]
  717. >>> Color.CmyToRgb(0, 0.5, 1)
  718. (1, 0.5, 0)
  719. '''
  720. return (1-c, 1-m, 1-y)
  721. @staticmethod
  722. def RgbToHtml(r, g, b):
  723. '''Convert the color from (r, g, b) to #RRGGBB.
  724. Parameters:
  725. :r:
  726. The Red component value [0...1]
  727. :g:
  728. The Green component value [0...1]
  729. :b:
  730. The Blue component value [0...1]
  731. Returns:
  732. A CSS string representation of this color (#RRGGBB).
  733. >>> Color.RgbToHtml(1, 0.5, 0)
  734. '#ff8000'
  735. '''
  736. return '#%02x%02x%02x' % tuple((min(round(v*255), 255) for v in (r, g, b)))
  737. @staticmethod
  738. def HtmlToRgb(html):
  739. '''Convert the HTML color to (r, g, b).
  740. Parameters:
  741. :html:
  742. the HTML definition of the color (#RRGGBB or #RGB or a color name).
  743. Returns:
  744. The color as an (r, g, b) tuple in the range:
  745. r[0...1],
  746. g[0...1],
  747. b[0...1]
  748. Throws:
  749. :ValueError:
  750. If html is neither a known color name or a hexadecimal RGB
  751. representation.
  752. >>> '(%g, %g, %g)' % Color.HtmlToRgb('#ff8000')
  753. '(1, 0.501961, 0)'
  754. >>> '(%g, %g, %g)' % Color.HtmlToRgb('ff8000')
  755. '(1, 0.501961, 0)'
  756. >>> '(%g, %g, %g)' % Color.HtmlToRgb('#f60')
  757. '(1, 0.4, 0)'
  758. >>> '(%g, %g, %g)' % Color.HtmlToRgb('f60')
  759. '(1, 0.4, 0)'
  760. >>> '(%g, %g, %g)' % Color.HtmlToRgb('lemonchiffon')
  761. '(1, 0.980392, 0.803922)'
  762. '''
  763. html = html.strip().lower()
  764. if html[0]=='#':
  765. html = html[1:]
  766. elif Color.NAMED_COLOR.has_key(html):
  767. html = Color.NAMED_COLOR[html][1:]
  768. if len(html)==6:
  769. rgb = html[:2], html[2:4], html[4:]
  770. elif len(html)==3:
  771. rgb = ['%c%c' % (v,v) for v in html]
  772. else:
  773. raise ValueError, 'input #%s is not in #RRGGBB format' % html
  774. return tuple(((int(n, 16) / 255.0) for n in rgb))
  775. @staticmethod
  776. def RgbToPil(r, g, b):
  777. '''Convert the color from RGB to a PIL-compatible integer.
  778. Parameters:
  779. :r:
  780. The Red component value [0...1]
  781. :g:
  782. The Green component value [0...1]
  783. :b:
  784. The Blue component value [0...1]
  785. Returns:
  786. A PIL compatible integer (0xBBGGRR).
  787. >>> '0x%06x' % Color.RgbToPil(1, 0.5, 0)
  788. '0x0080ff'
  789. '''
  790. r, g, b = [min(int(round(v*255)), 255) for v in (r, g, b)]
  791. return (b << 16) + (g << 8) + r
  792. @staticmethod
  793. def PilToRgb(pil):
  794. '''Convert the color from a PIL-compatible integer to RGB.
  795. Parameters:
  796. pil: a PIL compatible color representation (0xBBGGRR)
  797. Returns:
  798. The color as an (r, g, b) tuple in the range:
  799. the range:
  800. r: [0...1]
  801. g: [0...1]
  802. b: [0...1]
  803. >>> '(%g, %g, %g)' % Color.PilToRgb(0x0080ff)
  804. '(1, 0.501961, 0)'
  805. '''
  806. r = 0xff & pil
  807. g = 0xff & (pil >> 8)
  808. b = 0xff & (pil >> 16)
  809. return tuple((v / 255.0 for v in (r, g, b)))
  810. @staticmethod
  811. def _WebSafeComponent(c, alt=False):
  812. '''Convert a color component to its web safe equivalent.
  813. Parameters:
  814. :c:
  815. The component value [0...1]
  816. :alt:
  817. If True, return the alternative value instead of the nearest one.
  818. Returns:
  819. The web safe equivalent of the component value.
  820. '''
  821. # This sucks, but floating point between 0 and 1 is quite fuzzy...
  822. # So we just change the scale a while to make the equality tests
  823. # work, otherwise it gets wrong at some decimal far to the right.
  824. sc = c * 100.0
  825. # If the color is already safe, return it straight away
  826. d = sc % 20
  827. if d==0: return c
  828. # Get the lower and upper safe values
  829. l = sc - d
  830. u = l + 20
  831. # Return the 'closest' value according to the alt flag
  832. if alt:
  833. if (sc-l) >= (u-sc): return l/100.0
  834. else: return u/100.0
  835. else:
  836. if (sc-l) >= (u-sc): return u/100.0
  837. else: return l/100.0
  838. @staticmethod
  839. def RgbToWebSafe(r, g, b, alt=False):
  840. '''Convert the color from RGB to 'web safe' RGB
  841. Parameters:
  842. :r:
  843. The Red component value [0...1]
  844. :g:
  845. The Green component value [0...1]
  846. :b:
  847. The Blue component value [0...1]
  848. :alt:
  849. If True, use the alternative color instead of the nearest one.
  850. Can be used for dithering.
  851. Returns:
  852. The color as an (r, g, b) tuple in the range:
  853. the range:
  854. r[0...1],
  855. g[0...1],
  856. b[0...1]
  857. >>> '(%g, %g, %g)' % Color.RgbToWebSafe(1, 0.55, 0.0)
  858. '(1, 0.6, 0)'
  859. '''
  860. webSafeComponent = Color._WebSafeComponent
  861. return tuple((webSafeComponent(v, alt) for v in (r, g, b)))
  862. @staticmethod
  863. def RgbToGreyscale(r, g, b):
  864. '''Convert the color from RGB to its greyscale equivalent
  865. Parameters:
  866. :r:
  867. The Red component value [0...1]
  868. :g:
  869. The Green component value [0...1]
  870. :b:
  871. The Blue component value [0...1]
  872. Returns:
  873. The color as an (r, g, b) tuple in the range:
  874. the range:
  875. r[0...1],
  876. g[0...1],
  877. b[0...1]
  878. >>> '(%g, %g, %g)' % Color.RgbToGreyscale(1, 0.8, 0)
  879. '(0.6, 0.6, 0.6)'
  880. '''
  881. v = (r + g + b) / 3.0
  882. return (v, v, v)
  883. @staticmethod
  884. def RgbToRyb(hue):
  885. '''Maps a hue on the RGB color wheel to Itten's RYB wheel.
  886. Parameters:
  887. :hue:
  888. The hue on the RGB color wheel [0...360]
  889. Returns:
  890. An approximation of the corresponding hue on Itten's RYB wheel.
  891. >>> Color.RgbToRyb(15)
  892. 26
  893. '''
  894. d = hue % 15
  895. i = int(hue / 15)
  896. x0 = _RybWheel[i]
  897. x1 = _RybWheel[i+1]
  898. return x0 + (x1-x0) * d / 15
  899. @staticmethod
  900. def RybToRgb(hue):
  901. '''Maps a hue on Itten's RYB color wheel to the standard RGB wheel.
  902. Parameters:
  903. :hue:
  904. The hue on Itten's RYB color wheel [0...360]
  905. Returns:
  906. An approximation of the corresponding hue on the standard RGB wheel.
  907. >>> Color.RybToRgb(15)
  908. 8
  909. '''
  910. d = hue % 15
  911. i = int(hue / 15)
  912. x0 = _RgbWheel[i]
  913. x1 = _RgbWheel[i+1]
  914. return x0 + (x1-x0) * d / 15
  915. @staticmethod
  916. def NewFromRgb(r, g, b, alpha=1.0, wref=_DEFAULT_WREF):
  917. '''Create a new instance based on the specifed RGB values.
  918. Parameters:
  919. :r:
  920. The Red component value [0...1]
  921. :g:
  922. The Green component value [0...1]
  923. :b:
  924. The Blue component value [0...1]
  925. :alpha:
  926. The color transparency [0...1], default is opaque
  927. :wref:
  928. The whitepoint reference, default is 2° D65.
  929. Returns:
  930. A grapefruit.Color instance.
  931. >>> Color.NewFromRgb(1.0, 0.5, 0.0)
  932. (1.0, 0.5, 0.0, 1.0)
  933. >>> Color.NewFromRgb(1.0, 0.5, 0.0, 0.5)
  934. (1.0, 0.5, 0.0, 0.5)
  935. '''
  936. return Color((r, g, b), 'rgb', alpha, wref)
  937. @staticmethod
  938. def NewFromHsl(h, s, l, alpha=1.0, wref=_DEFAULT_WREF):
  939. '''Create a new instance based on the specifed HSL values.
  940. Parameters:
  941. :h:
  942. The Hue component value [0...1]
  943. :s:
  944. The Saturation component value [0...1]
  945. :l:
  946. The Lightness component value [0...1]
  947. :alpha:
  948. The color transparency [0...1], default is opaque
  949. :wref:
  950. The whitepoint reference, default is 2° D65.
  951. Returns:
  952. A grapefruit.Color instance.
  953. >>> Color.NewFromHsl(30, 1, 0.5)
  954. (1.0, 0.5, 0.0, 1.0)
  955. >>> Color.NewFromHsl(30, 1, 0.5, 0.5)
  956. (1.0, 0.5, 0.0, 0.5)
  957. '''
  958. return Color((h, s, l), 'hsl', alpha, wref)
  959. @staticmethod
  960. def NewFromHsv(h, s, v, alpha=1.0, wref=_DEFAULT_WREF):
  961. '''Create a new instance based on the specifed HSV values.
  962. Parameters:
  963. :h:
  964. The Hus component value [0...1]
  965. :s:
  966. The Saturation component value [0...1]
  967. :v:
  968. The Value component [0...1]
  969. :alpha:
  970. The color transparency [0...1], default is opaque
  971. :wref:
  972. The whitepoint reference, default is 2° D65.
  973. Returns:
  974. A grapefruit.Color instance.
  975. >>> Color.NewFromHsv(30, 1, 1)
  976. (1.0, 0.5, 0.0, 1.0)
  977. >>> Color.NewFromHsv(30, 1, 1, 0.5)
  978. (1.0, 0.5, 0.0, 0.5)
  979. '''
  980. h2, s, l = Color.RgbToHsl(*Color.HsvToRgb(h, s, v))
  981. return Color((h, s, l), 'hsl', alpha, wref)
  982. @staticmethod
  983. def NewFromYiq(y, i, q, alpha=1.0, wref=_DEFAULT_WREF):
  984. '''Create a new instance based on the specifed YIQ values.
  985. Parameters:
  986. :y:
  987. The Y component value [0...1]
  988. :i:
  989. The I component value [0...1]
  990. :q:
  991. The Q component value [0...1]
  992. :alpha:
  993. The color transparency [0...1], default is opaque
  994. :wref:
  995. The whitepoint reference, default is 2° D65.
  996. Returns:
  997. A grapefruit.Color instance.
  998. >>> str(Color.NewFromYiq(0.5922, 0.45885,-0.05))
  999. '(0.999902, 0.499955, -6.6905e-005, 1)'
  1000. >>> str(Color.NewFromYiq(0.5922, 0.45885,-0.05, 0.5))
  1001. '(0.999902, 0.499955, -6.6905e-005, 0.5)'
  1002. '''
  1003. return Color(Color.YiqToRgb(y, i, q), 'rgb', alpha, wref)
  1004. @staticmethod
  1005. def NewFromYuv(y, u, v, alpha=1.0, wref=_DEFAULT_WREF):
  1006. '''Create a new instance based on the specifed YUV values.
  1007. Parameters:
  1008. :y:
  1009. The Y component value [0...1]
  1010. :u:
  1011. The U component value [-0.436...0.436]
  1012. :v:
  1013. The V component value [-0.615...0.615]
  1014. :alpha:
  1015. The color transparency [0...1], default is opaque
  1016. :wref:
  1017. The whitepoint reference, default is 2° D65.
  1018. Returns:
  1019. A grapefruit.Color instance.
  1020. >>> str(Color.NewFromYuv(0.5925, -0.2916, 0.3575))
  1021. '(0.999989, 0.500015, -6.3276e-005, 1)'
  1022. >>> str(Color.NewFromYuv(0.5925, -0.2916, 0.3575, 0.5))
  1023. '(0.999989, 0.500015, -6.3276e-005, 0.5)'
  1024. '''
  1025. return Color(Color.YuvToRgb(y, u, v), 'rgb', alpha, wref)
  1026. @staticmethod
  1027. def NewFromXyz(x, y, z, alpha=1.0, wref=_DEFAULT_WREF):
  1028. '''Create a new instance based on the specifed CIE-XYZ values.
  1029. Parameters:
  1030. :x:
  1031. The Red component value [0...1]
  1032. :y:
  1033. The Green component value [0...1]
  1034. :z:
  1035. The Blue component value [0...1]
  1036. :alpha:
  1037. The color transparency [0...1], default is opaque
  1038. :wref:
  1039. The whitepoint reference, default is 2° D65.
  1040. Returns:
  1041. A grapefruit.Color instance.
  1042. >>> str(Color.NewFromXyz(0.488941, 0.365682, 0.0448137))
  1043. '(1, 0.5, 6.81883e-008, 1)'
  1044. >>> str(Color.NewFromXyz(0.488941, 0.365682, 0.0448137, 0.5))
  1045. '(1, 0.5, 6.81883e-008, 0.5)'
  1046. '''
  1047. return Color(Color.XyzToRgb(x, y, z), 'rgb', alpha, wref)
  1048. @staticmethod
  1049. def NewFromLab(l, a, b, alpha=1.0, wref=_DEFAULT_WREF):
  1050. '''Create a new instance based on the specifed CIE-LAB values.
  1051. Parameters:
  1052. :l:
  1053. The L component [0...100]
  1054. :a:
  1055. The a component [-1...1]
  1056. :b:
  1057. The a component [-1...1]
  1058. :alpha:
  1059. The color transparency [0...1], default is opaque
  1060. :wref:
  1061. The whitepoint reference, default is 2° D65.
  1062. Returns:
  1063. A grapefruit.Color instance.
  1064. >>> str(Color.NewFromLab(66.9518, 0.43084, 0.739692))
  1065. '(1, 0.5, 1.09491e-008, 1)'
  1066. >>> str(Color.NewFromLab(66.9518, 0.43084, 0.739692, wref=Color.WHITE_REFERENCE['std_D50']))
  1067. '(1.01238, 0.492011, -0.14311, 1)'
  1068. >>> str(Color.NewFromLab(66.9518, 0.43084, 0.739692, 0.5))
  1069. '(1, 0.5, 1.09491e-008, 0.5)'
  1070. >>> str(Color.NewFromLab(66.9518, 0.43084, 0.739692, 0.5, Color.WHITE_REFERENCE['std_D50']))
  1071. '(1.01238, 0.492011, -0.14311, 0.5)'
  1072. '''
  1073. return Color(Color.XyzToRgb(*Color.LabToXyz(l, a, b, wref)), 'rgb', alpha, wref)
  1074. @staticmethod
  1075. def NewFromCmy(c, m, y, alpha=1.0, wref=_DEFAULT_WREF):
  1076. '''Create a new instance based on the specifed CMY values.
  1077. Parameters:
  1078. :c:
  1079. The Cyan component value [0...1]
  1080. :m:
  1081. The Magenta component value [0...1]
  1082. :y:
  1083. The Yellow component value [0...1]
  1084. :alpha:
  1085. The color transparency [0...1], default is opaque
  1086. :wref:
  1087. The whitepoint reference, default is 2° D65.
  1088. Returns:
  1089. A grapefruit.Color instance.
  1090. >>> Color.NewFromCmy(0, 0.5, 1)
  1091. (1, 0.5, 0, 1.0)
  1092. >>> Color.NewFromCmy(0, 0.5, 1, 0.5)
  1093. (1, 0.5, 0, 0.5)
  1094. '''
  1095. return Color(Color.CmyToRgb(c, m, y), 'rgb', alpha, wref)
  1096. @staticmethod
  1097. def NewFromCmyk(c, m, y, k, alpha=1.0, wref=_DEFAULT_WREF):
  1098. '''Create a new instance based on the specifed CMYK values.
  1099. Parameters:
  1100. :c:
  1101. The Cyan component value [0...1]
  1102. :m:
  1103. The Magenta component value [0...1]
  1104. :y:
  1105. The Yellow component value [0...1]
  1106. :k:
  1107. The Black component value [0...1]
  1108. :alpha:
  1109. The color transparency [0...1], default is opaque
  1110. :wref:
  1111. The whitepoint reference, default is 2° D65.
  1112. Returns:
  1113. A grapefruit.Color instance.
  1114. >>> str(Color.NewFromCmyk(1, 0.32, 0, 0.5))
  1115. '(0, 0.34, 0.5, 1)'
  1116. >>> str(Color.NewFromCmyk(1, 0.32, 0, 0.5, 0.5))
  1117. '(0, 0.34, 0.5, 0.5)'
  1118. '''
  1119. return Color(Color.CmyToRgb(*Color.CmykToCmy(c, m, y, k)), 'rgb', alpha, wref)
  1120. @staticmethod
  1121. def NewFromHtml(html, alpha=1.0, wref=_DEFAULT_WREF):
  1122. '''Create a new instance based on the specifed HTML color definition.
  1123. Parameters:
  1124. :html:
  1125. The HTML definition of the color (#RRGGBB or #RGB or a color name).
  1126. :alpha:
  1127. The color transparency [0...1], default is opaque.
  1128. :wref:
  1129. The whitepoint reference, default is 2° D65.
  1130. Returns:
  1131. A grapefruit.Color instance.
  1132. >>> str(Color.NewFromHtml('#ff8000'))
  1133. '(1, 0.501961, 0, 1)'
  1134. >>> str(Color.NewFromHtml('ff8000'))
  1135. '(1, 0.501961, 0, 1)'
  1136. >>> str(Color.NewFromHtml('#f60'))
  1137. '(1, 0.4, 0, 1)'
  1138. >>> str(Color.NewFromHtml('f60'))
  1139. '(1, 0.4, 0, 1)'
  1140. >>> str(Color.NewFromHtml('lemonchiffon'))
  1141. '(1, 0.980392, 0.803922, 1)'
  1142. >>> str(Color.NewFromHtml('#ff8000', 0.5))
  1143. '(1, 0.501961, 0, 0.5)'
  1144. '''
  1145. return Color(Color.HtmlToRgb(html), 'rgb', alpha, wref)
  1146. @staticmethod
  1147. def NewFromPil(pil, alpha=1.0, wref=_DEFAULT_WREF):
  1148. '''Create a new instance based on the specifed PIL color.
  1149. Parameters:
  1150. :pil:
  1151. A PIL compatible color representation (0xBBGGRR)
  1152. :alpha:
  1153. The color transparency [0...1], default is opaque
  1154. :wref:
  1155. The whitepoint reference, default is 2° D65.
  1156. Returns:
  1157. A grapefruit.Color instance.
  1158. >>> str(Color.NewFromPil(0x0080ff))
  1159. '(1, 0.501961, 0, 1)'
  1160. >>> str(Color.NewFromPil(0x0080ff, 0.5))
  1161. '(1, 0.501961, 0, 0.5)'
  1162. '''
  1163. return Color(Color.PilToRgb(pil), 'rgb', alpha, wref)
  1164. def __GetAlpha(self):
  1165. return self.__a
  1166. alpha = property(fget=__GetAlpha, doc='The transparency of this color. 0.0 is transparent and 1.0 is fully opaque.')
  1167. def __GetWRef(self):
  1168. return self.__wref
  1169. whiteRef = property(fget=__GetWRef, doc='the white reference point of this color.')
  1170. def __GetRGB(self):
  1171. return self.__rgb
  1172. rgb = property(fget=__GetRGB, doc='The RGB values of this Color.')
  1173. def __GetHue(self):
  1174. return self.__hsl[0]
  1175. hue = property(fget=__GetHue, doc='The hue of this color.')
  1176. def __GetHSL(self):
  1177. return self.__hsl
  1178. hsl = property(fget=__GetHSL, doc='The HSL values of this Color.')
  1179. def __GetHSV(self):
  1180. h, s, v = Color.RgbToHsv(*self.__rgb)
  1181. return (self.__hsl[0], s, v)
  1182. hsv = property(fget=__GetHSV, doc='The HSV values of this Color.')
  1183. def __GetYIQ(self):
  1184. return Color.RgbToYiq(*self.__rgb)
  1185. yiq = property(fget=__GetYIQ, doc='The YIQ values of this Color.')
  1186. def __GetYUV(self):
  1187. return Color.RgbToYuv(*self.__rgb)
  1188. yuv = property(fget=__GetYUV, doc='The YUV values of this Color.')
  1189. def __GetXYZ(self):
  1190. return Color.RgbToXyz(*self.__rgb)
  1191. xyz = property(fget=__GetXYZ, doc='The CIE-XYZ values of this Color.')
  1192. def __GetLAB(self):
  1193. return Color.XyzToLab(wref=self.__wref, *Color.RgbToXyz(*self.__rgb))
  1194. lab = property(fget=__GetLAB, doc='The CIE-LAB values of this Color.')
  1195. def __GetCMY(self):
  1196. return Color.RgbToCmy(*self.__rgb)
  1197. cmy = property(fget=__GetCMY, doc='The CMY values of this Color.')
  1198. def __GetCMYK(self):
  1199. return Color.CmyToCmyk(*Color.RgbToCmy(*self.__rgb))
  1200. cmyk = property(fget=__GetCMYK, doc='The CMYK values of this Color.')
  1201. def __GetHTML(self):
  1202. return Color.RgbToHtml(*self.__rgb)
  1203. html = property(fget=__GetHTML, doc='This Color as an HTML color definition.')
  1204. def __GetPIL(self):
  1205. return Color.RgbToPil(*self.__rgb)
  1206. pil = property(fget=__GetPIL, doc='This Color as a PIL compatible value.')
  1207. def __GetwebSafe(self):
  1208. return Color.RgbToWebSafe(*self.__rgb)
  1209. webSafe = property(fget=__GetwebSafe, doc='The web safe color nearest to this one (RGB).')
  1210. def __GetGreyscale(self):
  1211. return Color.RgbToGreyscale(*self.rgb)
  1212. greyscale = property(fget=__GetGreyscale, doc='The greyscale equivalent to this color (RGB).')
  1213. def ColorWithAlpha(self, alpha):
  1214. '''Create a new instance based on this one with a new alpha value.
  1215. Parameters:
  1216. :alpha:
  1217. The transparency of the new color [0...1].
  1218. Returns:
  1219. A grapefruit.Color instance.
  1220. >>> Color.NewFromRgb(1.0, 0.5, 0.0, 1.0).ColorWithAlpha(0.5)
  1221. (1.0, 0.5, 0.0, 0.5)
  1222. '''
  1223. return Color(self.__rgb, 'rgb', alpha, self.__wref)
  1224. def ColorWithWhiteRef(self, wref, labAsRef=False):
  1225. '''Create a new instance based on this one with a new white reference.
  1226. Parameters:
  1227. :wref:
  1228. The whitepoint reference.
  1229. :labAsRef:
  1230. If True, the L*a*b* values of the current instance are used as reference
  1231. for the new color; otherwise, the RGB values are used as reference.
  1232. Returns:
  1233. A grapefruit.Color instance.
  1234. >>> c = Color.NewFromRgb(1.0, 0.5, 0.0, 1.0, Color.WHITE_REFERENCE['std_D65'])
  1235. >>> c2 = c.ColorWithWhiteRef(Color.WHITE_REFERENCE['sup_D50'])
  1236. >>> c2.rgb
  1237. (1.0, 0.5, 0.0)
  1238. >>> '(%g, %g, %g)' % c2.whiteRef
  1239. '(0.96721, 1, 0.81428)'
  1240. >>> c2 = c.ColorWithWhiteRef(Color.WHITE_REFERENCE['sup_D50'], labAsRef=True)
  1241. >>> '(%g, %g, %g)' % c2.rgb
  1242. '(1.01463, 0.490339, -0.148131)'
  1243. >>> '(%g, %g, %g)' % c2.whiteRef
  1244. '(0.96721, 1, 0.81428)'
  1245. >>> '(%g, %g, %g)' % c.lab
  1246. '(66.9518, 0.43084, 0.739692)'
  1247. >>> '(%g, %g, %g)' % c2.lab
  1248. '(66.9518, 0.43084, 0.739693)'
  1249. '''
  1250. if labAsRef:
  1251. l, a, b = self.__GetLAB()
  1252. return Color.NewFromLab(l, a, b, self.__a, wref)
  1253. else:
  1254. return Color(self.__rgb, 'rgb', self.__a, wref)
  1255. def ColorWithHue(self, hue):
  1256. '''Create a new instance based on this one with a new hue.
  1257. Parameters:
  1258. :hue:
  1259. The hue of the new color [0...360].
  1260. Returns:
  1261. A grapefruit.Color instance.
  1262. >>> Color.NewFromHsl(30, 1, 0.5).ColorWithHue(60)
  1263. (1.0, 1.0, 0.0, 1.0)
  1264. >>> Color.NewFromHsl(30, 1, 0.5).ColorWithHue(60).hsl
  1265. (60, 1, 0.5)
  1266. '''
  1267. h, s, l = self.__hsl
  1268. return Color((hue, s, l), 'hsl', self.__a, self.__wref)
  1269. def ColorWithSaturation(self, saturation):
  1270. '''Create a new instance based on this one with a new saturation value.
  1271. .. note::
  1272. The saturation is defined for the HSL mode.
  1273. Parameters:
  1274. :saturation:
  1275. The saturation of the new color [0...1].
  1276. Returns:
  1277. A grapefruit.Color instance.
  1278. >>> Color.NewFromHsl(30, 1, 0.5).ColorWithSaturation(0.5)
  1279. (0.75, 0.5, 0.25, 1.0)
  1280. >>> Color.NewFromHsl(30, 1, 0.5).ColorWithSaturation(0.5).hsl
  1281. (30, 0.5, 0.5)
  1282. '''
  1283. h, s, l = self.__hsl
  1284. return Color((h, saturation, l), 'hsl', self.__a, self.__wref)
  1285. def ColorWithLightness(self, lightness):
  1286. '''Create a new instance based on this one with a new lightness value.
  1287. Parameters:
  1288. :lightness:
  1289. The lightness of the new color [0...1].
  1290. Returns:
  1291. A grapefruit.Color instance.
  1292. >>> Color.NewFromHsl(30, 1, 0.5).ColorWithLightness(0.25)
  1293. (0.5, 0.25, 0.0, 1.0)
  1294. >>> Color.NewFromHsl(30, 1, 0.5).ColorWithLightness(0.25).hsl
  1295. (30, 1, 0.25)
  1296. '''
  1297. h, s, l = self.__hsl
  1298. return Color((h, s, lightness), 'hsl', self.__a, self.__wref)
  1299. def DarkerColor(self, level):
  1300. '''Create a new instance based on this one but darker.
  1301. Parameters:
  1302. :level:
  1303. The amount by which the color should be darkened to produce
  1304. the new one [0...1].
  1305. Returns:
  1306. A grapefruit.Color instance.
  1307. >>> Color.NewFromHsl(30, 1, 0.5).DarkerColor(0.25)
  1308. (0.5, 0.25, 0.0, 1.0)
  1309. >>> Color.NewFromHsl(30, 1, 0.5).DarkerColor(0.25).hsl
  1310. (30, 1, 0.25)
  1311. '''
  1312. h, s, l = self.__hsl
  1313. return Color((h, s, max(l - level, 0)), 'hsl', self.__a, self.__wref)
  1314. def LighterColor(self, level):
  1315. '''Create a new instance based on this one but lighter.
  1316. Parameters:
  1317. :level:
  1318. The amount by which the color should be lightened to produce
  1319. the new one [0...1].
  1320. Returns:
  1321. A grapefruit.Color instance.
  1322. >>> Color.NewFromHsl(30, 1, 0.5).LighterColor(0.25)
  1323. (1.0, 0.75, 0.5, 1.0)
  1324. >>> Color.NewFromHsl(30, 1, 0.5).LighterColor(0.25).hsl
  1325. (30, 1, 0.75)
  1326. '''
  1327. h, s, l = self.__hsl
  1328. return Color((h, s, min(l + level, 1)), 'hsl', self.__a, self.__wref)
  1329. def Saturate(self, level):
  1330. '''Create a new instance based on this one but more saturated.
  1331. Parameters:
  1332. :level:
  1333. The amount by which the color should be saturated to produce
  1334. the new one [0...1].
  1335. Returns:
  1336. A grapefruit.Color instance.
  1337. >>> Color.NewFromHsl(30, 0.5, 0.5).Saturate(0.25)
  1338. (0.875, 0.5, 0.125, 1.0)
  1339. >>> Color.NewFromHsl(30, 0.5, 0.5).Saturate(0.25).hsl
  1340. (30, 0.75, 0.5)
  1341. '''
  1342. h, s, l = self.__hsl
  1343. return Color((h, min(s + level, 1), l), 'hsl', self.__a, self.__wref)
  1344. def Desaturate(self, level):
  1345. '''Create a new instance based on this one but less saturated.
  1346. Parameters:
  1347. :level:
  1348. The amount by which the color should be desaturated to produce
  1349. the new one [0...1].
  1350. Returns:
  1351. A grapefruit.Color instance.
  1352. >>> Color.NewFromHsl(30, 0.5, 0.5).Desaturate(0.25)
  1353. (0.625, 0.5, 0.375, 1.0)
  1354. >>> Color.NewFromHsl(30, 0.5, 0.5).Desaturate(0.25).hsl
  1355. (30, 0.25, 0.5)
  1356. '''
  1357. h, s, l = self.__hsl
  1358. return Color((h, max(s - level, 0), l), 'hsl', self.__a, self.__wref)
  1359. def WebSafeDither(self):
  1360. '''Return the two websafe colors nearest to this one.
  1361. Returns:
  1362. A tuple of two grapefruit.Color instances which are the two
  1363. web safe colors closest this one.
  1364. >>> c = Color.NewFromRgb(1.0, 0.45, 0.0)
  1365. >>> c1, c2 = c.WebSafeDither()
  1366. >>> str(c1)
  1367. '(1, 0.4, 0, 1)'
  1368. >>> str(c2)
  1369. '(1, 0.6, 0, 1)'
  1370. '''
  1371. return (
  1372. Color(Color.RgbToWebSafe(*self.__rgb), 'rgb', self.__a, self.__wref),
  1373. Color(Color.RgbToWebSafe(alt=True, *self.__rgb), 'rgb', self.__a, self.__wref))
  1374. def Gradient(self, target, steps=100):
  1375. '''Create a list with the gradient colors between this and the other color.
  1376. Parameters:
  1377. :target:
  1378. The grapefruit.Color at the other end of the gradient.
  1379. :steps:
  1380. The number of gradients steps to create.
  1381. Returns:
  1382. A list of grapefruit.Color instances.
  1383. >>> c1 = Color.NewFromRgb(1.0, 0.0, 0.0, alpha=1)
  1384. >>> c2 = Color.NewFromRgb(0.0, 1.0, 0.0, alpha=0)
  1385. >>> c1.Gradient(c2, 3)
  1386. [(0.75, 0.25, 0.0, 0.75), (0.5, 0.5, 0.0, 0.5), (0.25, 0.75, 0.0, 0.25)]
  1387. '''
  1388. gradient = []
  1389. rgba1 = self.__rgb + (self.__a,)
  1390. rgba2 = target.__rgb + (target.__a,)
  1391. steps += 1
  1392. for n in xrange(1, steps):
  1393. d = 1.0*n/steps
  1394. r = (rgba1[0]*(1-d)) + (rgba2[0]*d)
  1395. g = (rgba1[1]*(1-d)) + (rgba2[1]*d)
  1396. b = (rgba1[2]*(1-d)) + (rgba2[2]*d)
  1397. a = (rgba1[3]*(1-d)) + (rgba2[3]*d)
  1398. gradient.append(Color((r, g, b), 'rgb', a, self.__wref))
  1399. return gradient
  1400. def ComplementaryColor(self, mode='ryb'):
  1401. '''Create a new instance which is the complementary color of this one.
  1402. Parameters:
  1403. :mode:
  1404. Select which color wheel to use for the generation (ryb/rgb).
  1405. Returns:
  1406. A grapefruit.Color instance.
  1407. >>> Color.NewFromHsl(30, 1, 0.5).ComplementaryColor()
  1408. (0.0, 0.5, 1.0, 1.0)
  1409. >>> Color.NewFromHsl(30, 1, 0.5).ComplementaryColor().hsl
  1410. (210, 1, 0.5)
  1411. '''
  1412. h, s, l = self.__hsl
  1413. if mode == 'ryb': h = Color.RgbToRyb(h)
  1414. h = (h+180)%360
  1415. if mode == 'ryb': h = Color.RybToRgb(h)
  1416. return Color((h, s, l), 'hsl', self.__a, self.__wref)
  1417. def MonochromeScheme(self):
  1418. '''Return 4 colors in the same hue with varying saturation/lightness.
  1419. Returns:
  1420. A tuple of 4 grapefruit.Color in the same hue as this one,
  1421. with varying saturation/lightness.
  1422. >>> c = Color.NewFromHsl(30, 0.5, 0.5)
  1423. >>> ['(%g, %g, %g)' % clr.hsl for clr in c.MonochromeScheme()]
  1424. ['(30, 0.2, 0.8)', '(30, 0.5, 0.3)', '(30, 0.2, 0.6)', '(30, 0.5, 0.8)']
  1425. '''
  1426. def _wrap(x, min, thres, plus):
  1427. if (x-min) < thres: return x + plus
  1428. else: return x-min
  1429. h, s, l = self.__hsl
  1430. s1 = _wrap(s, 0.3, 0.1, 0.3)
  1431. l1 = _wrap(l, 0.5, 0.2, 0.3)
  1432. s2 = s
  1433. l2 = _wrap(l, 0.2, 0.2, 0.6)
  1434. s3 = s1
  1435. l3 = max(0.2, l + (1-l)*0.2)
  1436. s4 = s
  1437. l4 = _wrap(l, 0.5, 0.2, 0.3)
  1438. return (
  1439. Color((h, s1, l1), 'hsl', self.__a, self.__wref),
  1440. Color((h, s2, l2), 'hsl', self.__a, self.__wref),
  1441. Color((h, s3, l3), 'hsl', self.__a, self.__wref),
  1442. Color((h, s4, l4), 'hsl', self.__a, self.__wref))
  1443. def TriadicScheme(self, angle=120, mode='ryb'):
  1444. '''Return two colors forming a triad or a split complementary with this one.
  1445. Parameters:
  1446. :angle:
  1447. The angle between the hues of the created colors.
  1448. The default value makes a triad.
  1449. :mode:
  1450. Select which color wheel to use for the generation (ryb/rgb).
  1451. Returns:
  1452. A tuple of two grapefruit.Color forming a color triad with
  1453. this one or a split complementary.
  1454. >>> c1 = Color.NewFromHsl(30, 1, 0.5)
  1455. >>> c2, c3 = c1.TriadicScheme()
  1456. >>> c2.hsl
  1457. (150.0, 1, 0.5)
  1458. >>> c3.hsl
  1459. (270.0, 1, 0.5)
  1460. >>> c2, c3 = c1.TriadicScheme(40)
  1461. >>> c2.hsl
  1462. (190.0, 1, 0.5)
  1463. >>> c3.hsl
  1464. (230.0, 1, 0.5)
  1465. '''
  1466. h, s, l = self.__hsl
  1467. angle = min(angle, 120) / 2.0
  1468. if mode == 'ryb': h = Color.RgbToRyb(h)
  1469. h += 180
  1470. h1 = (h - angle) % 360
  1471. h2 = (h + angle) % 360
  1472. if mode == 'ryb':
  1473. h1 = Color.RybToRgb(h1)
  1474. h2 = Color.RybToRgb(h2)
  1475. return (
  1476. Color((h1, s, l), 'hsl', self.__a, self.__wref),
  1477. Color((h2, s, l), 'hsl', self.__a, self.__wref))
  1478. def TetradicScheme(self, angle=30, mode='ryb'):
  1479. '''Return three colors froming a tetrad with this one.
  1480. Parameters:
  1481. :angle:
  1482. The angle to substract from the adjacent colors hues [-90...90].
  1483. You can use an angle of zero to generate a square tetrad.
  1484. :mode:
  1485. Select which color wheel to use for the generation (ryb/rgb).
  1486. Returns:
  1487. A tuple of three grapefruit.Color forming a color tetrad with
  1488. this one.
  1489. >>> col = Color.NewFromHsl(30, 1, 0.5)
  1490. >>> [c.hsl for c in col.TetradicScheme(mode='rgb', angle=30)]
  1491. [(90, 1, 0.5), (210, 1, 0.5), (270, 1, 0.5)]
  1492. '''
  1493. h, s, l = self.__hsl
  1494. if mode == 'ryb': h = Color.RgbToRyb(h)
  1495. h1 = (h + 90 - angle) % 360
  1496. h2 = (h + 180) % 360
  1497. h3 = (h + 270 - angle) % 360
  1498. if mode == 'ryb':
  1499. h1 = Color.RybToRgb(h1)
  1500. h2 = Color.RybToRgb(h2)
  1501. h3 = Color.RybToRgb(h3)
  1502. return (
  1503. Color((h1, s, l), 'hsl', self.__a, self.__wref),
  1504. Color((h2, s, l), 'hsl', self.__a, self.__wref),
  1505. Color((h3, s, l), 'hsl', self.__a, self.__wref))
  1506. def AnalogousScheme(self, angle=30, mode='ryb'):
  1507. '''Return two colors analogous to this one.
  1508. Args:
  1509. :angle:
  1510. The angle between the hues of the created colors and this one.
  1511. :mode:
  1512. Select which color wheel to use for the generation (ryb/rgb).
  1513. Returns:
  1514. A tuple of grapefruit.Colors analogous to this one.
  1515. >>> c1 = Color.NewFromHsl(30, 1, 0.5)
  1516. >>> c2, c3 = c1.AnalogousScheme()
  1517. >>> c2.hsl
  1518. (330, 1, 0.5)
  1519. >>> c3.hsl
  1520. (90, 1, 0.5)
  1521. >>> c2, c3 = c1.AnalogousScheme(10)
  1522. >>> c2.hsl
  1523. (20, 1, 0.5)
  1524. >>> c3.hsl
  1525. (40, 1, 0.5)
  1526. '''
  1527. h, s, l = self.__hsl
  1528. if mode == 'ryb': h = Color.RgbToRyb(h)
  1529. h += 360
  1530. h1 = (h - angle) % 360
  1531. h2 = (h + angle) % 360
  1532. if mode == 'ryb':
  1533. h1 = Color.RybToRgb(h1)
  1534. h2 = Color.RybToRgb(h2)
  1535. return (Color((h1, s, l), 'hsl', self.__a, self.__wref),
  1536. Color((h2, s, l), 'hsl', self.__a, self.__wref))
  1537. def AlphaBlend(self, other):
  1538. '''Alpha-blend this color on the other one.
  1539. Args:
  1540. :other:
  1541. The grapefruit.Color to alpha-blend with this one.
  1542. Returns:
  1543. A grapefruit.Color instance which is the result of alpha-blending
  1544. this color on the other one.
  1545. >>> c1 = Color.NewFromRgb(1, 0.5, 0, 0.2)
  1546. >>> c2 = Color.NewFromRgb(1, 1, 1, 0.8)
  1547. >>> c3 = c1.AlphaBlend(c2)
  1548. >>> str(c3)
  1549. '(1, 0.875, 0.75, 0.84)'
  1550. '''
  1551. # get final alpha channel
  1552. fa = self.__a + other.__a - (self.__a * other.__a)
  1553. # get percentage of source alpha compared to final alpha
  1554. if fa==0: sa = 0
  1555. else: sa = min(1.0, self.__a/other.__a)
  1556. # destination percentage is just the additive inverse
  1557. da = 1.0 - sa
  1558. sr, sg, sb = [v * sa for v in self.__rgb]
  1559. dr, dg, db = [v * da for v in other.__rgb]
  1560. return Color((sr+dr, sg+dg, sb+db), 'rgb', fa, self.__wref)
  1561. def Blend(self, other, percent=0.5):
  1562. '''Blend this color with the other one.
  1563. Args:
  1564. :other:
  1565. the grapefruit.Color to blend with this one.
  1566. Returns:
  1567. A grapefruit.Color instance which is the result of blending
  1568. this color on the other one.
  1569. >>> c1 = Color.NewFromRgb(1, 0.5, 0, 0.2)
  1570. >>> c2 = Color.NewFromRgb(1, 1, 1, 0.6)
  1571. >>> c3 = c1.Blend(c2)
  1572. >>> str(c3)
  1573. '(1, 0.75, 0.5, 0.4)'
  1574. '''
  1575. dest = 1.0 - percent
  1576. rgb = tuple(((u * percent) + (v * dest) for u, v in zip(self.__rgb, other.__rgb)))
  1577. a = (self.__a * percent) + (other.__a * dest)
  1578. return Color(rgb, 'rgb', a, self.__wref)
  1579. def _test():
  1580. import doctest
  1581. reload(doctest)
  1582. doctest.testmod()
  1583. if __name__=='__main__':
  1584. _test()