This should work - just linearly scale the red and green values. Assuming your max red/green/blue value is 255
, and n
is in range 0 .. 100
R = (255 * n) / 100
G = (255 * (100 - n)) / 100
B = 0
(Amended for integer maths, tip of the hat to Ferrucio)
Another way to do would be to use a HSV colour model, and cycle the hue from 0 degrees
(red) to 120 degrees
(green) with whatever saturation and value suited you. This should give a more pleasing gradient.
Here's a demonstration of each technique - top gradient uses RGB, bottom uses HSV:
I already knew about the color escapes, I used them in my bash prompt a while ago. Thanks anyway.
What I wanted was to integrate it with the logging module, which I eventually did after a couple of tries and errors.
Here is what I end up with:
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
#The background is set with 40 plus the number of the color, and the foreground with 30
#These are the sequences need to get colored ouput
RESET_SEQ = "\033[0m"
COLOR_SEQ = "\033[1;%dm"
BOLD_SEQ = "\033[1m"
def formatter_message(message, use_color = True):
if use_color:
message = message.replace("$RESET", RESET_SEQ).replace("$BOLD", BOLD_SEQ)
else:
message = message.replace("$RESET", "").replace("$BOLD", "")
return message
COLORS = {
'WARNING': YELLOW,
'INFO': WHITE,
'DEBUG': BLUE,
'CRITICAL': YELLOW,
'ERROR': RED
}
class ColoredFormatter(logging.Formatter):
def __init__(self, msg, use_color = True):
logging.Formatter.__init__(self, msg)
self.use_color = use_color
def format(self, record):
levelname = record.levelname
if self.use_color and levelname in COLORS:
levelname_color = COLOR_SEQ % (30 + COLORS[levelname]) + levelname + RESET_SEQ
record.levelname = levelname_color
return logging.Formatter.format(self, record)
And to use it, create your own Logger:
# Custom logger class with multiple destinations
class ColoredLogger(logging.Logger):
FORMAT = "[$BOLD%(name)-20s$RESET][%(levelname)-18s] %(message)s ($BOLD%(filename)s$RESET:%(lineno)d)"
COLOR_FORMAT = formatter_message(FORMAT, True)
def __init__(self, name):
logging.Logger.__init__(self, name, logging.DEBUG)
color_formatter = ColoredFormatter(self.COLOR_FORMAT)
console = logging.StreamHandler()
console.setFormatter(color_formatter)
self.addHandler(console)
return
logging.setLoggerClass(ColoredLogger)
Just in case anyone else needs it.
Be careful if you're using more than one logger or handler: ColoredFormatter
is changing the record object, which is passed further to other handlers or propagated to other loggers. If you have configured file loggers etc. you probably don't want to have the colors in the log files. To avoid that, it's probably best to simply create a copy of record
with copy.copy()
before manipulating the levelname attribute, or to reset the levelname to the previous value, before returning the formatted string (credit to Michael in the comments).
Best Answer
Its about endianness.
RGB is a byte-order. But a deliberate implementation choice of most vanilla Graphics libraries is that they treat colours as unsigned 32-bit integers internally, with the three (or four, as alpha is typically included) components packed into the integer.
On a little-endian machine (such as x86) the integer 0x01020304 will actually be stored in memory as 0x04030201. And thus 0x00BBGGRR will be stored as 0xRRGGBB00!
So the term BGR (and BGRA etc) is a leaky abstraction where the graphics library is explaining how the integer is logically ordered, so as to make your code that is directly accessing the colour components individually more readable.
Remember that bitmaps are usually accessed by more parts of the hardware than your processor, and the endian that is specified by, say, conventional display adapters, is not necessarily the same as the endian of your CPU. At the level of manipulating the channels in the pixel its no problem for a CPU to extract the fields whatever their order; its purely a programmer understanding the labelling thing.