aboutsummaryrefslogtreecommitdiff
path: root/autoload/color.vim
diff options
context:
space:
mode:
Diffstat (limited to 'autoload/color.vim')
-rw-r--r--autoload/color.vim269
1 files changed, 269 insertions, 0 deletions
diff --git a/autoload/color.vim b/autoload/color.vim
new file mode 100644
index 0000000..b5e0e8f
--- /dev/null
+++ b/autoload/color.vim
@@ -0,0 +1,269 @@
+" 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
+