Skip to main content

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

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

chromaverse-0.1.0.tar.gz (42.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

chromaverse-0.1.0-py3-none-any.whl (39.6 kB view details)

Uploaded Python 3

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

Hashes for chromaverse-0.1.0.tar.gz
Algorithm Hash digest
SHA256 5a57f2b90b548e7b5519ad89b7e369bd9ee98faa6674ff7a98141ab55ecf0a0b
MD5 0c9ce7b3f6bbc9cfe9feb4f95eac7d91
BLAKE2b-256 313255976554cc7a5cc5029655a5552984edcf5d3e728fdaf1a8875cc05739ed

See more details on using hashes here.

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

Hashes for chromaverse-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b10672eddc611cb44f2d74305534aaee2a42877d5a33c5c0cbcf0157b3645fd3
MD5 5d35d07472deeb887f5a2d0e02927885
BLAKE2b-256 a3e2613d992e719964c832fd94cf03be260b1741aa727a482ae6cf6a2452f923

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page