Skip to content

Commit

Permalink
support husl perceptual colour values
Browse files Browse the repository at this point in the history
  • Loading branch information
nebulon42 committed Dec 13, 2015
1 parent 469207b commit 03cc4a5
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 22 deletions.
5 changes: 4 additions & 1 deletion tools/export.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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.
60 changes: 39 additions & 21 deletions tools/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -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']:
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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).')

Expand All @@ -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']:
Expand Down Expand Up @@ -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).')

Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 03cc4a5

Please sign in to comment.