Bibliotheque Python exhaustive pour tout ce qui touche a la couleur : espaces colorimetriques, manipulation, harmonies, science perceptuelle, accessibilite et extraction depuis des images.
Project description
chromaverse
La boite a outils Python complete pour tout ce qui touche a la couleur.
chromaverse reunit en une seule bibliotheque tout ce dont vous avez besoin
pour manipuler des couleurs : conversions entre espaces colorimetriques
(vectorisees avec numpy), manipulation et melange, harmonies et generation
de palettes, science perceptuelle (Delta E, contraste WCAG), accessibilite
et design systems, et extraction de couleurs depuis des images.
import chromaverse as cc
c = cc.Color("#3498db")
c.lighten(0.15).hex # '#75B9E7'
c.complementary().hex # '#DB7734'
cc.wcag_contrast(c, "white") # 3.15
c.simulate_colorblindness("deuteranopia").hex # '#5A52C7'
Sommaire
- Installation
- Demarrage rapide
- La classe
Color - Espaces colorimetriques
- Manipulation
- Harmonies et palettes
- Science de la couleur
- Accessibilite et design systems
- Vision par ordinateur
- Fonctions basiques et utilitaires
- Reference API condensee
- Performance et vectorisation
- Developpement
- Licence
Installation
pip install chromaverse
Le module d'extraction de couleurs depuis des images (chromaverse.vision)
necessite Pillow :
pip install chromaverse[vision]
Seule dependance obligatoire : numpy (>=1.22).
Compatible Python 3.9+.
Demarrage rapide
import chromaverse as cc
from chromaverse import Color
# Construire une couleur de tres nombreuses manieres
Color("#3498db")
Color("cornflowerblue")
Color(52, 152, 219)
Color.from_hsl(204, 0.70, 0.53)
Color.from_lab(60.16, -6.10, -42.23)
c = Color("#3498db")
print(c.hex, c.rgb, c.hsl, c.lab)
La classe Color
Color est immuable : chaque transformation retourne une nouvelle
instance, l'originale n'est jamais modifiee.
Constructeurs
Color("#FF0000") # hex (avec ou sans '#', forme courte ou longue)
Color("#FF000080") # hex avec alpha
Color("red") # nom CSS (148 couleurs supportees)
Color(255, 0, 0) # RGB 0-255
Color(1.0, 0.0, 0.0) # RGB 0-1
Color.from_rgb(255, 0, 0)
Color.from_hsv(0, 1, 1)
Color.from_hsl(0, 1, 0.5)
Color.from_hsi(0, 1, 0.33)
Color.from_hwb(0, 0, 0)
Color.from_cmyk(0, 1, 1, 0)
Color.from_cmy(0, 1, 1)
Color.from_xyz(0.4124, 0.2127, 0.0193)
Color.from_lab(53.24, 80.09, 67.20)
Color.from_lch(53.24, 104.55, 40.0)
Color.from_luv(53.24, 175.0, 37.76)
Color.from_oklab(0.628, 0.225, 0.126)
Color.from_oklch(0.628, 0.258, 29.2)
Color.from_yuv(0.299, -0.147, 0.615)
Color.from_yiq(0.299, 0.596, 0.211)
Color.from_ycbcr(76, 84.4, 255)
Color.from_kelvin(2700) # lumiere chaude (ampoule)
Color.random()
Color.random_pastel()
Color.random_dark()
Proprietes de lecture
c.rgb # (52, 152, 219) 0-255
c.rgba # (52, 152, 219, 255)
c.rgb01 # (0.204, 0.596, 0.859) 0-1
c.hex # '#3498DB'
c.hexa # avec alpha
c.hsv / c.hsl / c.hsi / c.hwb
c.cmyk / c.cmy
c.xyz / c.lab / c.lch / c.luv
c.oklab / c.oklch
c.yuv / c.yiq / c.ycbcr
c.kelvin # temperature de couleur correlee estimee
c.name # nom CSS exact si correspondance parfaite, sinon None
c.nearest_name() # nom CSS le plus proche
Methodes
c.lighten(0.1) / c.darken(0.1)
c.saturate(0.1) / c.desaturate(0.1)
c.invert() / c.grayscale()
c.rotate_hue(180)
c.mix(other, ratio=0.5, space="lab") # 'rgb' | 'hsl' | 'lab' | 'oklab'
c.blend(other, mode="multiply") # 12 modes de fusion
c.complementary()
c.with_alpha(0.5)
c.luminance() # luminance relative WCAG
c.contrast_ratio(other) # ratio de contraste WCAG
c.delta_e(other, method="cie2000")
c.is_dark() / c.is_light()
c.best_text_color() # noir ou blanc, selon le meilleur contraste
c.simulate_colorblindness("protanopia")
Espaces colorimetriques
Toutes les fonctions de conversion sont entierement vectorisees : elles
acceptent un triplet unique ou un tableau numpy (..., 3), par exemple une
image complete (H, W, 3), sans changer de code.
import numpy as np
from chromaverse import conversions as spaces
# Une seule couleur
spaces.rgb_to_lab([0.8, 0.2, 0.4])
# array([47.99, 56.0, 4.6])
# Une image entiere (H, W, 3) en une seule passe vectorisee
image = np.random.rand(256, 256, 3)
lab_image = spaces.rgb_to_lab(image) # (256, 256, 3)
back = spaces.lab_to_rgb(lab_image) # (256, 256, 3)
Espaces supportes (conversion bidirectionnelle avec RGB) :
| Espace | Fonctions | Notes |
|---|---|---|
| HEX | hex_to_rgb, rgb_to_hex |
court/long, avec/sans alpha |
| HSV | rgb_to_hsv, hsv_to_rgb |
H en degres [0,360) |
| HSL | rgb_to_hsl, hsl_to_rgb |
|
| HSI | rgb_to_hsi, hsi_to_rgb |
Hue/Saturation/Intensity |
| HWB | rgb_to_hwb, hwb_to_rgb |
CSS Color Module 4 |
| CMY / CMYK | rgb_to_cmy(k), cmy(k)_to_rgb |
impression |
| XYZ | rgb_to_xyz, xyz_to_rgb |
reference D65 |
| Lab (CIE 1976) | rgb_to_lab, lab_to_rgb |
perceptuellement uniforme |
| LCh(ab) | rgb_to_lch, lch_to_rgb |
Lab en coordonnees polaires |
| Luv (CIE 1976) | rgb_to_luv, luv_to_rgb |
|
| YUV | rgb_to_yuv, yuv_to_rgb |
analogique, BT.601 |
| YIQ | rgb_to_yiq, yiq_to_rgb |
NTSC |
| YCbCr | rgb_to_ycbcr, ycbcr_to_rgb |
numerique, JPEG/BT.601 |
| Oklab / Oklch | rgb_to_oklab(ch), oklab(ch)_to_rgb |
Ottosson 2020, tres uniforme |
| Kelvin | kelvin_to_rgb, rgb_to_kelvin |
corps noir, approximation |
Fonctions de linearisation gamma egalement disponibles :
srgb_to_linear, linear_to_srgb.
Manipulation
from chromaverse import Color
c = Color("#3498db")
c.lighten(0.15) # eclaircit (L de HSL)
c.darken(0.15)
c.saturate(0.2)
c.desaturate(0.2)
c.invert() # negatif photographique
c.grayscale() # ponderation ITU-R BT.601
c.rotate_hue(45) # roue chromatique
c.mix("#e67e22", 0.5, space="lab") # melange perceptuellement uniforme
c.blend("#e67e22", "multiply") # mode de fusion type Photoshop
Modes de fusion disponibles dans blend() :
normal, multiply, screen, overlay, darken, lighten, difference,
exclusion, color-dodge, color-burn, soft-light, hard-light.
Fonctions additionnelles dans chromaverse.manipulate :
adjust_brightness, adjust_contrast, tint (melange avec du blanc),
shade (melange avec du noir), tone (melange avec du gris).
Harmonies et palettes
from chromaverse import Color
import chromaverse as cc
c = Color("#3498db")
cc.complementary(c) # 1 couleur, +180°
cc.analogous(c, count=5) # voisines sur la roue
cc.triadic(c) # 3 couleurs a 120°
cc.tetradic(c) # 4 couleurs (rectangle)
cc.square(c) # 4 couleurs a 90°
cc.split_complementary(c) # complementaire divisee
cc.monochromatic(c, count=5) # meme teinte, luminosite variable
cc.generate_palette(c, "triadic") # dispatch generique
cc.generate_palette(c, "analogous", count=7, spread=15)
Degrades, echelles UI et palettes generees
cc.gradient(Color("red"), Color("blue"), steps=10, space="lab")
cc.multi_gradient([Color("red"), Color("white"), Color("blue")])
cc.ui_scale(c) # {50: Color, 100: Color, ..., 900: Color} façon Tailwind
cc.distinct_colors(8) # 8 couleurs visuellement distinctes (angle dore)
La classe Palette
from chromaverse import Palette
p = Palette(["#FF0000", "#00FF00", "#0000FF"])
p.sort_by_hue()
p.to_css_variables(prefix="brand")
# :root {
# --brand-0: #FF0000;
# ...
# }
p.to_scss_variables(prefix="brand")
p.to_json()
p.most_accessible_pairs() # audit WCAG de toutes les paires
Science de la couleur
import chromaverse as cc
cc.relative_luminance((0.2, 0.6, 0.9)) # luminance relative WCAG
cc.contrast_ratio((1,1,1), (0,0,0)) # 21.0
lab1, lab2 = Color("#3498db").lab, Color("#e67e22").lab
cc.delta_e_cie76(lab1, lab2)
cc.delta_e_cie94(lab1, lab2)
cc.delta_e_cie2000(lab1, lab2) # recommande (le plus precis)
cc.delta_e(lab1, lab2, method="cie2000")
cc.color_temperature_to_rgb(2700) # lumiere chaude -> RGB
cc.rgb_to_color_temperature((1, 1, 1)) # RGB -> CCT estimee (formule McCamy)
cc.dominant_wavelength((1, 0, 0)) # ~645 nm (approximation, rouge)
Note sur la temperature de couleur : l'estimation
rgb_to_kelvin/rgb_to_color_temperature(formule de McCamy) n'est fiable que pour des couleurs proches du locus de corps noir (blancs, gris, eclairages). Sur une couleur tres saturee, la valeur retournee n'a pas de sens physique.
Accessibilite et design systems
import chromaverse as cc
cc.wcag_contrast("#3498db", "#FFFFFF") # 3.15
cc.meets_wcag_aa("#3498db", "#FFFFFF") # False
cc.meets_wcag_aaa("#000000", "#FFFFFF") # True
cc.wcag_level("#3498db", "#FFFFFF") # 'Fail' | 'AA' | 'AAA'
cc.suggest_text_color("#3498db") # Color('#000000') ou blanc
cc.suggest_text_color("#3498db", light="#FAFAFA", dark="#111111")
cc.simulate_colorblindness("#3498db", "deuteranopia")
# 'protanopia', 'deuteranopia', 'tritanopia', 'achromatopsia'
cc.check_palette_accessibility(["#FFFFFF", "#000000", "#3498db"])
# [{'pair': ('#FFFFFF', '#000000'), 'ratio': 21.0, 'level': 'AAA'}, ...]
Vision par ordinateur
Necessite pip install chromaverse[vision] (ajoute Pillow).
import chromaverse as cc
palette = cc.extract_palette("photo.jpg", n_colors=5) # k-means numpy pur
dominant = cc.dominant_color("photo.jpg")
moyenne = cc.average_color("photo.jpg")
hist = cc.image_histogram("photo.jpg", bins=16)
# {'r': array(16), 'g': array(16), 'b': array(16), 'bin_edges': array(17)}
extract_palette accepte un chemin de fichier, une PIL.Image, ou un
tableau numpy (H, W, 3).
Fonctions basiques et utilitaires
import chromaverse as cc
cc.is_valid_hex("#3498db") # True
cc.normalize_hex("#3ab") # '#33AABB'
cc.parse_color("cornflowerblue") # (0.39, 0.58, 0.93, 1.0)
cc.random_hex() # '#A3F21C'
cc.nearest_named_color((0.2, 0.6, 0.86)) # 'dodgerblue'
cc.get_named_color("tomato") # '#FF6347'
cc.all_named_colors() # dict des 148 couleurs CSS/X11
Reference API condensee
chromaverse
├── Color, Palette # objets coeur
├── conversions (alias: spaces) # *_to_* vectorises numpy
├── manipulate # lighten, mix, blend, ...
├── harmony # complementary, triadic, ...
├── palette # gradient, ui_scale, distinct_colors
├── science # luminance, delta_e, kelvin, ...
├── accessibility # wcag_*, simulate_colorblindness, ...
├── vision # extract_palette, dominant_color, ...
├── utils # parse_color, clamp, random_hex, ...
├── named_colors # CSS_NAMED_COLORS, get_named_color
└── exceptions # ChromaError et sous-classes
Performance et vectorisation
Le module chromaverse.conversions est concu pour fonctionner aussi bien
sur une couleur unique que sur une image complete, sans aucune boucle
Python : toutes les operations sont des operations numpy vectorisees.
import numpy as np
from chromaverse import conversions as spaces
image = np.random.rand(1080, 1920, 3) # image Full HD
lab = spaces.rgb_to_lab(image) # conversion de 2M de pixels en une passe
La classe Color, en revanche, est concue pour la clarte d'usage (couleur
par couleur) plutot que pour la performance brute sur de gros volumes :
pour traiter des images ou de grands tableaux, preferer directement les
fonctions de chromaverse.conversions / chromaverse.accessibility (qui
exposent des variantes vectorisees comme simulate_colorblindness_batch).
Developpement
git clone https://github.com/chromaverse/chromaverse.git
cd chromaverse
pip install -e ".[dev]"
pytest # suite de tests (254 tests)
pytest --cov=chromaverse # avec couverture (95%)
python -m build # construire sdist + wheel
twine check dist/* # valider avant publication
Publier sur PyPI
python -m build
twine check dist/*
twine upload dist/* # ou --repository testpypi pour tester d'abord
Pensez a verifier au prealable que le nom chromaverse est toujours
disponible sur pypi.org, et a incrementer la version
dans pyproject.toml et chromaverse.__version__ (fichier
src/chromaverse/__init__.py) avant chaque publication.
Licence
MIT - voir LICENSE.
Contributions bienvenues : ouvrez une issue ou une pull request.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file chromaverse-0.1.0.tar.gz.
File metadata
- Download URL: chromaverse-0.1.0.tar.gz
- Upload date:
- Size: 42.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5a57f2b90b548e7b5519ad89b7e369bd9ee98faa6674ff7a98141ab55ecf0a0b
|
|
| MD5 |
0c9ce7b3f6bbc9cfe9feb4f95eac7d91
|
|
| BLAKE2b-256 |
313255976554cc7a5cc5029655a5552984edcf5d3e728fdaf1a8875cc05739ed
|
File details
Details for the file chromaverse-0.1.0-py3-none-any.whl.
File metadata
- Download URL: chromaverse-0.1.0-py3-none-any.whl
- Upload date:
- Size: 39.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b10672eddc611cb44f2d74305534aaee2a42877d5a33c5c0cbcf0157b3645fd3
|
|
| MD5 |
5d35d07472deeb887f5a2d0e02927885
|
|
| BLAKE2b-256 |
a3e2613d992e719964c832fd94cf03be260b1741aa727a482ae6cf6a2452f923
|