I'm rewriting a full color Mandelbrot Set explorer in Python using tkinter. For it, I need to be able to convert a Tuple[int, int, int]
into a hex string in the form #123456
. Here are example uses of the two variants that I came up with:
>>>rgb_to_hex(123, 45, 6)
'#7b2d06'
>>>rgb_to_hex(99, 88, 77)
'#63584d'
>>>tup_rgb_to_hex((123, 45, 6))
'#7b2d06'
>>>tup_rgb_to_hex((99, 88, 77))
'#63584d'
>>>rgb_to_hex(*(123, 45, 6))
'#7b2d06'
>>>rgb_to_hex(*(99, 88, 77))
'#63584d'
The functions I've come up with are very simple, but intolerably slow. This code is a rare case where performance is a real concern. It will need to be called once per pixel, and my goal is to support the creation of images up to 50,000x30,000 pixels (1500000000 in total). 100 million executions take ~300 seconds:
>>>timeit.timeit(lambda: rgb_to_hex(255, 254, 253), number=int(1e8))
304.3993674000001
Which, unless my math is fubared, means this function alone will take 75 minutes in total for my extreme case.
I wrote two versions. The latter was to reduce redundancy (and since I'll be handling tuples anyways), but it was even slower, so I ended up just using unpacking on the first version:
# Takes a tuple instead
>>>timeit.timeit(lambda: tup_rgb_to_hex((255, 254, 253)), number=int(1e8))
342.8174099
# Unpacks arguments
>>>timeit.timeit(lambda: rgb_to_hex(*(255, 254, 253)), number=int(1e8))
308.64342439999973
The code:
from typing import Tuple
def _channel_to_hex(color_val: int) -> str:
raw: str = hex(color_val)[2:]
return raw.zfill(2)
def rgb_to_hex(red: int, green: int, blue: int) -> str:
return "#" + _channel_to_hex(red) + _channel_to_hex(green) + _channel_to_hex(blue)
def tup_rgb_to_hex(rgb: Tuple[int, int, int]) -> str:
return "#" + "".join([_channel_to_hex(c) for c in rgb])
I'd prefer to be able to use the tup_
variant for cleanliness, but there may not be a good way to automate the iteration with acceptable amounts of overhead.
Any performance-related tips (or anything else if you see something) are welcome.
It will need to be called once per pixel
- this is suspicious. What code is accepting a hex string? High-performance graphics code should be dealing in RGB byte triples packed into an int32. \$\endgroup\$number-guessing-game
tag. I'm not sure why that was added. \$\endgroup\$