Advanced Topics

This section covers advanced color operations, techniques, and best practices for using Colorium in complex applications.

Overview

TopicDescription
Performance OptimizationSpeed up color operations
Memory ManagementEfficient color handling
Custom Color SpacesExtend with new color spaces
IntegrationUse with other libraries
Production TipsBest practices for production

Performance Optimization

Batch Processing

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from colorium import Color

def process_batch(colors, operation, amount):
    """Process multiple colors efficiently"""
    results = []
    for color in colors:
        if operation == "lighten":
            result = color.clone().lighter(amount)
        elif operation == "darken":
            result = color.clone().darker(amount)
        elif operation == "saturate":
            result = color.clone().saturate(amount)
        else:
            result = color.clone()
        results.append(result)
    return results

# Batch process colors
colors = [
    Color(100, 150, 200),
    Color(255, 0, 0),
    Color(0, 255, 0),
    Color(0, 0, 255)
]

results = process_batch(colors, "lighten", 0.2)

Caching

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
from colorium import Color
from functools import lru_cache

class ColorCache:
    def __init__(self):
        self.conversion_cache = {}
        self.similarity_cache = {}

    def get_conversion(self, color, target_space):
        """Cache color conversions"""
        key = ((color.red, color.green, color.blue), target_space)
        if key not in self.conversion_cache:
            methods = {
                'hsl': color.to_hsl,
                'hwb': color.to_hwb,
                'cmyk': color.to_cmyk,
                'hex': color.to_hex_string
            }
            self.conversion_cache[key] = methods.get(target_space, lambda: None)()
        return self.conversion_cache[key]

    def get_similarity(self, color1, color2):
        """Cache similarity calculations"""
        key = (
            (color1.red, color1.green, color1.blue),
            (color2.red, color2.green, color2.blue)
        )
        if key not in self.similarity_cache:
            self.similarity_cache[key] = color1.similarity(color2)
        return self.similarity_cache[key]

# Usage
cache = ColorCache()
color = Color(100, 150, 200)

# First call calculates
hsl1 = cache.get_conversion(color, 'hsl')

# Second call uses cache
hsl2 = cache.get_conversion(color, 'hsl')

Lazy Evaluation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from colorium import Color

class LazyColor:
    def __init__(self, red, green, blue):
        self._red = red
        self._green = green
        self._blue = blue
        self._color = None
        self._hsl = None

    @property
    def color(self):
        if self._color is None:
            self._color = Color(self._red, self._green, self._blue)
        return self._color

    @property
    def hsl(self):
        if self._hsl is None:
            self._hsl = self.color.to_hsl()
        return self._hsl

# Usage
lazy = LazyColor(100, 150, 200)
# Color is not created until needed
hsl = lazy.hsl  # Color is created and HSL calculated

Memory Management

Object Pooling

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from colorium import Color
from collections import deque

class ColorPool:
    def __init__(self, size=100):
        self.pool = deque(maxlen=size)

    def get_color(self, red, green, blue):
        """Get color from pool or create new"""
        # Check pool for exact match
        for color in self.pool:
            if (color.red == red and
                color.green == green and
                color.blue == blue):
                return color

        # Create new color and add to pool
        color = Color(red, green, blue)
        self.pool.append(color)
        return color

    def clear(self):
        """Clear the pool"""
        self.pool.clear()

# Usage
pool = ColorPool()
color1 = pool.get_color(255, 0, 0)
color2 = pool.get_color(255, 0, 0)  # Returns from pool

print(color1 is color2)  # True (same object)

Memory-Efficient Storage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from colorium import Color

class CompactColorStorage:
    def __init__(self):
        self.colors = []
        self.metadata = []

    def add_color(self, color, metadata=None):
        """Store color with metadata"""
        # Store as tuple for memory efficiency
        self.colors.append((color.red, color.green, color.blue))
        self.metadata.append(metadata)

    def get_color(self, index):
        """Retrieve color by index"""
        if 0 <= index < len(self.colors):
            r, g, b = self.colors[index]
            return Color(r, g, b)
        return None

    def get_metadata(self, index):
        """Get metadata by index"""
        if 0 <= index < len(self.metadata):
            return self.metadata[index]
        return None

    def __len__(self):
        return len(self.colors)

# Usage
storage = CompactColorStorage()
storage.add_color(Color(255, 0, 0), {'name': 'Red'})
storage.add_color(Color(0, 0, 255), {'name': 'Blue'})

color = storage.get_color(0)
print(color.to_hex_string())  # #FF0000

Custom Color Spaces

Extending Color Spaces

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
from colorium import Color
from colorium.converters import rgb_to_hsl, hsl_to_rgb

def rgb_to_custom(r, g, b):
    """Convert RGB to custom color space"""
    # Example: Simple linear transformation
    return {
        'x': r / 255.0,
        'y': g / 255.0,
        'z': b / 255.0
    }

def custom_to_rgb(x, y, z):
    """Convert custom color space to RGB"""
    return {
        'r': int(x * 255),
        'g': int(y * 255),
        'b': int(z * 255)
    }

class CustomColor(Color):
    @classmethod
    def from_custom(cls, x, y, z, opacity=1.0):
        """Create color from custom space"""
        rgb = custom_to_rgb(x, y, z)
        return cls(rgb['r'], rgb['g'], rgb['b'], opacity)

    def to_custom(self):
        """Convert to custom space"""
        return rgb_to_custom(self.red, self.green, self.blue)

# Usage
color = CustomColor.from_custom(1.0, 0.5, 0.0)
custom = color.to_custom()
print(custom)  # {'x': 1.0, 'y': 0.5, 'z': 0.0}

Adding New Color Space

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
from colorium import Color, from_hsl

def add_color_space(name, to_rgb_func, from_rgb_func):
    """Add a custom color space to Colorium"""

    # Add factory method
    def from_func(self, *args, **kwargs):
        rgb = from_rgb_func(*args)
        return Color(rgb['r'], rgb['g'], rgb['b'], kwargs.get('opacity', 1.0))

    # Add conversion method
    def to_func(self):
        return to_rgb_func(self.red, self.green, self.blue)

    setattr(Color, f'from_{name}', classmethod(from_func))
    setattr(Color, f'to_{name}', to_func)

# Example: HSV color space
def hsv_to_rgb(h, s, v):
    """HSV to RGB conversion"""
    # Simplified conversion
    c = v * s
    x = c * (1 - abs((h / 60) % 2 - 1))
    m = v - c

    if h < 60:
        r, g, b = c, x, 0
    elif h < 120:
        r, g, b = x, c, 0
    elif h < 180:
        r, g, b = 0, c, x
    elif h < 240:
        r, g, b = 0, x, c
    elif h < 300:
        r, g, b = x, 0, c
    else:
        r, g, b = c, 0, x

    return {
        'r': int((r + m) * 255),
        'g': int((g + m) * 255),
        'b': int((b + m) * 255)
    }

def rgb_to_hsv(r, g, b):
    """RGB to HSV conversion"""
    r_n = r / 255.0
    g_n = g / 255.0
    b_n = b / 255.0

    max_val = max(r_n, g_n, b_n)
    min_val = min(r_n, g_n, b_n)
    delta = max_val - min_val

    if delta == 0:
        h = 0
    elif max_val == r_n:
        h = 60 * (((g_n - b_n) / delta) % 6)
    elif max_val == g_n:
        h = 60 * (((b_n - r_n) / delta) + 2)
    else:
        h = 60 * (((r_n - g_n) / delta) + 4)

    s = 0 if max_val == 0 else delta / max_val
    v = max_val

    return {'h': h, 's': s, 'v': v}

# Add HSV color space
add_color_space('hsv', hsv_to_rgb, rgb_to_hsv)

# Usage
color = Color.from_hsv(0, 1.0, 1.0)  # Red
hsv = color.to_hsv()
print(hsv)  # {'h': 0, 's': 1.0, 'v': 1.0}

Integration with Other Libraries

With Pillow

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from colorium import Color
from PIL import Image

def image_to_colors(image_path):
    """Extract colors from image using Pillow"""
    image = Image.open(image_path)
    pixels = image.getdata()

    colors = []
    for r, g, b in pixels:
        color = Color(r, g, b)
        colors.append(color)

    return colors

def create_image(colors, size=(100, 100)):
    """Create image from colors using Pillow"""
    image = Image.new('RGB', size)
    pixels = image.load()

    for i, color in enumerate(colors):
        x = i % size[0]
        y = i // size[0]
        if y < size[1]:
            pixels[x, y] = (color.red, color.green, color.blue)

    return image

# Usage
# colors = image_to_colors('image.jpg')
# create_image(colors[:100]).save('output.jpg')

With NumPy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
from colorium import Color
import numpy as np

def colors_to_array(colors):
    """Convert colors to NumPy array"""
    return np.array([
        [color.red, color.green, color.blue]
        for color in colors
    ])

def array_to_colors(array):
    """Convert NumPy array to colors"""
    return [
        Color(int(r), int(g), int(b))
        for r, g, b in array
    ]

def batch_manipulate(array, operation, amount):
    """Manipulate colors in NumPy array"""
    colors = array_to_colors(array)

    for color in colors:
        if operation == 'lighten':
            color.lighter(amount)
        elif operation == 'darken':
            color.darker(amount)
        elif operation == 'saturate':
            color.saturate(amount)

    return colors_to_array(colors)

# Usage
array = np.array([
    [255, 0, 0],
    [0, 255, 0],
    [0, 0, 255]
])

lightened = batch_manipulate(array, 'lighten', 0.2)
print(lightened)

With Matplotlib

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from colorium import Color
import matplotlib.pyplot as plt

def plot_colors(colors, title="Colors"):
    """Visualize colors using matplotlib"""
    fig, ax = plt.subplots(1, len(colors), figsize=(len(colors) * 2, 3))

    for i, color in enumerate(colors):
        rgb = (color.red/255, color.green/255, color.blue/255)
        ax[i].imshow([[rgb]])
        ax[i].axis('off')
        ax[i].set_title(color.to_hex_string())

    plt.suptitle(title)
    plt.tight_layout()
    plt.show()

def create_color_gradient(colors, steps=100):
    """Create gradient visualization"""
    gradient = []
    for i in range(len(colors) - 1):
        for j in range(steps):
            ratio = j / steps
            color = colors[i].blend(colors[i+1], ratio)
            gradient.append(color)
    return gradient

# Usage
colors = [
    Color(255, 0, 0),
    Color(255, 255, 0),
    Color(0, 255, 0)
]

gradient = create_color_gradient(colors)
# plot_colors(gradient[:20])

Production Tips

Error Handling

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from colorium import Color, from_string

def safe_color_operation(color, operation, *args):
    """Safely perform color operations"""
    try:
        if operation == 'lighter':
            color.lighter(*args)
        elif operation == 'darker':
            color.darker(*args)
        elif operation == 'saturate':
            color.saturate(*args)
        else:
            raise ValueError(f"Unknown operation: {operation}")
        return color
    except Exception as e:
        print(f"Error in color operation: {e}")
        return color

# Usage
color = Color(100, 150, 200)
result = safe_color_operation(color, 'lighter', 0.3)

Logging

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from colorium import Color
import logging

class ColorLogger:
    def __init__(self, logger=None):
        self.logger = logger or logging.getLogger(__name__)

    def log_operation(self, operation, color, result):
        """Log color operations"""
        self.logger.info(
            f"{operation}: {color.to_hex_string()}{result.to_hex_string()}"
        )

    def log_error(self, operation, color, error):
        """Log color errors"""
        self.logger.error(
            f"{operation} failed for {color.to_hex_string()}: {error}"
        )

# Usage
logger = ColorLogger()
color = Color(100, 150, 200)
result = color.clone().lighter(0.2)
logger.log_operation('lighten', color, result)

Validation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from colorium import Color

def validate_color(color):
    """Validate color values"""
    if not isinstance(color, Color):
        return False

    if not (0 <= color.red <= 255):
        return False
    if not (0 <= color.green <= 255):
        return False
    if not (0 <= color.blue <= 255):
        return False
    if not (0 <= color.opacity <= 1):
        return False

    return True

def validate_color_list(colors):
    """Validate list of colors"""
    return all(validate_color(c) for c in colors)

# Usage
colors = [
    Color(100, 150, 200),
    Color(255, 0, 0),
    Color(0, 255, 0)
]

if validate_color_list(colors):
    print("All colors are valid")

Next Steps


Previous: Named Colors Next: API Reference →

On this page
20 sections