def transparentify(top, bottom=None, alpha=None, evaluator=None): if isinstance(bottom, Unit): # dirty hack alpha = bottom bottom = None assert_color(top) top = top.rgba() if not bottom: bottom = RGBA(255, 255, 255, 1) if not alpha and bottom and hasattr(bottom, "rgba") and not bottom.rgba: alpha = bottom bottom = RGBA(255, 255, 255, 1) assert_color(bottom) bottom = bottom.rgba() ba = best_alpha(top, bottom) if alpha: assert_type(alpha, "unit", "aplha") if alpha.type == "%": ba = alpha.value / 100 elif not alpha.type: ba = alpha = alpha.value ba = max(min(ba, 1), 0) if ba == 0: return RGBA(bottom.r, bottom.g, bottom.b, round(ba * 100) / 100) else: return RGBA( bottom.r + (top.r - bottom.r) / ba, bottom.g + (top.g - bottom.g) / ba, bottom.b + (top.b - bottom.b) / ba, round(ba * 100) / 100, )
def hsla(hue, saturation=None, lightness=None, alpha=None, evaluator=None): """Convert the given `color` to an `HSLA` node, or h,s,l,a component values. :param hue: :param saturation: :param lightness: :param alpha: :return: :class:HSLA """ # color if hue and (saturation is lightness is alpha is None): assert_color(hue) return hue.hsla() # alpha if hue and saturation and (lightness is alpha is None): assert_color(hue) color = hue.hsla() assert_type(saturation, "unit", "alpha") alpha = saturation.clone() if alpha.type == "%": alpha.value /= 100 return HSLA(color.hue, color.saturation, color.lightness, alpha.value) # color assert_type(hue, "unit", "hue") assert_type(saturation, "unit", "saturation") assert_type(lightness, "unit", "lightness") assert_type(alpha, "unit", "alpha") alpha = alpha.clone() if alpha and alpha.type == "%": alpha.value /= 100 return HSLA(hue.value, saturation.value, lightness.value, alpha.value)
def contrast(top: Color = None, bottom: Color = None, evaluator=None): if not isinstance(top, Color) and not isinstance(bottom, Color): c = "" if isinstance(top, (Null, type(None))) else f"{top}" return Literal(f"contrast({c})") result = ObjectNode() if not bottom: bottom = RGBA(255, 255, 255, 1) assert_color(bottom) bottom = bottom.rgba() def contrast_function(top, bottom): if 1 > top.a: top = blend(top, bottom) l1 = luminosity(bottom).value + 0.05 l2 = luminosity(top).value + 0.05 ratio = l1 / l2 if l2 > l1: ratio = 1 / ratio return round(ratio * 10) / 10 if 1 <= bottom.a: result_ratio = Unit(contrast_function(top, bottom)) result.set("ratio", result_ratio) result.set("error", Unit(0)) result.set("min", result_ratio) result.set("max", result_ratio) else: on_black = contrast_function(top, blend(bottom, RGBA(0, 0, 0, 1))) on_white = contrast_function(top, blend(bottom, RGBA(255, 255, 255, 1))) the_max = max(on_black, on_white) def process_channel(top_channel, bottm_channel): return min( max( 0, (top_channel - bottm_channel * bottom.a) / (1 - bottom.a), ), 255, ) closest = RGBA( process_channel(top.r, bottom.r), process_channel(top.g, bottom.g), process_channel(top.b, bottom.b), 1, ) the_min = contrast_function(top, blend(bottom, closest)) result.set("ratio", Unit(stilus_round((the_min + the_max) * 50) / 100)) result.set("error", Unit(stilus_round((the_max - the_min) * 50) / 100)) result.set("min", Unit(the_min)) result.set("max", Unit(the_max)) return result
def blend(top, bottom=None, evaluator=None): assert_color(top) top = top.rgba() if not bottom: bottom = RGBA(255, 255, 255, 1) assert_color(bottom) bottom = bottom.rgba() return RGBA( top.r * top.a + bottom.r * (1 - top.a), top.g * top.a + bottom.g * (1 - top.a), top.b * top.a + bottom.b * (1 - top.a), top.a + bottom.a - top.a * bottom.a, )
def adjust(color, prop, amount, evaluator=None): assert_color(color, "color") assert_string(prop, "prop") assert_type(amount, "unit", "amount") hsl = color.hsla().clone() if not hasattr(hsl, prop.string): raise StilusError("Invalid adjustment property.") value = amount.value if amount.type == "%": if prop.string == "lightness" and value > 0: value = (100 - hsl.lightness) * value / 100 else: value = getattr(hsl, prop.string) * (value / 100) setattr(hsl, prop.string, getattr(hsl, prop.string) + value) return hsl.rgba()
def luminosity(color: Color, evaluator=None): assert_color(color) color = color.rgba() def process_channel(channel): channel = channel / 255 if 0.03928 > channel: return channel / 12.92 else: return pow((channel + 0.055) / 1.055, 2.4) return Unit( 0.2126 * process_channel(color.r) + 0.7152 * process_channel(color.g) + 0.0722 * process_channel(color.b) )
def component(color: Color, name: str, evaluator=None) -> Unit: """Return component `name` for a given `color`. :param color: Color :param name: str :return: Unit """ assert_color(color, "color") assert_string(name, "name") name = name.string unit = unit_map.setdefault(name, None) type = type_map[name] name = component_map[name] try: return Unit(getattr(getattr(color, type)(), name), unit) except AttributeError: raise TypeError(f'invalid color component "{name}"')
def rgba(red, green=None, blue=None, alpha=None, evaluator=None): """Return a `RGBA` from the r,g,b,a channels. >>> rgba(255,0,0,0.5) rgba(255,0,0,0.5) >>> rgba(255,0,0,1) #ff0000 >>> rgba(#ffcc00, 50%) rgba(255,204,0,0.5) :param red: :param green: :param blue: :param alpha: :return: """ # color if red and (green is blue is alpha is None): assert_color(red) return red.rgba() # alpha if red and green and (blue is alpha is None): assert_color(red) color = red.rgba() assert_type(green, "unit", "alpha") alpha = green.clone() if alpha.type == "%": alpha.value /= 100 return RGBA(color.r, color.g, color.b, alpha.value) # color assert_type(red, "unit", "red") assert_type(green, "unit", "green") assert_type(blue, "unit", "blue") assert_type(alpha, "unit", "alpha") r = round(red.value * 2.55) if red.type == "%" else red.value g = round(green.value * 2.55) if green.type == "%" else green.value b = round(blue.value * 2.55) if blue.type == "%" else blue.value alpha = alpha.clone() if alpha and alpha.type == "%": alpha.value /= 100 return RGBA(r, g, b, alpha.value)
def hsl(hue, saturation=None, lightness=None, evaluator=None): if hue and (saturation is lightness is None): assert_color(hue, "color") return hue.hsla() return hsla(hue, saturation, lightness, Unit(1), evaluator)