Home > Backend Development > Python Tutorial > Color Theory: Playing with Colors Programmatically

Color Theory: Playing with Colors Programmatically

Patricia Arquette
Release: 2024-11-26 07:24:11
Original
755 people have browsed it

Color Theory: Playing with Colors Programmatically

When I first started building Colorify Rocks, my color palette website, I had no idea how deep the rabbit hole of programmatic color manipulation would go. What started as a simple "let me build a color picker" project turned into a fascinating journey through color theory, mathematical color spaces, and accessibility considerations. Today, I want to share what I learned while building this tool, along with some Python code that might help you in your own color adventures.

It's Just Colors, How Hard Can It Be?

Oh, past me. How naive you were! My journey started with a simple goal: build a website where people could generate and save color palettes. Easy, right? Just grab a hex code and... wait, what's HSL? And why do we need RGB? And what in the world is CMYK?

Want to see what I'm talking about? Check out our color analysis for #3B49DF

Here's the first piece of code I wrote to handle color conversions, which now makes me chuckle at its simplicity:

class Color:
    def __init__(self, hex_code):
        self.hex = hex_code.lstrip('#')
        # Past me: "This is probably all I need!"
    def to_rgb(self):
        # My first "aha!" moment with color spaces
        r = int(self.hex[0:2], 16)
        g = int(self.hex[2:4], 16)
        b = int(self.hex[4:6], 16)
        return f"rgb({r},{g},{b})"
Copy after login

Everything is Math

Then came the moment I realized that colors are basically just math in disguise. Converting between color spaces meant diving into algorithms I hadn't touched since high school. Here's what the code evolved into

def _rgb_to_hsl(self):
    # This was my "mind-blown" moment
    r, g, b = [x/255 for x in (self.rgb['r'], self.rgb['g'], self.rgb['b'])]
    cmax, cmin = max(r, g, b), min(r, g, b)
    delta = cmax - cmin
    # The math that made me question everything I knew about colors
    h = 0
    if delta != 0:
        if cmax == r:
            h = 60 * (((g - b) / delta) % 6)
        elif cmax == g:
            h = 60 * ((b - r) / delta + 2)
        else:
            h = 60 * ((r - g) / delta + 4)
    l = (cmax + cmin) / 2
    s = 0 if delta == 0 else delta / (1 - abs(2 * l - 1))
    return {
        'h': round(h),
        's': round(s * 100),
        'l': round(l * 100)
    }
Copy after login

Colors Have Relationships

One of the most exciting features I built for Colorify Rocks was the color harmony generator. It turns out colors have relationships with each other, just like musical notes! Here's how I implemented color harmonies:

def get_color_harmonies(self, color):
    """
    This is probably my favorite piece of code in the entire project.
    It's like playing with a color wheel, but in code!
    """
    h, s, l = color.hsl['h'], color.hsl['s'], color.hsl['l']
    return {
        'complementary': self._get_complementary(h, s, l),
        'analogous': self._get_analogous(h, s, l),
        'triadic': self._get_triadic(h, s, l),
        'split_complementary': self._get_split_complementary(h, s, l)
    }
def _get_analogous(self, h, s, l):
    # The magic numbers that make designers happy
    return [
        self._hsl_to_hex((h - 30) % 360, s, l),
        self._hsl_to_hex(h, s, l),
        self._hsl_to_hex((h + 30) % 360, s, l)
    ]
Copy after login

Accessibility

The biggest eye-opener came when a user with color blindness submitted feedback. I had completely overlooked accessibility! This led me to implement color blindness simulation:

def simulate_color_blindness(self, color, type='protanopia'):
    """
    This feature wasn't in my original plan, but it became one of
    the most important parts of Colorify Rocks
    """
    matrices = {
        'protanopia': [
            [0.567, 0.433, 0],
            [0.558, 0.442, 0],
            [0, 0.242, 0.758]
        ],
        # Added more types after learning about different forms of color blindness
        'deuteranopia': [
            [0.625, 0.375, 0],
            [0.7, 0.3, 0],
            [0, 0.3, 0.7]
        ]
    }
    # Matrix multiplication that makes sure everyone can use our color palettes
    return self._apply_color_matrix(color, matrices[type])
Copy after login

As Colorify Rocks grew, designers started asking for more features. The big one? Shades and tints of colors. This led to some fun experimentation:

def get_color_variations(self, color, steps=10):
    """
    This started as a simple feature request and turned into
    one of our most-used tools
    """
    return {
        'shades': self._generate_shades(color, steps),
        'tints': self._generate_tints(color, steps),
        'tones': self._generate_tones(color, steps)
    }
Copy after login

The above is the detailed content of Color Theory: Playing with Colors Programmatically. For more information, please follow other related articles on the PHP Chinese website!

source:dev.to
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template