45
45
class CRGB (object ):
46
46
"""Color stored in Red, Green, Blue color space.
47
47
48
- One of two ways: separate red, gren, blue values (either as integers (0 to 255
49
- range) or floats (0.0 to 1.0 range), either type is 'clamped' to valid range and
50
- stored internally in the normalized (float) format), OR can accept a CHSV color as
51
- input, which will be converted and stored in RGB format.
48
+ One of two ways: separate red, gren, blue values (either as integers
49
+ (0 to 255 range) or floats (0.0 to 1.0 range), either type is
50
+ 'clamped' to valid range and stored internally in the normalized
51
+ (float) format), OR can accept a CHSV color as input, which will be
52
+ converted and stored in RGB format.
52
53
53
54
Following statements are equivalent - all return red:
54
55
@@ -108,23 +109,34 @@ def __repr__(self):
108
109
def __str__ (self ):
109
110
return "(%s, %s, %s)" % (self .red , self .green , self .blue )
110
111
112
+ def pack (self ):
113
+ """'Pack' a `CRGB` color into a 24-bit RGB integer.
114
+
115
+ :returns: 24-bit integer a la ``0x00RRGGBB``.
116
+ """
117
+
118
+ return ((denormalize (self .red ) << 16 ) |
119
+ (denormalize (self .green ) << 8 ) |
120
+ (denormalize (self .blue )))
121
+
111
122
112
123
class CHSV (object ):
113
124
"""Color stored in Hue, Saturation, Value color space.
114
125
115
- Accepts hue as float (any range) or integer (0-256 -> 0.0-1.0) with no clamping
116
- performed (hue can 'wrap around'), saturation and value as float (0.0 to 1.0) or
117
- integer (0 to 255), both are clamped and stored internally in the normalized (float)
118
- format. Latter two are optional, can pass juse hue and saturation/value will
119
- default to 1.0.
126
+ Accepts hue as float (any range) or integer (0-256 -> 0.0-1.0) with
127
+ no clamping performed (hue can 'wrap around'), saturation and value
128
+ as float (0.0 to 1.0) or integer (0 to 255), both are clamped and
129
+ stored internally in the normalized (float) format. Latter two are
130
+ optional, can pass juse hue and saturation/value will default to 1.0.
120
131
121
- Unlike `CRGB` (which can take a `CHSV` as input), there's currently no equivalent
122
- RGB-to-HSV conversion, mostly because it's a bit like trying to reverse a hash...
123
- there may be multiple HSV solutions for a given RGB input.
132
+ Unlike `CRGB` (which can take a `CHSV` as input), there's currently
133
+ no equivalent RGB-to-HSV conversion, mostly because it's a bit like
134
+ trying to reverse a hash...there may be multiple HSV solutions for a
135
+ given RGB input.
124
136
125
- This might be OK as long as conversion precedence is documented, but otherwise (and
126
- maybe still) could cause confusion as certain HSV->RGB->HSV translations won't have
127
- the same input and output. Hmmm .
137
+ This might be OK as long as conversion precedence is documented,
138
+ but otherwise (and maybe still) could cause confusion as certain
139
+ HSV->RGB->HSV translations won't have the same input and output.
128
140
"""
129
141
130
142
def __init__ (self , h , s = 1.0 , v = 1.0 ):
@@ -147,6 +159,15 @@ def __repr__(self):
147
159
def __str__ (self ):
148
160
return "(%s, %s, %s)" % (self .hue , self .saturation , self .value )
149
161
162
+ def pack (self ):
163
+ """'Pack' a `CHSV` color into a 24-bit RGB integer.
164
+
165
+ :returns: 24-bit integer a la ``0x00RRGGBB``.
166
+ """
167
+
168
+ # Convert CHSV to CRGB, return packed result
169
+ return CRGB (self ).pack ()
170
+
150
171
151
172
def clamp (val , lower , upper ):
152
173
"""Constrain value within a numeric range (inclusive).
@@ -157,7 +178,10 @@ def clamp(val, lower, upper):
157
178
def normalize (val , inplace = False ):
158
179
"""Convert 8-bit (0 to 255) value to normalized (0.0 to 1.0) value.
159
180
160
- Accepts integer, 0 to 255 range (input is clamped) or a list or tuple of integers. In list case, 'inplace' can be used to control whether the original list is modified (True) or a new list is generated and returned (False).
181
+ Accepts integer, 0 to 255 range (input is clamped) or a list or tuple
182
+ of integers. In list case, 'inplace' can be used to control whether
183
+ the original list is modified (True) or a new list is generated and
184
+ returned (False).
161
185
162
186
Returns float, 0.0 to 1.0 range, or list of floats (or None if inplace).
163
187
"""
@@ -180,11 +204,12 @@ def normalize(val, inplace=False):
180
204
def denormalize (val , inplace = False ):
181
205
"""Convert normalized (0.0 to 1.0) value to 8-bit (0 to 255) value
182
206
183
- Accepts float, 0.0 to 1.0 range or a list or tuple of floats. In list case,
184
- 'inplace' can be used to control whether the original list is modified (True) or a
185
- new list is generated and returned (False).
207
+ Accepts float, 0.0 to 1.0 range or a list or tuple of floats. In
208
+ list case, 'inplace' can be used to control whether the original list
209
+ is modified (True) or a new list is generated and returned (False).
186
210
187
- Returns integer, 0 to 255 range, or list of integers (or None if inplace).
211
+ Returns integer, 0 to 255 range, or list of integers (or None if
212
+ inplace).
188
213
"""
189
214
190
215
# 'Denormalizing' math varies slightly from normalize(). This is on
@@ -206,22 +231,6 @@ def denormalize(val, inplace=False):
206
231
return [denormalize (n ) for n in val ]
207
232
208
233
209
- def pack (val ):
210
- """'Pack' a `CRGB` or `CHSV` color into a 24-bit RGB integer.
211
-
212
- :param obj val: `CRGB` or `CHSV` color.
213
- :returns: 24-bit integer a la ``0x00RRGGBB``.
214
- """
215
-
216
- # Convert CHSV input to CRGB if needed
217
- if isinstance (val , CHSV ):
218
- val = CRGB (val )
219
-
220
- return ((denormalize (val .red ) << 16 ) |
221
- (denormalize (val .green ) << 8 ) |
222
- (denormalize (val .blue )))
223
-
224
-
225
234
def unpack (val ):
226
235
"""'Unpack' a 24-bit color into a `CRGB` instance.
227
236
@@ -239,8 +248,9 @@ def unpack(val):
239
248
240
249
241
250
def mix (color1 , color2 , weight2 = 0.5 ):
242
- """Blend between two colors using given ratio. Accepts two colors (each may be `CRGB`,
243
- `CHSV` or packed integer), and weighting (0.0 to 1.0) of second color.
251
+ """Blend between two colors using given ratio. Accepts two colors (each
252
+ may be `CRGB`, `CHSV` or packed integer), and weighting (0.0 to 1.0)
253
+ of second color.
244
254
245
255
:returns: `CRGB` color in most cases, `CHSV` if both inputs are `CHSV`.
246
256
"""
@@ -283,29 +293,32 @@ def mix(color1, color2, weight2=0.5):
283
293
(color1 .blue * weight1 + color2 .blue * weight2 ))
284
294
285
295
286
- GFACTOR = 2.5 # Default gamma-correction factor for function below
296
+ GFACTOR = 2.7 # Default gamma-correction factor for function below
287
297
288
298
def gamma_adjust (val , gamma_value = None , brightness = 1.0 , inplace = False ):
289
299
"""Provides gamma adjustment for single values, `CRGB` and `CHSV` types
290
300
and lists of any of these.
291
301
292
302
Works in one of three ways:
293
- 1. Accepts a single normalized level (0.0 to 1.0) and optional gamma-adjustment
294
- factor (float usu. > 1.0, default if unspecified is GFACTOR) and
295
- brightness (float 0.0 to 1.0, default is 1.0). Returns a single normalized gamma-corrected brightness level (0.0 to 1.0).
296
- 2. Accepts a single `CRGB` or `CHSV` type, optional single gamma factor OR a
297
- (R,G,B) gamma tuple (3 values usu. > 1.0), optional single
298
- brightness factor OR a (R,G,B) brightness tuple. The input tuples
299
- are RGB even when a `CHSV` color is passed. Returns a normalized
300
- gamma-corrected `CRGB` type (NOT `CHSV`!).
301
- 3. Accept a list or tuple of normalized levels, `CRGB` or `CHSV` types (and
302
- optional gamma and brightness levels or tuples applied to all). Returns a list
303
- of gamma-corrected values or `CRGB` types (NOT `CHSV`!).
303
+ 1. Accepts a single normalized level (0.0 to 1.0) and optional
304
+ gamma-adjustment factor (float usu. > 1.0, default if
305
+ unspecified is GFACTOR) and brightness (float 0.0 to 1.0,
306
+ default is 1.0). Returns a single normalized gamma-corrected
307
+ brightness level (0.0 to 1.0).
308
+ 2. Accepts a single `CRGB` or `CHSV` type, optional single gamma
309
+ factor OR a (R,G,B) gamma tuple (3 values usu. > 1.0), optional
310
+ single brightness factor OR a (R,G,B) brightness tuple. The
311
+ input tuples are RGB even when a `CHSV` color is passed. Returns
312
+ a normalized gamma-corrected `CRGB` type (NOT `CHSV`!).
313
+ 3. Accept a list or tuple of normalized levels, `CRGB` or `CHSV`
314
+ types (and optional gamma and brightness levels or tuples
315
+ applied to all). Returns a list of gamma-corrected values or
316
+ `CRGB` types (NOT `CHSV`!).
304
317
305
318
In cases 2 and 3, if the input is a list (NOT a tuple!), the 'inplace'
306
319
flag determines whether a new tuple/list is calculated and returned,
307
- or the existing value is modified in-place. By default this is 'False'.
308
- If you try to inplace-modify a tuple, an exception is raised.
320
+ or the existing value is modified in-place. By default this is
321
+ 'False'. If you try to inplace-modify a tuple, an exception is raised.
309
322
310
323
In cases 2 and 3, there is NO return value if 'inplace' is True --
311
324
the original values are modified.
@@ -338,14 +351,18 @@ def gamma_adjust(val, gamma_value=None, brightness=1.0, inplace=False):
338
351
gamma_red , gamma_green , gamma_blue = GFACTOR , GFACTOR , GFACTOR
339
352
elif isinstance (gamma_value , float ):
340
353
# Single gamma value provided, apply to R,G,B
341
- gamma_red , gamma_green , gamma_blue = gamma_value , gamma_value , gamma_value
354
+ gamma_red , gamma_green , gamma_blue = (
355
+ gamma_value , gamma_value , gamma_value )
342
356
else :
343
- gamma_red , gamma_green , gamma_blue = gamma_value [0 ], gamma_value [1 ], gamma_value [2 ]
357
+ gamma_red , gamma_green , gamma_blue = (
358
+ gamma_value [0 ], gamma_value [1 ], gamma_value [2 ])
344
359
if isinstance (brightness , float ):
345
360
# Single brightness value provided, apply to R,G,B
346
- brightness_red , brightness_green , brightness_blue = brightness , brightness , brightness
361
+ brightness_red , brightness_green , brightness_blue = (
362
+ brightness , brightness , brightness )
347
363
else :
348
- brightness_red , brightness_green , brightness_blue = brightness [0 ], brightness [1 ], brightness [2 ]
364
+ brightness_red , brightness_green , brightness_blue = (
365
+ brightness [0 ], brightness [1 ], brightness [2 ])
349
366
if inplace :
350
367
for i , x in enumerate (val ):
351
368
if isinstance (x , CHSV ):
@@ -369,14 +386,18 @@ def gamma_adjust(val, gamma_value=None, brightness=1.0, inplace=False):
369
386
gamma_red , gamma_green , gamma_blue = GFACTOR , GFACTOR , GFACTOR
370
387
elif isinstance (gamma_value , float ):
371
388
# Single gamma value provided, apply to R,G,B
372
- gamma_red , gamma_green , gamma_blue = gamma_value , gamma_value , gamma_value
389
+ gamma_red , gamma_green , gamma_blue = (
390
+ gamma_value , gamma_value , gamma_value )
373
391
else :
374
- gamma_red , gamma_green , gamma_blue = gamma_value [0 ], gamma_value [1 ], gamma_value [2 ]
392
+ gamma_red , gamma_green , gamma_blue = (
393
+ gamma_value [0 ], gamma_value [1 ], gamma_value [2 ])
375
394
if isinstance (brightness , float ):
376
395
# Single brightness value provided, apply to R,G,B
377
- brightness_red , brightness_green , brightness_blue = brightness , brightness , brightness
396
+ brightness_red , brightness_green , brightness_blue = (
397
+ brightness , brightness , brightness )
378
398
else :
379
- brightness_red , brightness_green , brightness_blue = brightness [0 ], brightness [1 ], brightness [2 ]
399
+ brightness_red , brightness_green , brightness_blue = (
400
+ brightness [0 ], brightness [1 ], brightness [2 ])
380
401
381
402
if isinstance (val , CHSV ):
382
403
val = CRGB (val )
@@ -397,24 +418,24 @@ def palette_lookup(palette, position):
397
418
398
419
position %= 1.0 # Wrap palette position in 0.0 to <1.0 range
399
420
400
- weight2 = position * len (palette ) # Scale position to palette length
401
- idx = int (floor (weight2 )) # Index of 'lower' color (0 to len-1)
402
- weight2 -= idx # Weighting of 'upper' color
421
+ weight2 = position * len (palette ) # Scale position to palette length
422
+ idx = int (floor (weight2 )) # Index of 'lower' color (0 to len-1)
423
+ weight2 -= idx # Weighting of 'upper' color
403
424
404
- color1 = palette [idx ] # Fetch 'lower' color
405
- idx = (idx + 1 ) % len (palette ) # Get index of 'upper' color
406
- color2 = palette [idx ] # Fetch 'upper' color
425
+ color1 = palette [idx ] # Fetch 'lower' color
426
+ idx = (idx + 1 ) % len (palette ) # Get index of 'upper' color
427
+ color2 = palette [idx ] # Fetch 'upper' color
407
428
408
429
return mix (color1 , color2 , weight2 )
409
430
410
431
411
432
def expand_gradient (gradient , length ):
412
433
"""Convert gradient palette into standard equal-interval palette.
413
434
414
- :param sequence gradient: List or tuple of of 2-element lists/tuples containing
415
- position (0.0 to 1.0) and color (packed int, CRGB or CHSV). It's OK if the
416
- list/tuple elements are either lists OR tuples, but don't mix and match lists and
417
- tuples -- use all one or the other.
435
+ :param sequence gradient: List or tuple of of 2-element lists/tuples
436
+ containing position (0.0 to 1.0) and color (packed int, CRGB or CHSV).
437
+ It's OK if the list/tuple elements are either lists OR tuples, but
438
+ don't mix and match lists and tuples -- use all one or the other.
418
439
419
440
:returns: CRGB list, can be used with palette_lookup() function.
420
441
"""
@@ -443,7 +464,8 @@ def expand_gradient(gradient, length):
443
464
if pos <= x [0 ]:
444
465
above = - 1 - n
445
466
446
- r = gradient [above ][0 ] - gradient [below ][0 ] # Range between below, above
467
+ # Range between below, above
468
+ r = gradient [above ][0 ] - gradient [below ][0 ]
447
469
if r <= 0 :
448
470
newlist .append (gradient [below ][1 ]) # Use 'below' color only
449
471
else :
0 commit comments