pimoroni / unicorn-hat

Python library for Unicorn pHAT and HAT. 32 or 64 blinding ws2812 pixels for your Raspberry Pi
https://shop.pimoroni.com/products/unicorn-hat
MIT License
370 stars 131 forks source link

Added hex color support #111

Closed ardek66 closed 5 years ago

Gadgetoid commented 6 years ago

Just realised this doesn't work in Python 2.7. Back to the drawing board!

I think int("AABBCC", 16) followed by bit-shifting and masking may be the best approach, or possibly a one-liner that uses struct like:

>>> import struct
>>> hex_colour = "112233"
>>> tuple([ord(_) for _ in struct.pack('>I', int(hex_colour, 16))[1:]])
(17, 34, 51)

And for shorthand colour support, this would expand "ABC" to "AABBCC":

>>> "".join(map(lambda x: x*2, "ABC"))
"AABBCC"

That said. I'm still not totally convinced that supporting string hex colours is valuable, since you can expand HTML colours quite trivially into native hexadecimal notation:

unicornhat.set_pixel(0x11, 0x22, 0x33)

Which works already, and would be the same as:

unicornhat.set_pixel("#112233")
ardek66 commented 6 years ago

So should i close this?

Gadgetoid commented 6 years ago

I'm not sure! Counter to my argument some users may build, for example, Flask applications which accept HTML colours as RESTful URL arguments, like: /set_pixel/x/y/FF00CC. That's a heck of an edge case to support though. I'll see what people think!

Pyroseza commented 6 years ago

I like the idea of hex colour, let me know if I can help out with this. Have a look at some of the solutions here: https://stackoverflow.com/questions/29643352/converting-hex-to-rgb-value-in-python

Pyroseza commented 6 years ago

More specifically this code snippet:

h = input('Enter hex: ').lstrip('#')
print('RGB =', tuple(int(h[i:i+2], 16) for i in (0, 2 ,4)))

Sample:

Enter hex: #B4FBB8
RGB = (180, 251, 184)
Pyroseza commented 6 years ago

As a function this could be:

def h2rgb(h):
    if len(h) == 3:
        h = ‘’.join(map(lambda x: x*2, h))
    if len(h) != 6:
        print(‘incorrect format, should be 3 or 6 chars’)
        #return black if incorrect???
        return (0, 0, 0)
    rgb = tuple(int(h[i:i+2], 16) for i in (0, 2 ,4))
    return rgb

Usage:

h = input('Enter hex: ').lstrip('#')
rgb = h2rgb(h)
print('RGB =', rgb)
Pyroseza commented 6 years ago

Just chop and change as needed, I’ve tested the code it works quite well

python playground

ardek66 commented 6 years ago

Thanks @Pyroseza !

Gadgetoid commented 6 years ago

I've been pointed towards Dave's PyCamera colour module for a canonical example of how to pull this off:

https://github.com/waveform80/picamera/blob/974540f38793c79c69405948e2fffafb3a1025dd/picamera/color.py#L547-L575

In this instance it requires that the colour string start with an #, and uses that, plus the length (4 or 7) to detect a valid hex colour.

I suspect I've probably been barking up the wrong tree with the lack of #, and this method is correct.

        if isinstance(s, bytes):
            s = s.decode('ascii')
        if s.startswith('#'):
            if len(s) == 7:
                r, g, b = (
                    int(s[1:3], base=16),
                    int(s[3:5], base=16),
                    int(s[5:7], base=16)
                    )
            elif len(s) == 4:
                r, g, b = (
                    int(s[1:2], base=16) * 0x11,
                    int(s[2:3], base=16) * 0x11,
                    int(s[3:4], base=16) * 0x11
                    )

While verbose, it's also pretty clear about its intent and function, which is always a good thing.

Gadgetoid commented 5 years ago

This has been up in the air for a while- to start the ball rolling again, I'm going to close this PR and raise this as a feature request (linking this PR) against both the Unicorn HAT and Unicorn HAT HD libraries.