You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

269 lines
7.2 KiB

" File: color.vim
" Author: romgrk
" Date: 15 Mar 2016
" Description: vimscript RGB/HSL color parsing
" This is mostly a transcript from a javascript color parsing module.
" !::exe [so %]
" ================================================================================
" Definitions: {{{1
" In function names:
" • “Hex” refers to hexadecimal color format e.g. #599eff
" • “RGB” refers to an array of numbers [r, g, b]
" where r,g,b ∈ [0, 255]
" • “HSL” refers to an array of floats [h, s, l]
" where h,s,l ∈ [0, 1.0]
" }}}1
" ================================================================================
" Color-format patterns:
" {{{1
let s:patterns = {}
" 6 hex-numbers, optionnal #-prefix
let s:patterns['hex'] = '\v#?(\x{2})(\x{2})(\x{2})'
" short version is strict: starting # mandatory
let s:patterns['shortHex'] = '\v#(\x{1})(\x{1})(\x{1})'
" Disabled
"let s:patterns['rgb'] = '\vrgb\s*\((\d+)\s*,(\d+)\s*,(\d+)\s*)\s*'
"let s:patterns['rgba'] = '\vrgba\s*\((\d+)\s*,(\d+)\s*,(\d+)\s*,(\d+)\s*)\s*'
" }}}1
" ================================================================================
" Functions:
" {{{1
" @params String string The string to test
" @returns Boolean [0 or 1] if string matches: rrggbb OR #rrggbb OR #rgb
fu! color#Test (string)
for key in keys(s:patterns)
if a:string =~# s:patterns[key]
return 1
end
endfor
return 0
endfu
" @params (r, g, b)
" @params ([r, g, b])
" @returns String A RGB color
fu! color#RGBtoHex (...)
let [r, g, b] = ( a:0==1 ? a:1 : a:000 )
let num = printf('%02x', float2nr(r)) . ''
\ . printf('%02x', float2nr(g)) . ''
\ . printf('%02x', float2nr(b)) . ''
return '#' . num
endfu
" @param {String|Number} color The color to parse
fu! color#HexToRGB (color)
if type(a:color) == 2
let color = printf('%x', a:color)
else
let color = a:color | end
let matches = matchlist(color, s:patterns['hex'])
let factor = 0x1
if empty(matches)
let matches = matchlist(color, s:patterns['shortHex'])
let factor = 0x10
end
if len(matches) < 4
throw 'Couldnt parse ' . string(color) . ' ' . string(matches)
end
let r = str2nr(matches[1], 16) * factor
let g = str2nr(matches[2], 16) * factor
let b = str2nr(matches[3], 16) * factor
return [r, g, b]
endfu
" Converts an HSL color value to RGB. Conversion formula
" adapted from http://en.wikipedia.org/wiki/HSL_color_space.
" Assumes h, s, and l are contained in the set [0, 1] and
" returns r, g, and b in the set [0, 255].
" @param Number h OR @param Array [h, s, l]
" @param Number s
" @param Number l
" @returns Array [r, g, b] The RGB representation
fu! color#HSLtoRGB(...) " (h, s, l)
let [h, s, l] = ( a:0==1 ? a:1 : a:000 )
if (s == 0.0) " achromatic
let r = l
let g = l
let b = l
else
let q = l < 0.5 ? l * (1 + s) : l + s - l * s
let p = 2 * l - q
let r = color#Hue2RGB(p, q, h + 0.33333)
let g = color#Hue2RGB(p, q, h)
let b = color#Hue2RGB(p, q, h - 0.33333)
end
return [r * 255.0, g * 255.0, b * 255.0]
endfu
" @param Number r OR @param Array [r, g, b]
" @param Number g
" @param Number b
" @returns Array [h, s, l] The HSL representation
fu! color#RGBtoHSL(...)
let [r, g, b] = ( a:0==1 ? a:1 : a:000 )
let max = max([r, g, b])
let min = min([r, g, b])
let r = str2float(r)
let g = str2float(g)
let b = str2float(b)
let max = str2float(max)
let min = str2float(min)
let max = max / 255
let min = min / 255
let r = r / 255
let g = g / 255
let b = b / 255
let h = str2float(0)
let s = str2float(0)
let l = (max + min) / 2
if (max == min)
let h = 0 " achromatic
let s = 0 " achromatic
else
let d = max - min
let s = (l > 0.5 ? d / (2 - max - min)
\ : d / (max + min) )
if (max == r)
let h = (g - b) / d + (g < b ? 6 : 0)
end
if (max == g)
let h = (b - r) / d + 2
end
if (max == b)
let h = (r - g) / d + 4
end
let h = h / 6
end
return [h, s, l]
endfu
fu! color#Hue2RGB(...) " (p, q, t)
let [p, q, t] = ( a:0==1 ? a:1 : a:000 )
if(t < 0) | let t += 1 | end
if(t > 1) | let t -= 1 | end
if(t < 1.0/6) | return (p + (q - p) * 6.0 * t) | end
if(t < 1.0/2) | return (q) | end
if(t < 2.0/3) | return (p + (q - p) * (2.0/3 - t) * 6.0) | end
return p
endfu
" }}}1
" ================================================================================
" Composed functions:
" {{{1
fu! color#HexToHSL (color)
let [r, g, b] = color#HexToRGB(a:color)
return color#RGBtoHSL(r, g, b)
endfu
fu! color#HSLtoHex (...)
let [h, s, l] = ( a:0==1 ? a:1 : a:000 )
let [r, g, b] = color#HSLtoRGB(h, s, l)
return color#RGBtoHex(r, g, b)
endfu
" @params String color The color
" @params {Number|String|Float} [amount=5] The percentage of light
fu! color#Lighten(color, ...)
let amount = a:0 ?
\(type(a:1) < 2 ?
\str2float(a:1) : a:1 )
\: 5.0
if(amount < 1.0)
let amount = 1.0 + amount
else
let amount = 1.0 + (amount / 100.0)
end
let rgb = color#HexToRGB(a:color)
let rgb = map(rgb, 'v:val * amount')
let rgb = map(rgb, 'v:val > 255.0 ? 255.0 : v:val')
let rgb = map(rgb, 'float2nr(v:val)')
let hex = color#RGBtoHex(rgb)
return hex
endfu
" @params String color The color
" @params {Number|String|Float} [amount=5] The percentage of darkness
fu! color#Darken(color, ...)
let amount = a:0 ?
\(type(a:1) < 2 ?
\str2float(a:1) : a:1 )
\: 5.0
if(amount < 1.0)
let amount = 1.0 - amount
else
let amount = 1.0 - (amount / 100.0)
end
if(amount < 0.0)
let amount = 0.0 | end
let rgb = color#HexToRGB(a:color)
let rgb = map(rgb, 'v:val * amount')
let rgb = map(rgb, 'v:val > 255.0 ? 255.0 : v:val')
let rgb = map(rgb, 'float2nr(v:val)')
let hex = color#RGBtoHex(rgb)
return hex
endfu
function! color#Decrease (...)
if &background == 'light'
return call(function('color#Lighten'), a:000)
end
return call(function('color#Darken'), a:000)
endfunc
function! color#Increase (...)
if &background == 'light'
return call(function('color#Darken'), a:000)
end
return call(function('color#Lighten'), a:000)
endfunc
function! color#Mix (a, b, ...)
let amount = a:0 ? a:1 : 0.5
let ca = color#HexToRGB(a:a)
let cb = color#HexToRGB(a:b)
let r = s:interpolate(ca[0], cb[0], amount)
let g = s:interpolate(ca[1], cb[1], amount)
let b = s:interpolate(ca[2], cb[2], amount)
return color#RGBtoHex([r, g, b])
endfunc
function! s:interpolate (start, end, amount)
let diff = a:end - a:start
return a:start + (diff * a:amount)
endfunc
" }}}1