置顶公告:【置顶】关于临时开启评论区所有功能的公告(2022.10.22) | 【置顶】关于本站Widget恢复使用的公告
  • 你好~!欢迎来到萌娘百科镜像站!如需查看或编辑,请联系本站管理员注册账号。
  • 本镜像站和其他萌娘百科的镜像站无关,请注意分别。

Module:Color

猛汉♂百科,万男皆可猛的百科全书!转载请标注来源页面的网页链接,并声明引自猛汉百科。内容不可商用。
跳到导航 跳到搜索
Template-info.svg 模块文档  [创建] [刷新]
  1. -- 该模块主要用于操作颜色。
  2. local colorKeywords = {
  3. aliceblue = { 240, 248, 255 },
  4. antiquewhite = { 250, 235, 215 },
  5. aqua = { 0, 255, 255 },
  6. aquamarine = { 127, 255, 212 },
  7. azure = { 240, 255, 255 },
  8. beige = { 245, 245, 220 },
  9. bisque = { 255, 228, 196 },
  10. black = { 0, 0, 0 },
  11. blanchedalmond = { 255, 235, 205 },
  12. blue = { 0, 0, 255 },
  13. blueviolet = { 138, 43, 226 },
  14. brown = { 165, 42, 42 },
  15. burlywood = { 222, 184, 135 },
  16. cadetblue = { 95, 158, 160 },
  17. chartreuse = { 127, 255, 0 },
  18. chocolate = { 210, 105, 30 },
  19. coral = { 255, 127, 80 },
  20. cornflowerblue = { 100, 149, 237 },
  21. cornsilk = { 255, 248, 220 },
  22. crimson = { 220, 20, 60 },
  23. cyan = { 0, 255, 255 },
  24. darkblue = { 0, 0, 139 },
  25. darkcyan = { 0, 139, 139 },
  26. darkgoldenrod = { 184, 134, 11 },
  27. darkgray = { 169, 169, 169 },
  28. darkgreen = { 0, 100, 0 },
  29. darkgrey = { 169, 169, 169 },
  30. darkkhaki = { 189, 183, 107 },
  31. darkmagenta = { 139, 0, 139 },
  32. darkolivegreen = { 85, 107, 47 },
  33. darkorange = { 255, 140, 0 },
  34. darkorchid = { 153, 50, 204 },
  35. darkred = { 139, 0, 0 },
  36. darksalmon = { 233, 150, 122 },
  37. darkseagreen = { 143, 188, 143 },
  38. darkslateblue = { 72, 61, 139 },
  39. darkslategray = { 47, 79, 79 },
  40. darkslategrey = { 47, 79, 79 },
  41. darkturquoise = { 0, 206, 209 },
  42. darkviolet = { 148, 0, 211 },
  43. deeppink = { 255, 20, 147 },
  44. deepskyblue = { 0, 191, 255 },
  45. dimgray = { 105, 105, 105 },
  46. dimgrey = { 105, 105, 105 },
  47. dodgerblue = { 30, 144, 255 },
  48. firebrick = { 178, 34, 34 },
  49. floralwhite = { 255, 250, 240 },
  50. forestgreen = { 34, 139, 34 },
  51. fuchsia = { 255, 0, 255 },
  52. gainsboro = { 220, 220, 220 },
  53. ghostwhite = { 248, 248, 255 },
  54. gold = { 255, 215, 0 },
  55. goldenrod = { 218, 165, 32 },
  56. gray = { 128, 128, 128 },
  57. green = { 0, 128, 0 },
  58. greenyellow = { 173, 255, 47 },
  59. grey = { 128, 128, 128 },
  60. honeydew = { 240, 255, 240 },
  61. hotpink = { 255, 105, 180 },
  62. indianred = { 205, 92, 92 },
  63. indigo = { 75, 0, 130 },
  64. ivory = { 255, 255, 240 },
  65. khaki = { 240, 230, 140 },
  66. lavender = { 230, 230, 250 },
  67. lavenderblush = { 255, 240, 245 },
  68. lawngreen = { 124, 252, 0 },
  69. lemonchiffon = { 255, 250, 205 },
  70. lightblue = { 173, 216, 230 },
  71. lightcoral = { 240, 128, 128 },
  72. lightcyan = { 224, 255, 255 },
  73. lightgoldenrodyellow = { 250, 250, 210 },
  74. lightgray = { 211, 211, 211 },
  75. lightgreen = { 144, 238, 144 },
  76. lightgrey = { 211, 211, 211 },
  77. lightpink = { 255, 182, 193 },
  78. lightsalmon = { 255, 160, 122 },
  79. lightseagreen = { 32, 178, 170 },
  80. lightskyblue = { 135, 206, 250 },
  81. lightslategray = { 119, 136, 153 },
  82. lightslategrey = { 119, 136, 153 },
  83. lightsteelblue = { 176, 196, 222 },
  84. lightyellow = { 255, 255, 224 },
  85. lime = { 0, 255, 0 },
  86. limegreen = { 50, 205, 50 },
  87. linen = { 250, 240, 230 },
  88. magenta = { 255, 0, 255 },
  89. maroon = { 128, 0, 0 },
  90. mediumaquamarine = { 102, 205, 170 },
  91. mediumblue = { 0, 0, 205 },
  92. mediumorchid = { 186, 85, 211 },
  93. mediumpurple = { 147, 112, 219 },
  94. mediumseagreen = { 60, 179, 113 },
  95. mediumslateblue = { 123, 104, 238 },
  96. mediumspringgreen = { 0, 250, 154 },
  97. mediumturquoise = { 72, 209, 204 },
  98. mediumvioletred = { 199, 21, 133 },
  99. midnightblue = { 25, 25, 112 },
  100. mintcream = { 245, 255, 250 },
  101. mistyrose = { 255, 228, 225 },
  102. moccasin = { 255, 228, 181 },
  103. navajowhite = { 255, 222, 173 },
  104. navy = { 0, 0, 128 },
  105. oldlace = { 253, 245, 230 },
  106. olive = { 128, 128, 0 },
  107. olivedrab = { 107, 142, 35 },
  108. orange = { 255, 165, 0 },
  109. orangered = { 255, 69, 0 },
  110. orchid = { 218, 112, 214 },
  111. palegoldenrod = { 238, 232, 170 },
  112. palegreen = { 152, 251, 152 },
  113. paleturquoise = { 175, 238, 238 },
  114. palevioletred = { 219, 112, 147 },
  115. papayawhip = { 255, 239, 213 },
  116. peachpuff = { 255, 218, 185 },
  117. peru = { 205, 133, 63 },
  118. pink = { 255, 192, 203 },
  119. plum = { 221, 160, 221 },
  120. powderblue = { 176, 224, 230 },
  121. purple = { 128, 0, 128 },
  122. red = { 255, 0, 0 },
  123. rosybrown = { 188, 143, 143 },
  124. royalblue = { 65, 105, 225 },
  125. saddlebrown = { 139, 69, 19 },
  126. salmon = { 250, 128, 114 },
  127. sandybrown = { 244, 164, 96 },
  128. seagreen = { 46, 139, 87 },
  129. seashell = { 255, 245, 238 },
  130. sienna = { 160, 82, 45 },
  131. silver = { 192, 192, 192 },
  132. skyblue = { 135, 206, 235 },
  133. slateblue = { 106, 90, 205 },
  134. slategray = { 112, 128, 144 },
  135. slategrey = { 112, 128, 144 },
  136. snow = { 255, 250, 250 },
  137. springgreen = { 0, 255, 127 },
  138. steelblue = { 70, 130, 180 },
  139. tan = { 210, 180, 140 },
  140. teal = { 0, 128, 128 },
  141. thistle = { 216, 191, 216 },
  142. tomato = { 255, 99, 71 },
  143. turquoise = { 64, 224, 208 },
  144. violet = { 238, 130, 238 },
  145. wheat = { 245, 222, 179 },
  146. white = { 255, 255, 255 },
  147. whitesmoke = { 245, 245, 245 },
  148. yellow = { 255, 255, 0 },
  149. yellowgreen = { 154, 205, 50 },
  150. }
  151. local rgbRegex = '^rgb%(%s-(%d-),%s-(%d-)%s-,%s-(%d-)%s-%)$'
  152. local rgbaRegex = '^rgba%(%s-(%d-),%s-(%d-)%s-,%s-(%d-)%s-,%s-([%d%.]+)%s-%)$'
  153. local hslRegex = '^hsl%(%s-(%d-),%s-(%d-)%%%s-,%s-(%d-)%%%s-%)$'
  154. local hslaRegex = '^hsla%(%s-(%d-),%s-(%d-)%%%s-,%s-(%d-)%%%s-,%s-([%d%.]+)%s-%)$'
  155. local hexRegex = '^#(%x%x)(%x%x)(%x%x)$'
  156. local hexShorthandRegex = '^#(%x)(%x)(%x)$'
  157. --[[
  158. Color实例结构
  159. interface ColorInstance {
  160. __index = Color
  161. value: [number, number, number]
  162. format: 'rgb' | 'hsl'
  163. opacity: number
  164. }
  165. ]]
  166. local Color = {}
  167. local colorMetaTable = { __index = Color }
  168. --[[
  169. @param {number} min
  170. @param {number} max
  171. @return {number}
  172. ]]
  173. local function _random(min, max)
  174. return tonumber(mw.getCurrentFrame():expandTemplate{ title = 'random', args = { min, max } })
  175. end
  176. --[[
  177. @desc 操作颜色加深减淡
  178. @param {[number, number, number]} rgb
  179. @param {'+' | '-'} operator - 加深,减淡
  180. @param {number} ratio 范围:0 ~ 100
  181. @return {[number, number, number]}
  182. ]]
  183. local function _computeRgb(rgb, operator, ratio)
  184. local ranges = {}
  185. local cloneRgb = { rgb[1], rgb[2], rgb[3] }
  186. for i, v in ipairs(rgb) do
  187. ranges[i] = {
  188. ['-'] = (255 - v) / 100,
  189. ['+'] = -v / 100
  190. }
  191. end
  192. for i, v in ipairs(cloneRgb) do
  193. cloneRgb[i] = v + ranges[i][operator] * ratio
  194. if cloneRgb[i] < 0 then cloneRgb[i] = 0 end
  195. if cloneRgb[i] > 255 then cloneRgb[i] = 255 end
  196. end
  197. return cloneRgb
  198. end
  199. --[[
  200. @desc 判断一个字符串或table是否为合法的color值
  201. @param {(string | [number, number, number])} rawValue - 接受一个字符串或数组table,有效的格式有:css颜色关键字,hex颜色,hex简写颜色,rgb函数,rgba函数,hsl函数,hsla函数
  202. @return {boolean}
  203. ]]
  204. function Color.isColorStr(rawValue)
  205. if type(rawValue) == 'string' then
  206. if
  207. rawValue:match(rgbRegex) or
  208. rawValue:match(rgbaRegex) or
  209. rawValue:match(hslRegex) or
  210. rawValue:match(hslaRegex) or
  211. colorKeywords[rawValue]
  212. then return true end
  213. rawValue = mw.text.unstripNoWiki(rawValue)
  214. :gsub('^&#35;', '#') -- 为了避免解析器自动换行,一些返回颜色值的模板常用'<nowiki>#</nowiki>'或'&#35;'代替'#'
  215. :gsub('^#', '#') -- Bhsd加的全角字符兼容,不知道为啥
  216. if
  217. rawValue:match(hexRegex) or
  218. rawValue:match(hexShorthandRegex)
  219. then return true end
  220. elseif type(rawValue) == 'table' then
  221. if #rawValue ~= 3 and #rawValue ~= 4 then return false end
  222. for _, v in ipairs(rawValue) do
  223. if type(v) ~= 'number' then return false end
  224. end
  225. return true
  226. end
  227. return false
  228. end
  229. --[[
  230. @desc 创建一个Color实例
  231. @param {(string | [number, number, number])} rawValue - 接受一个字符串或数组table,有效的格式有:css颜色关键字,hex颜色,hex简写颜色,rgb函数,rgba函数,hsl函数,hsla函数
  232. @return {(Color | nil)} - 如果rawValue无效,则返回nil
  233. ]]
  234. function Color.create(rawValue)
  235. if not Color.isColorStr(rawValue) then return nil end
  236. if type(rawValue) == 'string' then
  237. rawValue = mw.text.unstripNoWiki(rawValue)
  238. :gsub('^&#35;', '#') -- 为了避免解析器自动换行,一些返回颜色值的模板常用'<nowiki>#</nowiki>'或'&#35;'代替'#'
  239. :gsub('^#', '#') -- Bhsd加的全角字符兼容,不知道为啥
  240. end
  241. local color = setmetatable({}, colorMetaTable)
  242. local r_h, g_s, b_l, opacity -- rgb or hsl
  243. if type(rawValue) == 'string' then
  244. if rawValue:match(rgbRegex) then
  245. color.format = 'rgb'
  246. r_h, g_s, b_l = rawValue:match(rgbRegex)
  247. r_h = tonumber(r_h)
  248. g_s = tonumber(g_s)
  249. b_l = tonumber(b_l)
  250. elseif rawValue:match(rgbaRegex) then
  251. color.format = 'rgb'
  252. r_h, g_s, b_l, opacity = rawValue:match(rgbaRegex)
  253. r_h = tonumber(r_h)
  254. g_s = tonumber(g_s)
  255. b_l = tonumber(b_l)
  256. opacity = tonumber(opacity)
  257. elseif rawValue:match(hslRegex) then
  258. color.format = 'hsl'
  259. r_h, g_s, b_l = rawValue:match(hslRegex)
  260. r_h = tonumber(r_h)
  261. g_s = tonumber(g_s)
  262. b_l = tonumber(b_l)
  263. elseif rawValue:match(hslaRegex) then
  264. color.format = 'hsl'
  265. r_h, g_s, b_l, opacity = rawValue:match(hslaRegex)
  266. r_h = tonumber(r_h)
  267. g_s = tonumber(g_s)
  268. b_l = tonumber(b_l)
  269. opacity = tonumber(opacity)
  270. elseif rawValue:match(hexRegex) then
  271. color.format = 'rgb'
  272. r_h, g_s, b_l = rawValue:match(hexRegex)
  273. r_h = tonumber(r_h, 16)
  274. g_s = tonumber(g_s, 16)
  275. b_l = tonumber(b_l, 16)
  276. elseif rawValue:match(hexShorthandRegex) then
  277. color.format = 'rgb'
  278. r_h, g_s, b_l = rawValue:match(hexShorthandRegex)
  279. r_h = tonumber(r_h, 16) * 17
  280. g_s = tonumber(g_s, 16) * 17
  281. b_l = tonumber(b_l, 16) * 17
  282. else
  283. color.format = 'rgb'
  284. local colorkeywordRgb = colorKeywords[rawValue]
  285. r_h = colorkeywordRgb[1]
  286. g_s = colorkeywordRgb[2]
  287. b_l = colorkeywordRgb[3]
  288. end
  289. elseif type(rawValue) == 'table' then
  290. color.format = 'rgb'
  291. r_h = rawValue[1]
  292. g_s = rawValue[2]
  293. b_l = rawValue[3]
  294. opacity = rawValue[4]
  295. end
  296. color.value = { r_h, g_s, b_l }
  297. color.opacity = opacity or 1
  298. return color
  299. end
  300. --[[
  301. @desc 克隆一个Color对象
  302. @param {Color} this
  303. @return {Color} - 一个新的Color对象
  304. ]]
  305. function Color.clone(this)
  306. local rgb = this:rgb().value
  307. return Color.create(rgb):setOpacity(this.opacity)
  308. end
  309. --[[
  310. @desc rgb转hsl
  311. @param {number} r
  312. @param {number} g
  313. @param {number} b
  314. @return [number, number, number] - 返回的所有值均为整数
  315. ]]
  316. function Color.rgb2hsl(r, g, b)
  317. r = r / 255
  318. g = g / 255
  319. b = b / 255
  320. local max = math.max(r, g, b)
  321. local min = math.min(r, g, b)
  322. local diff = max - min
  323. local h, s
  324. local l = (max + min) / 2
  325. if max == min then
  326. h = 0
  327. s = 0
  328. elseif max == r and g >= b then
  329. h = 60 * ((g - b) / diff)
  330. elseif max == r and g < b then
  331. h = 60 * ((g - b) / diff) + 360
  332. elseif max == g then
  333. h = 60 * ((b - r) / diff) + 120
  334. elseif max == b then
  335. h = 60 * ((r - g) / diff) + 240
  336. end
  337. if l == 0 or max == min then
  338. s = 0
  339. elseif 0 < 1 and l <= 0.5 then
  340. s = diff / (2 * l)
  341. elseif l > 0.5 then
  342. s = diff / (2 - 2 * l)
  343. end
  344. return {
  345. math.floor(h + 0.5),
  346. math.floor(s * 100 + 0.5),
  347. math.floor(l * 100 + 0.5)
  348. }
  349. end
  350. --[[
  351. @desc hsl转rgb
  352. @param {number} h
  353. @param {number} s - css中使用百分比,但该函数需要传整数 50% => 50
  354. @param {number} l - css中使用百分比,但该函数需要传整数 50% => 50
  355. @return [number, number, number]
  356. ]]
  357. function Color.hsl2rgb(h, s, l)
  358. h = h % 360
  359. s = s / 100
  360. l = l / 100
  361. local c = (1 - math.abs(2 * l - 1)) * s
  362. local x = c * (1 - math.abs(((h / 60) % 2) - 1))
  363. local m = l - c / 2
  364. local vRGB = {}
  365. if h >=0 and h < 60 then
  366. vRGB = {c, x, 0}
  367. elseif h >= 60 and h < 120 then
  368. vRGB = {x, c, 0}
  369. elseif h >= 120 and h < 180 then
  370. vRGB = {0, c, x}
  371. elseif h >= 180 and h < 240 then
  372. vRGB = {0, x, c}
  373. elseif h >= 240 and h < 300 then
  374. vRGB = {x, 0, c}
  375. elseif h >= 300 and h < 360 then
  376. vRGB = {c, 0, x}
  377. end
  378. local r = 255 * (vRGB[1] + m)
  379. local g = 255 * (vRGB[2] + m)
  380. local b = 255 * (vRGB[3] + m)
  381. return {
  382. math.floor(r + 0.5),
  383. math.floor(g + 0.5),
  384. math.floor(b + 0.5)
  385. }
  386. end
  387. --[[
  388. @desc 将color对象的数据转为rgb格式
  389. @param {Color} this
  390. @return {Color} - this
  391. ]]
  392. function Color.rgb(this)
  393. if this.format == 'rgb' then return this end
  394. if this.format == 'hsl' then
  395. this.value = Color.hsl2rgb(this.value[1], this.value[2], this.value[3])
  396. this.format = 'rgb'
  397. end
  398. return this
  399. end
  400. --[[
  401. @desc 将color对象的数据转为hsl格式
  402. @param {Color} this
  403. @return {Color} - this
  404. ]]
  405. function Color.hsl(this)
  406. if this.format == 'hsl' then return this end
  407. if this.format == 'rgb' then
  408. this.value = Color.rgb2hsl(this.value[1], this.value[2], this.value[3])
  409. this.format = 'hsl'
  410. end
  411. return this
  412. end
  413. --[[
  414. @desc 加深一个颜色(明度-)
  415. @param {Color} this
  416. @param {number} ratio - 范围:0 ~ 100
  417. @return {Color} - this
  418. ]]
  419. function Color.darken(this, ratio)
  420. local rgb = this:rgb().value
  421. this.value = _computeRgb(rgb, '+', ratio)
  422. return this
  423. end
  424. --[[
  425. @desc 减淡一个颜色(明度+)
  426. @param {Color} this
  427. @param {number} ratio - 范围:0 ~ 100
  428. @return {Color} - this
  429. ]]
  430. function Color.lighten(this, ratio)
  431. local rgb = this:rgb().value
  432. this.value = _computeRgb(rgb, '-', ratio)
  433. return this
  434. end
  435. --[[
  436. @desc 提高一个颜色的饱和度
  437. @param {Color} this
  438. @param {number} ratio - 范围:0 ~ 100
  439. @return {Color} - this
  440. ]]
  441. function Color.saturate(this, ratio)
  442. local hsl = this:hsl().value
  443. this.value[2] = hsl[2] + (100 - hsl[2]) * (ratio / 100)
  444. if this.value[2] > 100 then this.value[2] = 100 end
  445. return this
  446. end
  447. --[[
  448. @desc 降低一个颜色的饱和度
  449. @param {Color} this
  450. @param {number} ratio - 范围:0 ~ 100
  451. @return {Color} - this
  452. ]]
  453. function Color.desaturate(this, ratio)
  454. local hsl = this:hsl().value
  455. this.value[2] = hsl[2] - hsl[2] * (ratio / 100)
  456. if this.value[2] < 0 then this.value[2] = 0 end
  457. return this
  458. end
  459. --[[
  460. @desc 混合两个颜色
  461. @param {Color} this 颜色1
  462. @param {Color} color 颜色2
  463. @param {number} weight 颜色1比重 范围:0 ~ 100,默认值为50
  464. @return {Color} this
  465. ]]
  466. function Color.mix(this, color, weight)
  467. local color1 = this:rgb()
  468. local color2 = color:rgb()
  469. local p = weight == nil and 50 or weight
  470. p = p / 100
  471. local w = 2 * p - 1
  472. local a = color1.opacity - color2.opacity
  473. local w1 = (((w * a == -1) and w or (w + a) / (1 + w * a)) + 1) / 2.0
  474. local w2 = 1 - w1
  475. this.value = {
  476. w1 * color1.value[1] + w2 * color2.value[1],
  477. w1 * color1.value[2] + w2 * color2.value[2],
  478. w1 * color1.value[3] + w2 * color2.value[3]
  479. }
  480. this:setOpacity(color1.opacity * p + color2.opacity * (1 - p))
  481. return this
  482. end
  483. --[[
  484. @desc 设置一个值的不透明度
  485. @param {Color} this
  486. @param {number} value - 范围:0 ~ 1
  487. @return {Color} - this
  488. ]]
  489. function Color.setOpacity(this, value)
  490. this.opacity = tonumber(value)
  491. return this
  492. end
  493. --[[
  494. @desc Gamma校正
  495. @param {number} r_g_b
  496. @return {number}
  497. ]]
  498. local function adjustGamma(r_g_b)
  499. if r_g_b <= 0.04045 then return r_g_b / 12.92
  500. else return ((r_g_b + 0.055) / 1.055) ^ 2.4 end
  501. end
  502. --[[
  503. @desc 获得颜色的相对亮度
  504. @param {Color} this
  505. @return {number}
  506. ]]
  507. function Color.getRelativeLuminance(this)
  508. local rgb = this:rgb().value
  509. return 0.2126 * adjustGamma(rgb[1] / 255) +
  510. 0.7152 * adjustGamma(rgb[2] / 255) +
  511. 0.0722 * adjustGamma(rgb[3] / 255)
  512. end
  513. --[[
  514. @desc 获得两颜色的对比度比例
  515. @param {Color} this
  516. @param {Color} color
  517. @return {number}
  518. ]]
  519. function Color.getContrastRatio(this, color)
  520. local ratio = (this:getRelativeLuminance() + 0.05) / (color:getRelativeLuminance() + 0.05)
  521. if ratio < 1 then return 1 / ratio
  522. else return ratio end
  523. end
  524. --[[
  525. @desc 检测一个颜色是否为亮色
  526. @param {Color} this
  527. @return {boolean}
  528. ]]
  529. function Color.isLight(this)
  530. return this:getRelativeLuminance() > (0.05 * 1.05) ^ 0.5 - 0.05
  531. end
  532. --[[
  533. @desc 检测一个颜色是否为暗色
  534. @param {Color} this
  535. @return {boolean}
  536. ]]
  537. function Color.isDark(this)
  538. return this:isLight() == false
  539. end
  540. --[[
  541. @desc 根据范围随机产生一个颜色
  542. @param {number} [min = 0] - 范围:0 ~ 255
  543. @param {number} [max = 255] - 范围:0 ~ 255
  544. @return {Color}
  545. ]]
  546. function Color.random(min, max)
  547. min = min or 0
  548. max = max or 255
  549. local rgb = {
  550. _random(min, max),
  551. _random(min, max),
  552. _random(min, max)
  553. }
  554. return Color.create(rgb)
  555. end
  556. --[[
  557. @desc 反转一个颜色
  558. @param {Color} this
  559. @return {Color} - this
  560. ]]
  561. function Color.reverse(this)
  562. local rgb = this:rgb().value
  563. for i, v in ipairs(rgb) do
  564. rgb[i] = math.abs(v - 255)
  565. end
  566. return this
  567. end
  568. --[[
  569. @desc 将一个Color实例转化为有效的css颜色值字符串
  570. @param {Color} this
  571. @param {('auto' | 'hex' | 'hex-opacity')} [format = 'auto'] - 格式,
  572. 为auto时,根据Color对象本身的format进行转换,使用对应的css函数,并保留透明度。在调用前应该先执行rgb()或hsl(),以明确输出格式。
  573. 为hex时,返回hex颜色。无视透明度。
  574. 为hex-opacity时,返回hex颜色。若不透明度不为1,则假定背景为白色将透明度和颜色进行计算。
  575. ]]
  576. function Color.toString(this, format)
  577. local function toHex(num)
  578. local int, float = math.modf(num)
  579. if float > 0.4 then int = int + 1 end
  580. local zero = ''
  581. if int < 16 then zero = '0' end
  582. return zero..string.format('%X', int)
  583. end
  584. format = format or 'auto'
  585. if format == 'auto' then
  586. if this.format == 'rgb' then
  587. if this.opacity >= 0 and this.opacity < 1 then
  588. return 'rgba('..table.concat(this.value, ',')..','..this.opacity..')'
  589. else
  590. return 'rgb('..table.concat(this.value, ',')..')'
  591. end
  592. elseif this.format == 'hsl' then
  593. local hsl = this.value
  594. if this.opacity >= 0 and this.opacity < 1 then
  595. return string.format('hsla(%s, %s%%, %s%%, %s)', hsl[1], hsl[2], hsl[3], this.opacity)
  596. else
  597. return string.format('hsl(%s, %s%%, %s%%)', hsl[1], hsl[2], hsl[3])
  598. end
  599. end
  600. elseif format == 'hex' then
  601. this:rgb()
  602. return '#'..toHex(this.value[1])..toHex(this.value[2])..toHex(this.value[3])
  603. elseif format == 'hex-opacity' then
  604. this:rgb()
  605. local r = this.value[1]
  606. local g = this.value[2]
  607. local b = this.value[3]
  608. r = r + r * (1 - this.opacity)
  609. g = g + g * (1 - this.opacity)
  610. b = b + b * (1 - this.opacity)
  611. if r > 255 then r = 255 end
  612. if g > 255 then g = 255 end
  613. if b > 255 then b = 255 end
  614. return '#'..toHex(r)..toHex(g)..toHex(b)
  615. end
  616. end
  617. return Color