import colorsys from math import pow from typing import Tuple from datetime import datetime # Function to calculate relative luminance of a color def relative_luminance(rgb: Tuple[int, int, int]) -> float: def adjust(c: float) -> float: c = c / 255.0 return c / 12.92 if c <= 0.03928 else pow((c + 0.055) / 1.055, 2.4) r, g, b = rgb return 0.2126 * adjust(r) + 0.7152 * adjust(g) + 0.0722 * adjust(b) # Function to calculate contrast ratio def contrast_ratio(foreground: Tuple[int, int, int], background: Tuple[int, int, int]) -> float: lum1 = relative_luminance(foreground) lum2 = relative_luminance(background) if lum1 > lum2: return (lum1 + 0.05) / (lum2 + 0.05) return (lum2 + 0.05) / (lum1 + 0.05) # Generate HTML table def generate_html(colors: list): html = '' # Helper function to determine text color def get_text_color(hex_color): rgb = tuple(int(hex_color.lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) return "textwhite" if relative_luminance(rgb) < 0.5 else "textblack" # Helper function to determine text-shadow color def get_text_shadow(hex_color): rgb = tuple(int(hex_color.lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) return "bgwhite" if relative_luminance(rgb) >= 0.5 else "bgblack" # Store passing combinations for summary table summary_data = {bg[1]: {"name": bg[0], "AAA": [], "AA": [], "AALarge": []} for bg in colors} # Top row html += '
| BG → FG ↓ | '
for bg in colors:
text_color = get_text_color(bg[1])
html += f'{bg[0]} {bg[1]} | '
html += '
|---|---|
| {fg[0]} {fg[1]} | '
for bg in colors:
rgb_fg = tuple(int(fg[1].lstrip('#')[i:i+2], 16) for i in (0, 2, 4))
rgb_bg = tuple(int(bg[1].lstrip('#')[i:i+2], 16) for i in (0, 2, 4))
ratio = round(contrast_ratio(rgb_fg, rgb_bg), 3)
# Compliance check and store in summary data
if ratio >= 7:
summary_data[bg[1]]["AAA"].append((fg[0], fg[1], ratio))
elif ratio >= 4.5:
summary_data[bg[1]]["AA"].append((fg[0], fg[1], ratio))
elif ratio >= 3:
summary_data[bg[1]]["AALarge"].append((fg[0], fg[1], ratio))
compliance = (
"Pass - 100% (AAA ≥ 7.0)" if ratio >= 7 else
"Pass - 80% (AA Normal ≥ 4.5)" if ratio >= 4.5 else
"Pass - 60% (AA Large ≥ 3.0)" if ratio >= 3 else
"Fail - 0% (< 3.0)"
)
labelclass = (
"pass100" if ratio >= 7 else
"pass80" if ratio >= 4.5 else
"pass60" if ratio >= 3 else
"fail"
)
text_shadow = get_text_shadow(bg[1])
html += (
f''
f'{fg[0]} over {bg[0]}'
f' {compliance} with ratio {ratio}' f' | '
)
html += '
| Background | ' html += 'AAA ≥ 7.0 | AA Normal ≥ 4.5 | AA Large ≥ 3.0 |
|---|---|---|---|
| {bg_data["name"]} {bg_hex} | '
# AAA Column
html += f''
for fg_name, fg_hex, ratio in sorted(bg_data["AAA"], key=lambda x: x[2], reverse=True):
html += f' {fg_name} (Ratio: {ratio}) '
html += ' | '
# AA Column
html += f''
for fg_name, fg_hex, ratio in sorted(bg_data["AA"], key=lambda x: x[2], reverse=True):
html += f' {fg_name} (Ratio: {ratio}) '
html += ' | '
# AA Large Column
html += f''
for fg_name, fg_hex, ratio in sorted(bg_data["AALarge"], key=lambda x: x[2], reverse=True):
html += f' {fg_name} (Ratio: {ratio}) '
html += ' | '
html += '