Skip to content

Commit

Permalink
Hued, update 1.0.1
Browse files Browse the repository at this point in the history
  • Loading branch information
Infinitode committed Sep 25, 2024
1 parent 61cfa29 commit fa04448
Show file tree
Hide file tree
Showing 8 changed files with 637 additions and 9 deletions.
17 changes: 16 additions & 1 deletion Tests/test_analysis.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from hued.analysis import is_neutral, brightness, is_pastel, is_muted, is_vibrant
from hued.analysis import is_neutral, brightness, is_pastel, is_muted, is_vibrant, color_contrast, get_text_color_from_background

def test_is_neutral():
print("Testing Neutral Color Check...")
Expand Down Expand Up @@ -40,12 +40,27 @@ def test_is_vibrant():
assert is_vibrant(non_vibrant_color) == False, "Expected non-vibrant color to return False."
print(f"Vibrant Color Test Passed: {vibrant_color} is vibrant.")

def test_color_contrast():
print("Testing Color Contrast...")
color1 = (0, 255, 0) # Green
color2 = (128, 128, 128) # Gray
assert color_contrast(color1, color2) == 2.839124370809266, "Expected a contrast ratio of 2.839124370809266."
print("Color Contrast Test Passed.")

def test_text_mode():
print("Testing Text Color, Based On A Background Color...")
background_color = (0, 0, 255) # Vibrant Blue
assert get_text_color_from_background(background_color) == "light", "Expected text color, to be `light`."
print("Text Background Color Test Passed.")

def run_tests():
test_is_neutral()
test_brightness()
test_is_pastel()
test_is_muted()
test_is_vibrant()
test_color_contrast()
test_text_mode()
print("All tests passed!")

if __name__ == "__main__":
Expand Down
19 changes: 19 additions & 0 deletions Tests/test_conversions.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,22 @@ def test_cmyk_to_rgb():
assert result == expected_rgb, f"Expected {expected_rgb}, but got {result}"
print(f"CMYK({c}, {m}, {y}, {k}) -> RGB: {result}")

def test_hsl_to_hex():
hsl = (0, 1, 0.5)
result = hsl_to_hex(hsl)
assert result == "#FF0000", f"Expected '#FF0000', but got {result}"
print(f"HSL converted to HEX successfully: {result}")

def test_blend_colors():
print("Testing blend_colors...")
color1 = (255, 0, 0) # Red
color2 = (0, 0, 255) # Blue
ratio = 0.5 # Equal blend
expected_color = (127, 0, 127) # Purple (midpoint blend of red and blue)
result = blend_colors(color1, color2, ratio)
assert result == expected_color, f"Expected {expected_color}, but got {result}"
print(f"blend_colors({color1}, {color2}, {ratio}) -> RGB: {result}")

def run_tests():
test_rgb_to_hex()
test_hex_to_rgb()
Expand All @@ -73,6 +89,9 @@ def run_tests():
test_hsv_to_rgb()
test_rgb_to_cmyk()
test_cmyk_to_rgb()
test_hsl_to_hex()
test_blend_colors()

print("All tests passed!")

if __name__ == "__main__":
Expand Down
60 changes: 60 additions & 0 deletions Tests/test_palettes.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,47 @@ def test_generate_monochromatic():
assert result == expected_monochromatic, f"Expected {expected_monochromatic}, but got {result}"
print(f"Monochromatic Palette: {result}")

def test_generate_tetradic():
print("Testing Tetradic Palette...")
base_color = (255, 60, 52) # Example base color (Red)
palette = ColorPalette(base_color)
expected_tetradic = [
(255, 60, 52), # Base color
(145, 255, 51), # Tetradic 1
(51, 247, 255), # Tetradic 2
(161, 51, 255) # Tetradic 3
]
result = palette.generate_tetradic()
assert result == expected_tetradic, f"Expected {expected_tetradic}, but got {result}"
print(f"Tetradic Palette: {result}")

def test_generate_square():
print("Testing Square Palette...")
base_color = (255, 60, 52) # Example base color (Red)
palette = ColorPalette(base_color)
expected_square = [
(255, 60, 52), # Base color
(145, 255, 51), # Square 1
(51, 247, 255), # Square 2
(161, 51, 255) # Square 3
]
result = palette.generate_square()
assert result == expected_square, f"Expected {expected_square}, but got {result}"
print(f"Square Palette: {result}")

def test_generate_split_complementary():
print("Testing Split-Complementary Palette...")
base_color = (255, 60, 52) # Example base color (Red)
palette = ColorPalette(base_color)
expected_split_complementary = [
(255, 60, 52), # Base color
(51, 255, 161), # Split Complementary 1
(51, 145, 255) # Split Complementary 2
]
result = palette.generate_split_complementary()
assert result == expected_split_complementary, f"Expected {expected_split_complementary}, but got {result}"
print(f"Split-Complementary Palette: {result}")

def test_palette_to_hex():
print("Testing Palette to HEX conversion...")
base_color = (255, 60, 52) # Red
Expand All @@ -64,13 +105,32 @@ def test_generate_random_palette():
assert isinstance(result, dict), "Expected a dictionary for the random palette."
print("Random Palette:", result)

def test_generate_random_color():
print("Testing Random Color Generation...")
palette = ColorPalette((0, 0, 0))
result = palette.generate_random_color()
assert isinstance(result, dict), "Expected a dictionary for the random color."
print("Random Color:", result)

def test_generate_random_hex_colors():
print("Testing Random HEX Colors Generation...")
palette = ColorPalette((0, 0, 0))
result = palette.generate_random_hex_colors()
assert isinstance(result, list), "Expected a list for the random HEX colors."
print("Random HEX Colors:", result)

def run_tests():
test_generate_complementary()
test_generate_analogous()
test_generate_triadic()
test_generate_monochromatic()
test_generate_tetradic()
test_generate_square()
test_generate_split_complementary()
test_palette_to_hex()
test_generate_random_palette()
test_generate_random_color()
test_generate_random_hex_colors()
print("All tests passed!")

if __name__ == "__main__":
Expand Down
4 changes: 2 additions & 2 deletions hued/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from hued.colors import ColorManager
from hued.analysis import get_temperature, is_neutral, brightness, is_pastel, is_muted, is_vibrant
from hued.conversions import rgb_to_hex, hex_to_rgb, rgb_to_hsl, hsl_to_rgb, rgb_to_hsv, hsv_to_rgb, rgb_to_cmyk, cmyk_to_rgb
from hued.analysis import get_temperature, is_neutral, brightness, is_pastel, is_muted, is_vibrant, rgb_to_linear, get_luminance, get_vibrancy, color_contrast, get_text_color_from_background
from hued.conversions import rgb_to_hex, hex_to_rgb, rgb_to_hsl, hsl_to_rgb, rgb_to_hsv, hsv_to_rgb, rgb_to_cmyk, cmyk_to_rgb, blend_colors, hex_to_cmyk, hex_to_hsl, hex_to_hsv, hsv_to_cmyk, hsv_to_hex, hsv_to_hsl, hsl_to_cmyk, hsl_to_hex, hsl_to_hsv, cmyk_to_hex, cmyk_to_hsl, cmyk_to_hsv
from hued.palettes import ColorPalette
116 changes: 115 additions & 1 deletion hued/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,118 @@ def is_vibrant(rgb):
value_threshold = 0.7

# Check if the color is vibrant
return s > saturation_threshold and v > value_threshold
return s > saturation_threshold and v > value_threshold

def rgb_to_linear(rgb):
"""Convert RGB values to linear RGB.
The input RGB values should be in the range [0, 255]. This function
applies the sRGB transfer function to convert each RGB component
to its linear equivalent, which is useful for various color
calculations, including luminance and color mixing.
Parameters:
rgb (tuple): A tuple of three integers representing the RGB
values (r, g, b), each in the range [0, 255].
Returns:
list: A list of three floats representing the linear RGB values.
"""
r, g, b = rgb
return [
(c / 255) ** 2.2 if c > 0.04045 else c / 255 / 12.92 for c in (r, g, b)
]

def get_luminance(rgb):
"""Calculate the relative luminance of an RGB color.
This function converts the input RGB color to linear RGB and
then computes the relative luminance using the standard
formula based on the RGB color's linear components.
The coefficients used are based on the sRGB color space.
Parameters:
rgb (tuple): A tuple of three integers representing the RGB
values (r, g, b), each in the range [0, 255].
Returns:
float: The calculated relative luminance of the RGB color.
"""
r_linear, g_linear, b_linear = rgb_to_linear(rgb)
return 0.2126 * r_linear + 0.7152 * g_linear + 0.0722 * b_linear

def get_vibrancy(rgb):
"""Calculate the vibrancy of an RGB color.
This function computes vibrancy based on the chromaticity of the RGB values.
A higher value indicates a more vibrant color.
Parameters:
rgb (tuple): A tuple of three integers representing the RGB
values (r, g, b), each in the range [0, 255].
Returns:
float: The calculated vibrancy of the RGB color.
"""
r, g, b = rgb
max_color = max(r, g, b)
min_color = min(r, g, b)
if max_color == 0:
return 0 # Avoid division by zero; neutral color

vibrancy = (max_color - min_color) / max_color # A simple measure of vibrancy
return vibrancy

def color_contrast(color1, color2):
"""
Calculates the contrast ratio between two colors using their RGB values.
The contrast ratio is calculated based on the relative luminance of each color
and is used to determine the readability of text on different background colors.
The result is a number between 1 and 21, where a higher value indicates better
contrast.
Parameters:
color1 (tuple): The first RGB color as a tuple of three integers (R, G, B).
color2 (tuple): The second RGB color as a tuple of three integers (R, G, B).
Returns:
float: The contrast ratio between the two colors.
"""

L1 = get_luminance(color1)
L2 = get_luminance(color2)
if L1 > L2:
return (L1 + 0.05) / (L2 + 0.05)
else:
return (L2 + 0.05) / (L1 + 0.05)

def get_text_color_from_background(background_color):
"""Determines whether the text should be "light" or "dark" based on the background color.
Parameters:
background_color (tuple): The background RGB color as a tuple of three integers (R, G, B).
Returns:
str: "light" if the background is dark and vibrant, "dark" if the background is bright and muted.
"""
# Calculate luminance and vibrancy of the background color
luminance_value = get_luminance(background_color)
vibrancy_value = get_vibrancy(background_color)

# Enhanced decision logic based on luminance and vibrancy
if luminance_value < 0.3: # Dark background
if vibrancy_value > 0.4: # Vibrant dark colors
return "light" # Use light text for better readability
else:
return "dark" # Use dark text if it's a muted dark color
elif luminance_value < 0.6: # Medium background (transition zone)
if vibrancy_value > 0.5: # Bright but vibrant
return "dark" # Use dark text for readability
else:
return "light" # Use light text if the color is less vibrant
else: # Bright background
if vibrancy_value < 0.4: # Muted bright colors
return "dark" # Use dark text for readability
else:
return "light" # Use light text for vibrant bright colors
Loading

0 comments on commit fa04448

Please sign in to comment.