Created
December 11, 2024 18:38
-
-
Save Mason-McGough/d5ef8e5a343ef8fe715b219fe407f727 to your computer and use it in GitHub Desktop.
Color scheme generation app based on "A Math-Based Approach to Color Theory" by Ethan Gardner
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Based on "A Math-Based Approach to Color Theory" by Ethan Gardner | |
- ethangardner.com/posts/color-theory-math/ | |
""" | |
import colorsys | |
import gradio as gr | |
from PIL import Image, ImageDraw | |
def complementary_color_scheme(base_color_hsv): | |
scheme_colors = [ | |
base_color_hsv, | |
((base_color_hsv[0] + 0.5) % 1, base_color_hsv[1], base_color_hsv[2]) | |
] | |
return scheme_colors | |
def split_complementary_color_scheme(base_color_hsv): | |
scheme_colors = [ | |
base_color_hsv, | |
((base_color_hsv[0] + 0.4) % 1, base_color_hsv[1], base_color_hsv[2]), | |
((base_color_hsv[0] + 0.6) % 1, base_color_hsv[1], base_color_hsv[2]) | |
] | |
return scheme_colors | |
def triadic_color_scheme(base_color_hsv): | |
scheme_colors = [ | |
base_color_hsv, | |
((base_color_hsv[0] + 1/3) % 1, base_color_hsv[1], base_color_hsv[2]), | |
((base_color_hsv[0] + 2/3) % 1, base_color_hsv[1], base_color_hsv[2]) | |
] | |
return scheme_colors | |
def tetradic_color_scheme(base_color_hsv): | |
scheme_colors = [ | |
base_color_hsv, | |
((base_color_hsv[0] + 0.25) % 1, base_color_hsv[1], base_color_hsv[2]), | |
((base_color_hsv[0] + 0.5) % 1, base_color_hsv[1], base_color_hsv[2]), | |
((base_color_hsv[0] + 0.75) % 1, base_color_hsv[1], base_color_hsv[2]) | |
] | |
return scheme_colors | |
def monochrome_color_scheme(base_color_hsv): | |
return (base_color_hsv,) | |
def analogous_color_scheme(base_color_hsv): | |
scheme_colors = [ | |
base_color_hsv, | |
((base_color_hsv[0] + 0.05) % 1, base_color_hsv[1], base_color_hsv[2]), | |
((base_color_hsv[0] - 0.05) % 1, base_color_hsv[1], base_color_hsv[2]) | |
] | |
return scheme_colors | |
color_scheme_map = { | |
"complementary": complementary_color_scheme, | |
"split-complementary": split_complementary_color_scheme, | |
"triadic": triadic_color_scheme, | |
"tetradic": tetradic_color_scheme, | |
"monochrome": monochrome_color_scheme, | |
"analogous": analogous_color_scheme | |
} | |
def generate_color_scheme(base_color_hsv, scheme_type): | |
try: | |
scheme_fn = color_scheme_map[scheme_type] | |
except KeyError as e: | |
raise ValueError("Invalid color scheme") from e | |
return scheme_fn(base_color_hsv) | |
def color_scheme_generator(base_color_dropdown, scheme_type_dropdown): | |
# Convert hex value to tuple of integers | |
base_color = tuple(int(base_color_dropdown.lstrip("#")[i:i + 2], 16) for i in (0, 2, 4)) | |
# Convert base color from RGB to HSV | |
base_color_hsv = colorsys.rgb_to_hsv(*[c / 255.0 for c in base_color]) | |
# Generate color scheme | |
scheme_colors = generate_color_scheme(base_color_hsv, scheme_type_dropdown) | |
# Create a color palette image | |
palette_width = 400 | |
palette_height = 300 | |
n_rows = 6 | |
palette = Image.new("RGB", (palette_width, palette_height)) | |
draw = ImageDraw.Draw(palette) | |
color_width = palette_width // len(scheme_colors) | |
row_height = palette_height // n_rows | |
r = 0 | |
for r in range(n_rows): | |
for i, color in enumerate(scheme_colors): | |
# Adjust value of color based on row | |
color_adj = list(color) | |
# Places the base value at the top of the palette | |
# color_adj[2] = (1.0 - r / n_rows) if r > 0 else color[2] | |
# Ignores base value and generates a range across rows | |
color_adj[2] = 1.0 - r / n_rows | |
color_adj = tuple(color_adj) | |
# Convert scheme colors from HSV to RGB | |
color_rgb = tuple(round(c * 255) for c in colorsys.hsv_to_rgb(*color_adj)) | |
# Draw color rectangle in image | |
draw.rectangle( | |
[i * color_width, r * row_height, | |
(i + 1) * color_width, (r + 1) * row_height], | |
fill=color_rgb | |
) | |
return palette | |
# Define the base color dropdown | |
base_color_dropdown = gr.ColorPicker( | |
label="Select Base Color (RGB)" | |
) | |
# Define the color scheme type dropdown | |
scheme_type_dropdown = gr.Dropdown( | |
choices=color_scheme_map.keys(), | |
label="Select Color Scheme Type", | |
value="complementary" | |
) | |
iface = gr.Interface( | |
fn=color_scheme_generator, | |
inputs=[base_color_dropdown, scheme_type_dropdown], | |
outputs="image" | |
) | |
iface.launch() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment