Skip to content

Instantly share code, notes, and snippets.

@joxl
Created April 5, 2016 14:18
Show Gist options
  • Save joxl/138b0132cde3e641ed97808ee95adc20 to your computer and use it in GitHub Desktop.
Save joxl/138b0132cde3e641ed97808ee95adc20 to your computer and use it in GitHub Desktop.
Python utility for generating HSB gradient color samples
#!/usr/bin/env python
import argparse
import colorsys
HTML_TEMPLATE = """<!DOCTYPE html>
<html>
<head>
<style>
body {
background: linear-gradient(to right, %s);
}
</style>
</head>
<body>
</body>
<html>"""
class Color(object):
VALID = set("0123456789abcdef")
def __init__(self, hex_str):
hex_str = hex_str.lower()
if len(hex_str) != 6 or not set(hex_str).issubset(self.VALID):
raise ValueError(hex_str)
self._hex_str = hex_str
@classmethod
def from_hsv(cls, hue, sat, val):
def perc2byte(perc):
return int(round(perc * 255, 0))
r, g, b = colorsys.hsv_to_rgb(hue, sat, val)
hex_str = "%02x%02x%02x" % (perc2byte(r), perc2byte(g), perc2byte(b))
return cls(hex_str)
@property
def hex_str(self):
return self._hex_str
@property
def rgb(self):
def hex2color(hexval):
return int(hexval, 16) / 255.0
red = hex2color(self.hex_str[0:2])
green = hex2color(self.hex_str[2:4])
blue = hex2color(self.hex_str[4:6])
return red, green, blue
@property
def hsv(self):
return colorsys.rgb_to_hsv(*self.rgb)
def __repr__(self):
return "<Color hex='%s'>" % (self.hex_str,)
def gradient(src, dst, samples, reverse=False):
assert samples >= 2, "Must have at least 2 samples"
def ilerp(it1, it2):
step = (it2 - it1) / (samples - 1)
for index in xrange(samples):
yield it1 + (step * index)
def ilerp_hue(hue1, hue2, reverse):
if not reverse and hue1 > hue2:
# wrap foward (e.g 300..360..0..50)
for hue in ilerp(hue1, hue2 + 1.0):
if hue <= 1.0:
yield hue
else:
yield hue - 1.0
elif reverse and hue1 < hue2:
# wrap backward (e.g 50..0..360..300)
for hue in ilerp(hue1, hue2 - 1.0):
if hue >= 0.0:
yield hue
else:
yield hue + 1.0
else:
for hue in ilerp(hue1, hue2):
yield hue
hue1, sat1, val1 = src.hsv
hue2, sat2, val2 = dst.hsv
return map(Color.from_hsv,
ilerp_hue(hue1, hue2, reverse),
ilerp(sat1, sat2),
ilerp(val1, val2),
)
def main():
parser = argparse.ArgumentParser()
parser.add_argument("source", metavar="SRC_HEX",
help="source color (in hex format, e.g. FF0000)")
parser.add_argument("dest", metavar="DST_HEX",
help="destination color (in hex format, e.g. 0000FF)")
parser.add_argument("-s", "--samples", metavar="N", default=10, type=int,
help="generate %(metavar)s gradient color samples (default=%(default)s)")
parser.add_argument("-r", "--reverse", action="store_true", default=False,
help="perform reverse gradient in the hue spectrum")
parser.add_argument("--html", action="store_true", default=False,
help="Output HTML code for viewing gradient")
opts = parser.parse_args()
# validate args
if opts.samples < 2:
parser.error("Must have at least 2 samples")
try:
src = Color(opts.source)
dst = Color(opts.dest)
except ValueError:
parser.error("Invalid source/destination colors (%s/%s)" % (opts.source,
opts.dest))
# calculate gradient colors
colors = gradient(src, dst, opts.samples, opts.reverse)
# output results
if opts.html:
# in html
css = []
for color in colors:
css.append("#%s" % (color.hex_str,))
print(HTML_TEMPLATE % (",".join(css),))
else:
# just raw color hex strings
for color in colors:
print(color.hex_str)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment