Permalink
Browse files

support husl perceptual colour values

  • Loading branch information...
1 parent 469207b commit 03cc4a5c9f526d9c2aaeb668d2c87a218cc58f32 @nebulon42 nebulon42 committed Dec 13, 2015
Showing with 43 additions and 22 deletions.
  1. +4 −1 tools/export.md
  2. +39 −21 tools/export.py
View
@@ -31,7 +31,7 @@ Such a configuration file must be supplied to the script as parameter e.g. execu
The configuration file follows a simple organisational pattern for maximum versatility: all global icon parameters can be overridden by parameters specific to a certain icon id (except for sprites where only the colour can be changed). This is e.g. how re-colouring of icons works. An example of this pattern can be found in [osm-carto-png.yaml](https://github.com/gmgeo/osmic/blob/master/tools/config/osm-carto-png.yaml) where the global fill colour of `#734a08` is changed for the icon id `peak` to `#d08f55`.
In the following all possible parameters are listed. All of them are optional.
-Colour values can be either specified as RGB value e.g. `rgb(255, 255, 255)` or `#ffffff` or as HSL value e.g. `hsl(20, 40%, 33%)`.
+Colour values can be either specified as RGB value e.g. `rgb(255, 255, 255)` or `#ffffff`, as HSL value e.g. `hsl(20, 40%, 33%)` or as perceptual HUSL value (http://www.husl-colors.org/) e.g. `husl(20, 40%, 33%)`.
* `basedir` - specify the working directory, if not specified it defaults to the current working directory, relative and absolute paths are allowed, relative paths are evaluated against the current working directory
@@ -84,3 +84,6 @@ Colour values can be either specified as RGB value e.g. `rgb(255, 255, 255)` or
* `font` - a list of configuration options for icon font generation
* `output_basedir` - specify the output directory for the font files, if not specified it defaults to `./font`, can be either an absolute or relative path
+
+#### Dependencies
+* `husl` (`pip install husl`) if you want to specify HUSL colour values.
View
@@ -364,7 +364,7 @@ def exportSprite(config, size_filter, num_icons):
if 'background' in config['sprite']:
sprite_background = parseColor(config['sprite']['background'])
if sprite_background == None:
- print('The specified background colour is invalid. Format it as HEX/RGB/HSL (e.g. #1a1a1a). Defaulting to none (transparent).')
+ print('The specified background colour is invalid. Format it as HEX/RGB/HSL/HUSL (e.g. #1a1a1a). Defaulting to none (transparent).')
sprite_file_name = 'sprite'
if 'filename' in config['sprite']:
@@ -529,31 +529,49 @@ def exportFont(config, size_filter):
return
-# parse rgb, hex and hsl color definitions, return hex color or None on error
+# parse rgb, hex, hsl and husl (perceptual) color definitions, return hex color or None on error
+# husl needs husl library, load on demand
def parseColor(color):
parsed_color = None
- if re.match('^#[0-9a-f]{6}$', color) != None:
- parsed_color = color
- rgb_match = re.search('^rgb\(([0-9]{1,3}),\s*([0-9]{1,3}),\s*([0-9]{1,3})\)$', color)
- if rgb_match is not None:
- try:
- r = int(rgb_match.group(1))
- g = int(rgb_match.group(2))
- b = int(rgb_match.group(3))
- parsed_color = '#'+("%x" % r)+("%x" % g)+("%x" % b)
- except ValueError:
- pass
- else:
+ if color.startswith('#'):
+ if re.match('^#[0-9a-f]{6}$', color) != None:
+ parsed_color = color
+ elif color.startswith('rgb'):
+ rgb_match = re.search('^rgb\(([0-9]{1,3}),\s*([0-9]{1,3}),\s*([0-9]{1,3})\)$', color)
+ if rgb_match is not None:
+ try:
+ r = min(int(rgb_match.group(1)), 255)
+ g = min(int(rgb_match.group(2)), 255)
+ b = min(int(rgb_match.group(3)), 255)
+ parsed_color = '#'+("%x" % r)+("%x" % g)+("%x" % b)
+ except ValueError:
+ pass
+ elif color.startswith('hsl'):
hsl_match = re.search('^hsl\(([0-9]{1,3}(\.[0-9]*)?),\s*([0-9]{1,3}(\.[0-9]*)?)\%,\s*([0-9]{1,3}(\.[0-9]*)?)\%\)$', color)
if hsl_match is not None:
try:
- h = float(hsl_match.group(1)) / 365
- s = float(hsl_match.group(3)) / 100
- l = float(hsl_match.group(5)) / 100
+ h = min(float(hsl_match.group(1)) / 365, 1)
+ s = min(float(hsl_match.group(3)) / 100, 1)
+ l = min(float(hsl_match.group(5)) / 100, 1)
(r, g, b) = colorsys.hls_to_rgb(h, l, s)
parsed_color = '#'+("%x" % (r * 255))+("%x" % (g * 255))+("%x" % (b * 255))
except ValueError:
pass
+ elif color.startswith('husl'):
+ husl_match = re.search('^husl\(([0-9]{1,3}(\.[0-9]*)?),\s*([0-9]{1,3}(\.[0-9]*)?)\%,\s*([0-9]{1,3}(\.[0-9]*)?)\%\)$', color)
+ if husl_match is not None:
+ try:
+ import husl
+ h = min(float(husl_match.group(1)), 360)
+ s = min(float(husl_match.group(3)), 100)
+ l = min(float(husl_match.group(5)), 100)
+ rgb = husl.husl_to_rgb(h, s, l)
+ parsed_color = husl.rgb_to_hex(rgb)
+ except ValueError:
+ pass
+ except ImportError:
+ print('HUSL colour definitions need the husl library. Please install it.')
+ pass
return parsed_color
@@ -620,7 +638,7 @@ def modifySVG(config, icon_id, size, icon):
shield_fill = parseColor(config['shield']['fill'])
if shield_fill == None:
shield_fill = '#000000'
- print('The specified shield fill is invalid. Format it as HEX/RGB/HSL (e.g. #1a1a1a). Defaulting to #000000 (black).')
+ print('The specified shield fill is invalid. Format it as HEX/RGB/HSL/HUSL (e.g. #1a1a1a). Defaulting to #000000 (black).')
else:
print('Shield fill not specified. Defaulting to #000000 (black).')
@@ -629,7 +647,7 @@ def modifySVG(config, icon_id, size, icon):
if 'stroke_fill' in config['shield']:
stroke_fill = parseColor(config['shield']['stroke_fill'])
if stroke_fill == None:
- print('The specified shield stroke fill is invalid. Format it as HEX/RGB/HSL (e.g. #1a1a1a).')
+ print('The specified shield stroke fill is invalid. Format it as HEX/RGB/HSL/HUSL (e.g. #1a1a1a).')
stroke_width = None
if 'stroke_width' in config['shield']:
@@ -674,7 +692,7 @@ def modifySVG(config, icon_id, size, icon):
halo_fill = parseColor(config['halo']['fill'])
if halo_fill == None:
halo_fill = '#ffffff'
- print('The specified halo fill is invalid. Format it as HEX/RGB/HSL (e.g. #1a1a1a). Defaulting to #ffffff (white).')
+ print('The specified halo fill is invalid. Format it as HEX/RGB/HSL/HUSL (e.g. #1a1a1a). Defaulting to #ffffff (white).')
else:
print('Halo fill not specified. Defaulting to #ffffff (white).')
@@ -715,7 +733,7 @@ def modifySVG(config, icon_id, size, icon):
path = xpEval("//def:path[@id='"+icon_id+"']")[0]
path.attrib['style'] = re.sub('fill:#[0-9a-f]{6};?', 'fill:'+fill_color+';', path.attrib['style'])
else:
- print('The specified fill is invalid. Format it as HEX/RGB/HSL (e.g. #1a1a1a).')
+ print('The specified fill is invalid. Format it as HEX/RGB/HSL/HUSL (e.g. #1a1a1a).')
# adjust document and canvas size, icon position

0 comments on commit 03cc4a5

Please sign in to comment.