Files
Ranska 3323237e67 add CLAUDE.md and project documentation
- CLAUDE.md with architecture overview, conventions, and strict commit rules
- docs/architecture-registries.md: registry pattern details
- docs/color-spaces.md: color space system guide
- docs/testing.md: BDD testing guide with mamba
- docs/nodes-comfyui.md: ComfyUI nodes reference
- docs/data-models.md: PixelColor and PixelPalette models
2026-02-13 10:38:29 +01:00

7.1 KiB

Modeles de données

PixelColor

Fichier : lib/pixel_color.py

Dataclass représentant une couleur individuelle avec ses métadonnées.

Attributs

Attribut Type Défaut Description
r int requis Canal rouge (0-255, clampé dans __post_init__)
g int requis Canal vert (0-255)
b int requis Canal bleu (0-255)
name str "" Nom optionnel de la couleur
color_space str "rgb" Espace colorimétrique actif pour le mélange

Propriétés

color = PixelColor(255, 128, 0, "Orange")

color.hex            # "#ff8000"
color.rgb_tuple      # (255, 128, 0)
color.rgb_normalized # (1.0, 0.502, 0.0)
color.exporter       # Instance RGBExporter (lazy-loaded)

Méthodes

mix_with(color, ratio=0.5) -> PixelColor

Mélange en place avec une autre couleur. Utilise le mixer de l'espace colorimétrique actuel.

red = PixelColor(255, 0, 0)
blue = PixelColor(0, 0, 255)
red.mix_with(blue, 0.5)  # red est maintenant (127, 0, 127)

Attention : cette méthode modifie l'instance. Utiliser create_copy() avant si on veut préserver l'original.

create_copy() -> PixelColor

Copie profonde de la couleur (tous les attributs).

original = PixelColor(255, 0, 0, "Rouge", "hsv")
copy = original.create_copy()
# copy.r == 255, copy.name == "Rouge", copy.color_space == "hsv"

distance_to(other) -> float

Distance euclidienne en espace RGB. Utilisée pour trouver la couleur la plus proche.

red = PixelColor(255, 0, 0)
orange = PixelColor(255, 128, 0)
red.distance_to(orange)  # ~128.0

using_color_space(new_space) -> ColorSpaceContext

Context manager pour changer temporairement l'espace colorimétrique.

color = PixelColor(255, 0, 0)  # color_space = "rgb"

with color.using_color_space("hsv"):
    color.mix_with(other, 0.5)  # mélange en HSV
# color_space restauré a "rgb"

to_hex() -> str

Format hexadécimal majuscule : "#FF8040"

Exporter (via propriété exporter)

color.exporter.to_hex()               # "#FF8000"
color.exporter.to_hex_alpha(0.5)       # "#FF800080"
color.exporter.to_rgb_string()         # "rgb(255, 128, 0)"
color.exporter.to_rgba_string(0.5)     # "rgba(255, 128, 0, 0.5)"
color.exporter.to_rgb_tuple()          # "(255, 128, 0)"
color.exporter.to_rgba_tuple(128)      # "(255, 128, 0, 128)"
color.exporter.to_hsl_string()         # "hsl(30, 100%, 50%)"
color.exporter.to_css_var("primary")   # "--primary: #FF8000;"
color.exporter.to_gimp_palette_line(0) # "255 128   0\tOrange"

Validation

__post_init__ clampe les valeurs RGB entre 0 et 255 :

color = PixelColor(300, -10, 128)
# color.r == 255, color.g == 0, color.b == 128

PixelPalette

Fichier : lib/pixel_palette.py

Classe pour gérer une collection de couleurs avec métadonnées et opérations de manipulation.

Attributs

Attribut Type Défaut Description
name str "Untitled Palette" Nom de la palette
colors List[PixelColor] [] Liste des couleurs
raw_content str "" Contenu brut (pour parsing automatique)
source_filename Optional[str] None Fichier source
metadata Dict[str, Any] {} Métadonnées libres
format_type str "unknown" Format détecté après parsing

Note : le __init__ actuel est simplifié et initialise seulement colors = []. Le @dataclass et __init__ coexistent (le __init__ explicite a priorité).

Protocole séquence

PixelPalette implémente le protocole séquence Python :

palette = PixelPalette()
palette.add_color(255, 0, 0, "Rouge")
palette.add_color(0, 255, 0, "Vert")

len(palette)        # 2
palette[0]          # PixelColor(255, 0, 0, "Rouge")
for color in palette:
    print(color)    # Itération

Propriétés

palette.is_empty     # True si aucune couleur
palette.color_count  # Nombre de couleurs
palette.is_valid     # Toujours True (une palette vide est valide)

Méthodes de manipulation

add_color(r, g, b, name="")

palette.add_color(255, 0, 0, "Rouge")

remove_color(index) -> bool

Supprime par index. Retourne True si suppression réussie.

palette.remove_color(0)  # True
palette.remove_color(99) # False (hors limites)

find_closest_color(target) -> (PixelColor, int)

Recherche linéaire par distance euclidienne RGB.

target = PixelColor(250, 10, 10)
closest, index = palette.find_closest_color(target)

get_unique_colors() -> List[PixelColor]

Déduplique les couleurs par tuple RGB.

sort_by_hue()

Tri en place par teinte HSV (utilise colorsys).

sort_by_brightness()

Tri en place par luminosité perceptuelle : 0.299*R + 0.587*G + 0.114*B

create_gradient(index1, index2, color_space="rgb")

Interpole les couleurs entre deux index existants.

palette = PixelPalette()
palette.add_color(255, 0, 0, "Rouge")     # 0
palette.add_color(0, 0, 0, "Placeholder") # 1
palette.add_color(0, 0, 0, "Placeholder") # 2
palette.add_color(0, 0, 255, "Bleu")      # 3

palette.create_gradient(0, 3, "rgb")
# palette[1] et palette[2] sont maintenant des couleurs interpolées

Contraintes :

  • index1 < index2
  • Au moins une couleur entre les deux index
  • Leve ValueError ou IndexError si invalide

Factory methods

create_monochrome(color, count, name=None) -> PixelPalette

Crée une palette avec count copies d'une même couleur.

red = PixelColor(255, 0, 0, "Rouge")
mono = PixelPalette.create_monochrome(red, 5)
# 5 copies indépendantes de Rouge

Méthodes d'export

to_formatted_string(format_type, separator, include_header, include_names) -> str

Export complet avec en-tête optionnel. Utilise PaletteExporter en interne.

palette.to_formatted_string("hex", separator="\n", include_header=True)
# "# Palette: Mon palette\n# Couleurs: 3\n...\n#FF0000\n#00FF00\n#0000FF"

to_list(format_type, include_names) -> List[str]

Liste de strings formatées.

palette.to_list("hex")  # ["#FF0000", "#00FF00", "#0000FF"]

to_rgb_tuples() -> List[Tuple[int, int, int]]

palette.to_rgb_tuples()  # [(255, 0, 0), (0, 255, 0), (0, 0, 255)]

Parsing automatique

Si raw_content est fourni, __post_init__ lance le parsing via ParserRegistry :

content = "GIMP Palette\nName: Test\n#\n255   0   0\tRouge"
palette = PixelPalette(raw_content=content)
# palette.colors contient les couleurs parsées
# palette.format_type == "gimp"

Les parsers sont essayés dans l'ordre d'enregistrement. Le premier qui retourne can_parse() == True est utilisé.


Relations entre modeles

PixelPalette
  └── colors: List[PixelColor]
        ├── .exporter -> RGBExporter (export individuel)
        └── .mix_with() -> ColorSpaceRegistry -> Mixer

PixelPalette
  ├── .to_formatted_string() -> PaletteExporter -> ExporterRegistry -> Exporter
  └── ._parse_content() -> ParserRegistry -> Parser -> List[PixelColor]