# -*- coding: utf-8 -*- # -*- coding: utf-8 -*- import colorsys import numpy class Color(object): red = None green = None blue = None hue = None saturation = None value = None alpha = None shortcuts = { "h":"hue", "s":"saturation", "v":"value", "r":"red", "g":"green", "b":"blue" } attributes_range = { "hue":360, "saturation":1, "value":1, "red":255, "green":255, "blue":255 } def __init__(self, red=None, green=None, blue=None, hue=None, saturation=None, value=None, alpha=None): rgb_passed = bool(red)|bool(green)|bool(blue) hsv_passed = bool(hue)|bool(saturation)|bool(value) if not alpha: alpha = 0.0 if rgb_passed and hsv_passed: raise ValueError("Color can't be initialized with RGB and HSV at the same time.") elif hsv_passed: if not hue: hue = 0.0 if not saturation: saturation = 0.0 if not value: value = 0.0 super(Color, self).__setattr__('hue', hue) super(Color, self).__setattr__('saturation', saturation) super(Color, self).__setattr__('value', value) self._update_rgb() else: if not red: red = 0 if not green: green = 0 if not blue: blue = 0 super(Color, self).__setattr__('red', red) super(Color, self).__setattr__('green', green) super(Color, self).__setattr__('blue', blue) self._update_hsv() super(Color, self).__setattr__('alpha', alpha) def __getattr__(self, key): if key == "hue" or key == "h": return self.hue if key == "saturation" or key == "s": return self.saturation if key == "value" or key == "v": return self.value if key == "red" or key == "r": return self.red if key == "green" or key == "g": return self.green if key == "blue" or key == "b": return self.blue else: return None def translate_shortcut( self, p_shortcut ): return self.shortcuts[ p_shortcut ] def get_attributes_range( self, key ): return self.attributes_range[ key ] def __setattr__(self, key, value): if key in ('red', 'green', 'blue'): if value > 255.0: value = value % 255.0 super(Color, self).__setattr__(key, value) self._update_hsv() elif key in ('hue', 'saturation', 'value'): if key == 'hue' and (value >= 360.0 or value < 0): value = value % 360.0 elif key != 'hue' and value > 1.0: value = 1.0 super(Color, self).__setattr__(key, value) self._update_rgb() else: if key == 'alpha' and value > 1.0: # TODO: Might this be more fitting in another place? value = 1.0 super(Color, self).__setattr__(key, value) def __repr__(self): return '<%s: red %f, green %f, blue %f, hue %f, saturation %f, value %f, alpha %f>' % ( self.__class__.__name__, self.red, self.green, self.blue, self.hue, self.saturation, self.value, self.alpha ) def __str__(self): return "%d %d %d" % ( int(round(self.red * self.alpha)), int(round(self.green * self.alpha)), int(round(self.blue * self.alpha)), ) def blend(self, other, mode='normal'): if self.alpha != 1.0: # no clue how to blend with a translucent bottom layer self.red = self.red * self.alpha self.green = self.green * self.alpha self.blue = self.blue * self.alpha self.alpha = 1.0 if mode == 'normal': own_influence = 1.0 - other.alpha self.red = (self.red * own_influence) + (other.red * other.alpha) self.green = (self.green * own_influence) + (other.green * other.alpha) self.blue = (self.blue * own_influence) + (other.blue * other.alpha) def lighten(self, other): if isinstance(other, int) or isinstance(other, float): other = Color(red=other, green=other, blue=other, alpha=1.0) if self.alpha != 1.0: self.red = self.red * self.alpha self.green = self.green * self.alpha self.blue = self.blue * self.alpha self.alpha = 1.0 red = self.red + (other.red * other.alpha) green = self.green + (other.green * other.alpha) blue = self.blue + (other.blue * other.alpha) if red > 255.0: red = 255.0 if green > 255.0: green = 255.0 if blue > 255.0: blue = 255.0 self.red = red self.green = green self.blue = blue def darken(self, other): if isinstance(other, int) or isinstance(other, float): other = Color(red=other, green=other, blue=other, alpha=1.0) red = self.red - other.red green = self.green - other.green blue = self.blue - other.blue if red < 0: red = 0 if green < 0: green = 0 if blue < 0: blue = 0 self.red = red self.green = green self.blue = blue def hex(self): return "%.2X%.2X%.2X" % (self.red, self.green, self.blue) def _update_hsv(self): hue, saturation, value = colorsys.rgb_to_hsv(self.red/255.0, self.green/255.0, self.blue/255.0) super(Color, self).__setattr__('hue', hue * 360.0) super(Color, self).__setattr__('saturation', saturation) super(Color, self).__setattr__('value', value) def _update_rgb(self): red, green, blue = colorsys.hsv_to_rgb(self.hue / 360.0, self.saturation, self.value) super(Color, self).__setattr__('red', red * 255.0) super(Color, self).__setattr__('green', green * 255.0) super(Color, self).__setattr__('blue', blue * 255.0) def copy(self): return Color( self.r, self.g, self.b ) def rgb_tripel(self, p_int=False): if p_int: return (int(self.red), int(self.green), int(self.blue)) else: return (self.red, self.green, self.blue) def bin_ranges(length, num_bins): length = numpy.float64(length) bin_range = [] current_range = length / (2 ** num_bins -1) lower = 0 upper = current_range -1 if upper < lower: upper = lower bin_range.append([int(round(lower)), int(round(upper))]) for i in range(1, num_bins): current_range *=2 lower = upper + 1 upper = lower + current_range - 1 if upper < lower: upper = lower bin_range.append([int(round(lower)), int(round(upper))]) return bin_range def octave_amplitudes(amplitudes, num_bins): bins = numpy.zeros(num_bins) i = 0 ranges = bin_ranges(len(amplitudes), num_bins) for lower, upper in ranges: if lower == upper: bin = amplitudes[lower] else: #bin = amplitudes[lower:upper].mean() #bin = sum(amplitudes[lower:upper]) / float(len(amplitudes[lower:upper])) # average instead of mean #bin = numpy.max(amplitudes[lower:upper]) # this is an ugly hack instead of doing, like, statistical analysis or anything. bin = (numpy.max(amplitudes[lower:upper]) + numpy.mean(amplitudes[lower:upper])) / 2 # mean and max mixed if numpy.isnan(bin): bin = numpy.float64(0) bins[i] = bin i += 1 return bins