colors.nim 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. #
  2. # Nim's Runtime Library
  3. # (c) Copyright 2010 Andreas Rumpf
  4. #
  5. # See the file "copying.txt", included in this
  6. # distribution, for details about the copyright.
  7. #
  8. ## This module implements color handling for Nim.
  9. import strutils
  10. from algorithm import binarySearch
  11. type
  12. Color* = distinct int ## A color stored as RGB, e.g. `0xff00cc`.
  13. proc `==` *(a, b: Color): bool {.borrow.}
  14. ## Compares two colors.
  15. ##
  16. ## .. code-block::
  17. ## var
  18. ## a = Color(0xff_00_ff)
  19. ## b = colFuchsia
  20. ## c = Color(0x00_ff_cc)
  21. ## assert a == b
  22. ## assert not a == c
  23. template extract(a: Color, r, g, b: untyped) =
  24. var r = a.int shr 16 and 0xff
  25. var g = a.int shr 8 and 0xff
  26. var b = a.int and 0xff
  27. template rawRGB(r, g, b: int): Color =
  28. Color(r shl 16 or g shl 8 or b)
  29. template colorOp(op): Color =
  30. extract(a, ar, ag, ab)
  31. extract(b, br, bg, bb)
  32. rawRGB(op(ar, br), op(ag, bg), op(ab, bb))
  33. proc satPlus(a, b: int): int {.inline.} =
  34. result = a +% b
  35. if result > 255: result = 255
  36. proc satMinus(a, b: int): int {.inline.} =
  37. result = a -% b
  38. if result < 0: result = 0
  39. proc `+`*(a, b: Color): Color =
  40. ## Adds two colors.
  41. ##
  42. ## This uses saturated arithmetic, so that each color
  43. ## component cannot overflow (255 is used as a maximum).
  44. ##
  45. runnableExamples:
  46. var
  47. a = Color(0xaa_00_ff)
  48. b = Color(0x11_cc_cc)
  49. assert a + b == Color(0xbb_cc_ff)
  50. colorOp(satPlus)
  51. proc `-`*(a, b: Color): Color =
  52. ## Subtracts two colors.
  53. ##
  54. ## This uses saturated arithmetic, so that each color
  55. ## component cannot underflow (0 is used as a minimum).
  56. ##
  57. runnableExamples:
  58. var
  59. a = Color(0xff_33_ff)
  60. b = Color(0x11_ff_cc)
  61. assert a - b == Color(0xee_00_33)
  62. colorOp(satMinus)
  63. proc extractRGB*(a: Color): tuple[r, g, b: range[0..255]] =
  64. ## Extracts the red/green/blue components of the color `a`.
  65. ##
  66. runnableExamples:
  67. var
  68. a = Color(0xff_00_ff)
  69. b = Color(0x00_ff_cc)
  70. type
  71. Col = range[0..255]
  72. # assert extractRGB(a) == (r: 255.Col, g: 0.Col, b: 255.Col)
  73. # assert extractRGB(b) == (r: 0.Col, g: 255.Col, b: 204.Col)
  74. echo extractRGB(a)
  75. echo typeof(extractRGB(a))
  76. echo extractRGB(b)
  77. echo typeof(extractRGB(b))
  78. result.r = a.int shr 16 and 0xff
  79. result.g = a.int shr 8 and 0xff
  80. result.b = a.int and 0xff
  81. proc intensity*(a: Color, f: float): Color =
  82. ## Returns `a` with intensity `f`. `f` should be a float from 0.0 (completely
  83. ## dark) to 1.0 (full color intensity).
  84. ##
  85. runnableExamples:
  86. var
  87. a = Color(0xff_00_ff)
  88. b = Color(0x00_42_cc)
  89. assert a.intensity(0.5) == Color(0x80_00_80)
  90. assert b.intensity(0.5) == Color(0x00_21_66)
  91. var r = toInt(toFloat(a.int shr 16 and 0xff) * f)
  92. var g = toInt(toFloat(a.int shr 8 and 0xff) * f)
  93. var b = toInt(toFloat(a.int and 0xff) * f)
  94. if r >% 255: r = 255
  95. if g >% 255: g = 255
  96. if b >% 255: b = 255
  97. result = rawRGB(r, g, b)
  98. template mix*(a, b: Color, fn: untyped): untyped =
  99. ## Uses `fn` to mix the colors `a` and `b`.
  100. ##
  101. ## `fn` is invoked for each component R, G, and B.
  102. ## If `fn`'s result is not in the `range[0..255]`,
  103. ## it will be saturated to be so.
  104. ##
  105. runnableExamples:
  106. var
  107. a = Color(0x0a2814)
  108. b = Color(0x050a03)
  109. proc myMix(x, y: int): int =
  110. 2 * x - 3 * y
  111. assert mix(a, b, myMix) == Color(0x05_32_1f)
  112. template `><` (x: untyped): untyped =
  113. # keep it in the range 0..255
  114. block:
  115. var y = x # eval only once
  116. if y >% 255:
  117. y = if y < 0: 0 else: 255
  118. y
  119. extract(a, ar, ag, ab)
  120. extract(b, br, bg, bb)
  121. rawRGB(><fn(ar, br), ><fn(ag, bg), ><fn(ab, bb))
  122. const
  123. colAliceBlue* = Color(0xF0F8FF)
  124. colAntiqueWhite* = Color(0xFAEBD7)
  125. colAqua* = Color(0x00FFFF)
  126. colAquamarine* = Color(0x7FFFD4)
  127. colAzure* = Color(0xF0FFFF)
  128. colBeige* = Color(0xF5F5DC)
  129. colBisque* = Color(0xFFE4C4)
  130. colBlack* = Color(0x000000)
  131. colBlanchedAlmond* = Color(0xFFEBCD)
  132. colBlue* = Color(0x0000FF)
  133. colBlueViolet* = Color(0x8A2BE2)
  134. colBrown* = Color(0xA52A2A)
  135. colBurlyWood* = Color(0xDEB887)
  136. colCadetBlue* = Color(0x5F9EA0)
  137. colChartreuse* = Color(0x7FFF00)
  138. colChocolate* = Color(0xD2691E)
  139. colCoral* = Color(0xFF7F50)
  140. colCornflowerBlue* = Color(0x6495ED)
  141. colCornsilk* = Color(0xFFF8DC)
  142. colCrimson* = Color(0xDC143C)
  143. colCyan* = Color(0x00FFFF)
  144. colDarkBlue* = Color(0x00008B)
  145. colDarkCyan* = Color(0x008B8B)
  146. colDarkGoldenRod* = Color(0xB8860B)
  147. colDarkGray* = Color(0xA9A9A9)
  148. colDarkGreen* = Color(0x006400)
  149. colDarkKhaki* = Color(0xBDB76B)
  150. colDarkMagenta* = Color(0x8B008B)
  151. colDarkOliveGreen* = Color(0x556B2F)
  152. colDarkorange* = Color(0xFF8C00)
  153. colDarkOrchid* = Color(0x9932CC)
  154. colDarkRed* = Color(0x8B0000)
  155. colDarkSalmon* = Color(0xE9967A)
  156. colDarkSeaGreen* = Color(0x8FBC8F)
  157. colDarkSlateBlue* = Color(0x483D8B)
  158. colDarkSlateGray* = Color(0x2F4F4F)
  159. colDarkTurquoise* = Color(0x00CED1)
  160. colDarkViolet* = Color(0x9400D3)
  161. colDeepPink* = Color(0xFF1493)
  162. colDeepSkyBlue* = Color(0x00BFFF)
  163. colDimGray* = Color(0x696969)
  164. colDodgerBlue* = Color(0x1E90FF)
  165. colFireBrick* = Color(0xB22222)
  166. colFloralWhite* = Color(0xFFFAF0)
  167. colForestGreen* = Color(0x228B22)
  168. colFuchsia* = Color(0xFF00FF)
  169. colGainsboro* = Color(0xDCDCDC)
  170. colGhostWhite* = Color(0xF8F8FF)
  171. colGold* = Color(0xFFD700)
  172. colGoldenRod* = Color(0xDAA520)
  173. colGray* = Color(0x808080)
  174. colGreen* = Color(0x008000)
  175. colGreenYellow* = Color(0xADFF2F)
  176. colHoneyDew* = Color(0xF0FFF0)
  177. colHotPink* = Color(0xFF69B4)
  178. colIndianRed* = Color(0xCD5C5C)
  179. colIndigo* = Color(0x4B0082)
  180. colIvory* = Color(0xFFFFF0)
  181. colKhaki* = Color(0xF0E68C)
  182. colLavender* = Color(0xE6E6FA)
  183. colLavenderBlush* = Color(0xFFF0F5)
  184. colLawnGreen* = Color(0x7CFC00)
  185. colLemonChiffon* = Color(0xFFFACD)
  186. colLightBlue* = Color(0xADD8E6)
  187. colLightCoral* = Color(0xF08080)
  188. colLightCyan* = Color(0xE0FFFF)
  189. colLightGoldenRodYellow* = Color(0xFAFAD2)
  190. colLightGrey* = Color(0xD3D3D3)
  191. colLightGreen* = Color(0x90EE90)
  192. colLightPink* = Color(0xFFB6C1)
  193. colLightSalmon* = Color(0xFFA07A)
  194. colLightSeaGreen* = Color(0x20B2AA)
  195. colLightSkyBlue* = Color(0x87CEFA)
  196. colLightSlateGray* = Color(0x778899)
  197. colLightSteelBlue* = Color(0xB0C4DE)
  198. colLightYellow* = Color(0xFFFFE0)
  199. colLime* = Color(0x00FF00)
  200. colLimeGreen* = Color(0x32CD32)
  201. colLinen* = Color(0xFAF0E6)
  202. colMagenta* = Color(0xFF00FF)
  203. colMaroon* = Color(0x800000)
  204. colMediumAquaMarine* = Color(0x66CDAA)
  205. colMediumBlue* = Color(0x0000CD)
  206. colMediumOrchid* = Color(0xBA55D3)
  207. colMediumPurple* = Color(0x9370D8)
  208. colMediumSeaGreen* = Color(0x3CB371)
  209. colMediumSlateBlue* = Color(0x7B68EE)
  210. colMediumSpringGreen* = Color(0x00FA9A)
  211. colMediumTurquoise* = Color(0x48D1CC)
  212. colMediumVioletRed* = Color(0xC71585)
  213. colMidnightBlue* = Color(0x191970)
  214. colMintCream* = Color(0xF5FFFA)
  215. colMistyRose* = Color(0xFFE4E1)
  216. colMoccasin* = Color(0xFFE4B5)
  217. colNavajoWhite* = Color(0xFFDEAD)
  218. colNavy* = Color(0x000080)
  219. colOldLace* = Color(0xFDF5E6)
  220. colOlive* = Color(0x808000)
  221. colOliveDrab* = Color(0x6B8E23)
  222. colOrange* = Color(0xFFA500)
  223. colOrangeRed* = Color(0xFF4500)
  224. colOrchid* = Color(0xDA70D6)
  225. colPaleGoldenRod* = Color(0xEEE8AA)
  226. colPaleGreen* = Color(0x98FB98)
  227. colPaleTurquoise* = Color(0xAFEEEE)
  228. colPaleVioletRed* = Color(0xD87093)
  229. colPapayaWhip* = Color(0xFFEFD5)
  230. colPeachPuff* = Color(0xFFDAB9)
  231. colPeru* = Color(0xCD853F)
  232. colPink* = Color(0xFFC0CB)
  233. colPlum* = Color(0xDDA0DD)
  234. colPowderBlue* = Color(0xB0E0E6)
  235. colPurple* = Color(0x800080)
  236. colRed* = Color(0xFF0000)
  237. colRosyBrown* = Color(0xBC8F8F)
  238. colRoyalBlue* = Color(0x4169E1)
  239. colSaddleBrown* = Color(0x8B4513)
  240. colSalmon* = Color(0xFA8072)
  241. colSandyBrown* = Color(0xF4A460)
  242. colSeaGreen* = Color(0x2E8B57)
  243. colSeaShell* = Color(0xFFF5EE)
  244. colSienna* = Color(0xA0522D)
  245. colSilver* = Color(0xC0C0C0)
  246. colSkyBlue* = Color(0x87CEEB)
  247. colSlateBlue* = Color(0x6A5ACD)
  248. colSlateGray* = Color(0x708090)
  249. colSnow* = Color(0xFFFAFA)
  250. colSpringGreen* = Color(0x00FF7F)
  251. colSteelBlue* = Color(0x4682B4)
  252. colTan* = Color(0xD2B48C)
  253. colTeal* = Color(0x008080)
  254. colThistle* = Color(0xD8BFD8)
  255. colTomato* = Color(0xFF6347)
  256. colTurquoise* = Color(0x40E0D0)
  257. colViolet* = Color(0xEE82EE)
  258. colWheat* = Color(0xF5DEB3)
  259. colWhite* = Color(0xFFFFFF)
  260. colWhiteSmoke* = Color(0xF5F5F5)
  261. colYellow* = Color(0xFFFF00)
  262. colYellowGreen* = Color(0x9ACD32)
  263. colorNames = [
  264. ("aliceblue", colAliceBlue),
  265. ("antiquewhite", colAntiqueWhite),
  266. ("aqua", colAqua),
  267. ("aquamarine", colAquamarine),
  268. ("azure", colAzure),
  269. ("beige", colBeige),
  270. ("bisque", colBisque),
  271. ("black", colBlack),
  272. ("blanchedalmond", colBlanchedAlmond),
  273. ("blue", colBlue),
  274. ("blueviolet", colBlueViolet),
  275. ("brown", colBrown),
  276. ("burlywood", colBurlyWood),
  277. ("cadetblue", colCadetBlue),
  278. ("chartreuse", colChartreuse),
  279. ("chocolate", colChocolate),
  280. ("coral", colCoral),
  281. ("cornflowerblue", colCornflowerBlue),
  282. ("cornsilk", colCornsilk),
  283. ("crimson", colCrimson),
  284. ("cyan", colCyan),
  285. ("darkblue", colDarkBlue),
  286. ("darkcyan", colDarkCyan),
  287. ("darkgoldenrod", colDarkGoldenRod),
  288. ("darkgray", colDarkGray),
  289. ("darkgreen", colDarkGreen),
  290. ("darkkhaki", colDarkKhaki),
  291. ("darkmagenta", colDarkMagenta),
  292. ("darkolivegreen", colDarkOliveGreen),
  293. ("darkorange", colDarkorange),
  294. ("darkorchid", colDarkOrchid),
  295. ("darkred", colDarkRed),
  296. ("darksalmon", colDarkSalmon),
  297. ("darkseagreen", colDarkSeaGreen),
  298. ("darkslateblue", colDarkSlateBlue),
  299. ("darkslategray", colDarkSlateGray),
  300. ("darkturquoise", colDarkTurquoise),
  301. ("darkviolet", colDarkViolet),
  302. ("deeppink", colDeepPink),
  303. ("deepskyblue", colDeepSkyBlue),
  304. ("dimgray", colDimGray),
  305. ("dodgerblue", colDodgerBlue),
  306. ("firebrick", colFireBrick),
  307. ("floralwhite", colFloralWhite),
  308. ("forestgreen", colForestGreen),
  309. ("fuchsia", colFuchsia),
  310. ("gainsboro", colGainsboro),
  311. ("ghostwhite", colGhostWhite),
  312. ("gold", colGold),
  313. ("goldenrod", colGoldenRod),
  314. ("gray", colGray),
  315. ("green", colGreen),
  316. ("greenyellow", colGreenYellow),
  317. ("honeydew", colHoneyDew),
  318. ("hotpink", colHotPink),
  319. ("indianred", colIndianRed),
  320. ("indigo", colIndigo),
  321. ("ivory", colIvory),
  322. ("khaki", colKhaki),
  323. ("lavender", colLavender),
  324. ("lavenderblush", colLavenderBlush),
  325. ("lawngreen", colLawnGreen),
  326. ("lemonchiffon", colLemonChiffon),
  327. ("lightblue", colLightBlue),
  328. ("lightcoral", colLightCoral),
  329. ("lightcyan", colLightCyan),
  330. ("lightgoldenrodyellow", colLightGoldenRodYellow),
  331. ("lightgrey", colLightGrey),
  332. ("lightgreen", colLightGreen),
  333. ("lightpink", colLightPink),
  334. ("lightsalmon", colLightSalmon),
  335. ("lightseagreen", colLightSeaGreen),
  336. ("lightskyblue", colLightSkyBlue),
  337. ("lightslategray", colLightSlateGray),
  338. ("lightsteelblue", colLightSteelBlue),
  339. ("lightyellow", colLightYellow),
  340. ("lime", colLime),
  341. ("limegreen", colLimeGreen),
  342. ("linen", colLinen),
  343. ("magenta", colMagenta),
  344. ("maroon", colMaroon),
  345. ("mediumaquamarine", colMediumAquaMarine),
  346. ("mediumblue", colMediumBlue),
  347. ("mediumorchid", colMediumOrchid),
  348. ("mediumpurple", colMediumPurple),
  349. ("mediumseagreen", colMediumSeaGreen),
  350. ("mediumslateblue", colMediumSlateBlue),
  351. ("mediumspringgreen", colMediumSpringGreen),
  352. ("mediumturquoise", colMediumTurquoise),
  353. ("mediumvioletred", colMediumVioletRed),
  354. ("midnightblue", colMidnightBlue),
  355. ("mintcream", colMintCream),
  356. ("mistyrose", colMistyRose),
  357. ("moccasin", colMoccasin),
  358. ("navajowhite", colNavajoWhite),
  359. ("navy", colNavy),
  360. ("oldlace", colOldLace),
  361. ("olive", colOlive),
  362. ("olivedrab", colOliveDrab),
  363. ("orange", colOrange),
  364. ("orangered", colOrangeRed),
  365. ("orchid", colOrchid),
  366. ("palegoldenrod", colPaleGoldenRod),
  367. ("palegreen", colPaleGreen),
  368. ("paleturquoise", colPaleTurquoise),
  369. ("palevioletred", colPaleVioletRed),
  370. ("papayawhip", colPapayaWhip),
  371. ("peachpuff", colPeachPuff),
  372. ("peru", colPeru),
  373. ("pink", colPink),
  374. ("plum", colPlum),
  375. ("powderblue", colPowderBlue),
  376. ("purple", colPurple),
  377. ("red", colRed),
  378. ("rosybrown", colRosyBrown),
  379. ("royalblue", colRoyalBlue),
  380. ("saddlebrown", colSaddleBrown),
  381. ("salmon", colSalmon),
  382. ("sandybrown", colSandyBrown),
  383. ("seagreen", colSeaGreen),
  384. ("seashell", colSeaShell),
  385. ("sienna", colSienna),
  386. ("silver", colSilver),
  387. ("skyblue", colSkyBlue),
  388. ("slateblue", colSlateBlue),
  389. ("slategray", colSlateGray),
  390. ("snow", colSnow),
  391. ("springgreen", colSpringGreen),
  392. ("steelblue", colSteelBlue),
  393. ("tan", colTan),
  394. ("teal", colTeal),
  395. ("thistle", colThistle),
  396. ("tomato", colTomato),
  397. ("turquoise", colTurquoise),
  398. ("violet", colViolet),
  399. ("wheat", colWheat),
  400. ("white", colWhite),
  401. ("whitesmoke", colWhiteSmoke),
  402. ("yellow", colYellow),
  403. ("yellowgreen", colYellowGreen)]
  404. proc `$`*(c: Color): string =
  405. ## Converts a color into its textual representation.
  406. ##
  407. runnableExamples:
  408. assert $colFuchsia == "#FF00FF"
  409. result = '#' & toHex(int(c), 6)
  410. proc colorNameCmp(x: tuple[name: string, col: Color], y: string): int =
  411. result = cmpIgnoreCase(x.name, y)
  412. proc parseColor*(name: string): Color =
  413. ## Parses `name` to a color value.
  414. ##
  415. ## If no valid color could be parsed `ValueError` is raised.
  416. ## Case insensitive.
  417. ##
  418. runnableExamples:
  419. var
  420. a = "silver"
  421. b = "#0179fc"
  422. c = "#zzmmtt"
  423. assert parseColor(a) == Color(0xc0_c0_c0)
  424. assert parseColor(b) == Color(0x01_79_fc)
  425. doAssertRaises(ValueError): discard parseColor(c)
  426. if name.len > 0 and name[0] == '#':
  427. result = Color(parseHexInt(name))
  428. else:
  429. var idx = binarySearch(colorNames, name, colorNameCmp)
  430. if idx < 0: raise newException(ValueError, "unknown color: " & name)
  431. result = colorNames[idx][1]
  432. proc isColor*(name: string): bool =
  433. ## Returns true if `name` is a known color name or a hexadecimal color
  434. ## prefixed with `#`. Case insensitive.
  435. ##
  436. runnableExamples:
  437. var
  438. a = "silver"
  439. b = "#0179fc"
  440. c = "#zzmmtt"
  441. assert a.isColor
  442. assert b.isColor
  443. assert not c.isColor
  444. if name.len == 0: return false
  445. if name[0] == '#':
  446. for i in 1 .. name.len-1:
  447. if name[i] notin HexDigits: return false
  448. result = true
  449. else:
  450. result = binarySearch(colorNames, name, colorNameCmp) >= 0
  451. proc rgb*(r, g, b: range[0..255]): Color =
  452. ## Constructs a color from RGB values.
  453. ##
  454. runnableExamples:
  455. assert rgb(0, 255, 128) == Color(0x00_ff_80)
  456. result = rawRGB(r, g, b)