Mar 10

Color Palette in Python

I though this might be of use to somebody. It got some rough edges but is good enoughâ„¢ for my needs.

# -*- coding: utf-8 -*-
from colorsys import rgb_to_hls, hls_to_rgb
from PIL import Image
import struct
from cStringIO import StringIO

__author__ = 'Simon Pantzare'

class Color(object):
    def __init__(self, r, g, b):
        self.r = r
        self.g = g
        self.b = b
        self.h, self.l, self.s = rgb_to_hls(r/255.0, g/255.0, b/255.0)
        self.h *= 360
        self.l *= 100
        self.s *= 100


class RangeImage(object):
    def __init__(
            self, 
            start_rgb, 
            lightness_pc, 
            hue_dg,
            dim=(200,50)
            ):
        """
        lightness_pc 
            Range 0-50%.

        hue_dg
            Range 0-180 degrees.
        """
        self.start_color = Color(*start_rgb)
        self.lightness_pc = lightness_pc
        self.hue_dg = hue_dg
        self.width_px = dim[0]
        self.height_px = dim[1]

    def h_vector(self):
        assert 0 <= self.hue_dg and self.hue_dg <= 180
        start_h = self.start_color.h - self.hue_dg
        if start_h < 0:
            start_h = 360 + start_h
        incr = float(self.hue_dg*2) / self.height_px
        return [(start_h+i*incr)%(360+1) for i in range(0, self.height_px)]

    def l_vector(self):
        assert 0 <= self.lightness_pc and self.lightness_pc <= 50
        minv = max(self.start_color.l - self.lightness_pc, 0)
        incr = float(self.lightness_pc*2) / self.width_px
        return [min(minv+i*incr,100) for i in range(0, self.width_px)]

    def image(self):
        arr = [[0] * self.width_px for _ in range(self.height_px)] # the outer list comprehension IS needed
        hues = self.h_vector()
        ls = self.l_vector()
        sat = self.start_color.s / 100

        for row_idx, row in enumerate(arr):
            h = hues[row_idx] / 360.0
            for col_idx, px in enumerate(row):
                l = ls[col_idx] / 100.0
                r,g,b = hls_to_rgb(h, l, sat)
                arr[row_idx][col_idx] = struct.pack(
                        "BBBB", 
                        int(r*255),
                        int(g*255),
                        int(b*255),
                        255
                        )

        buf = StringIO()
        [[buf.write(px) for px in row] for row in arr]
        buf.seek(0)

        im = Image.frombuffer(
                "RGBA", 
                (self.width_px, self.height_px), 
                buf.read(),
                "raw",
                "RGBA",
                0,
                1
                )
        return im

Output for RangeImage((0, 255, 0), 50, 180, (200, 100)).image():

RangeImage((0, 255, 0), 50, 180, (200, 100))



Simon Pantzare
Simon Pantzare, also available on
Facebook,
Twitter,
Google+,
Reddit,
Github (dev blog).
Ask me anything.