Metadata-Version: 2.4
Name: color-match-tools
Version: 7.0.0
Summary: Comprehensive color science library for accurate color space conversions, perceptual color distance metrics (Delta E), and color matching with CSS and 3D printing filament databases
Author-email: David Terracino <dterracino@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/dterracino/color_tools
Project-URL: Repository, https://github.com/dterracino/color_tools
Project-URL: Issues, https://github.com/dterracino/color_tools/issues
Project-URL: Changelog, https://github.com/dterracino/color_tools/blob/main/CHANGELOG.md
Project-URL: Documentation, https://dterracino.github.io/color_tools/
Keywords: color,color-science,delta-e,color-conversion,color-matching,rgb,lab,lch,hsl,xyz,ciede2000,cie94,cie76,gamut,srgb,3d-printing,filament
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Multimedia :: Graphics
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Operating System :: OS Independent
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: fuzzy
Requires-Dist: rapidfuzz>=3.0.0; extra == "fuzzy"
Provides-Extra: image
Requires-Dist: Pillow>=10.0.0; extra == "image"
Requires-Dist: numpy>=1.24.0; extra == "image"
Requires-Dist: scikit-image>=0.20.0; extra == "image"
Requires-Dist: pillow-heif>=0.14.0; extra == "image"
Requires-Dist: cairosvg>=2.7.0; extra == "image"
Requires-Dist: opencv-contrib-python>=4.8.0; extra == "image"
Requires-Dist: scikit-learn>=1.3.0; extra == "image"
Requires-Dist: swatch>=0.4.0; extra == "image"
Provides-Extra: interactive
Requires-Dist: prompt_toolkit>=3.0.0; extra == "interactive"
Provides-Extra: gui
Requires-Dist: PySide6>=6.6.0; extra == "gui"
Provides-Extra: logging
Requires-Dist: rich>=13.0.0; extra == "logging"
Provides-Extra: mcp
Requires-Dist: mcp<3,>=2.0.0; extra == "mcp"
Provides-Extra: docs
Requires-Dist: sphinx>=7.0.0; extra == "docs"
Requires-Dist: sphinx-rtd-theme>=1.3.0; extra == "docs"
Requires-Dist: myst-parser>=2.0.0; extra == "docs"
Requires-Dist: sphinx-autodoc-typehints>=1.24.0; extra == "docs"
Provides-Extra: dev
Requires-Dist: pyright>=1.1.0; extra == "dev"
Requires-Dist: build>=1.0.0; extra == "dev"
Requires-Dist: twine>=4.0.0; extra == "dev"
Requires-Dist: pytest>=8.0.0; extra == "dev"
Requires-Dist: pytest-cov>=6.0.0; extra == "dev"
Requires-Dist: coverage[toml]>=7.7.0; extra == "dev"
Provides-Extra: all
Requires-Dist: color-match-tools[fuzzy]; extra == "all"
Requires-Dist: color-match-tools[image]; extra == "all"
Requires-Dist: color-match-tools[interactive]; extra == "all"
Requires-Dist: color-match-tools[gui]; extra == "all"
Requires-Dist: color-match-tools[logging]; extra == "all"
Requires-Dist: color-match-tools[mcp]; extra == "all"
Dynamic: license-file

# Color Tools

A comprehensive Python library for color science operations, color space conversions, and color matching. This tool provides perceptually accurate color distance calculations, gamut checking, and extensive databases of CSS colors and 3D printing filament colors.

[![Version](https://img.shields.io/badge/version-7.0.0-blue.svg)](https://github.com/dterracino/color_tools/blob/main/CHANGELOG.md)
[![PyPI version](https://img.shields.io/pypi/v/color-match-tools.svg)](https://pypi.org/project/color-match-tools/)
[![Python versions](https://img.shields.io/pypi/pyversions/color-match-tools.svg)](https://pypi.org/project/color-match-tools/)
[![CI](https://github.com/dterracino/color_tools/actions/workflows/ci.yml/badge.svg)](https://github.com/dterracino/color_tools/actions/workflows/ci.yml)
[![CodeQL](https://github.com/dterracino/color_tools/actions/workflows/codeql.yml/badge.svg)](https://github.com/dterracino/color_tools/actions/workflows/codeql.yml)
[![codecov](https://codecov.io/gh/dterracino/color_tools/branch/main/graph/badge.svg)](https://codecov.io/gh/dterracino/color_tools)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/dterracino/color_tools/blob/main/LICENSE)
[![PyPI downloads](https://img.shields.io/pypi/dm/color-match-tools.svg)](https://pypi.org/project/color-match-tools/)

[![Color of the Day](https://color-tools-nine.vercel.app/api/color_of_day)](https://color-tools-nine.vercel.app/api/color_of_day)
[![Filament of the Day](https://color-tools-nine.vercel.app/api/filament_of_day)](https://color-tools-nine.vercel.app/api/filament_of_day)

> **Note:** The swatch images above are served by a personal demo deployment — not a public API.
> They may change or be unavailable without notice. See [docs/Badges.md](https://github.com/dterracino/color_tools/blob/main/docs/Badges.md) for details.

[Changelog](https://github.com/dterracino/color_tools/blob/main/CHANGELOG.md)

## 📚 Documentation

**[📖 Full API Documentation](https://dterracino.github.io/color_tools/)** - Complete API reference with examples

### User Guides

| Document | Description |
| ----------- | ------------- |
| [Installation](https://github.com/dterracino/color_tools/blob/main/docs/Installation.md) | Setup, dependencies, development install |
| [Usage](https://github.com/dterracino/color_tools/blob/main/docs/Usage.md) | Library API, CLI commands, examples |
| [Customization](https://github.com/dterracino/color_tools/blob/main/docs/Customization.md) | Data files, custom palettes, configuration |
| [Troubleshooting](https://github.com/dterracino/color_tools/blob/main/docs/Troubleshooting.md) | Error handling, performance, technical notes |
| [FAQ](https://github.com/dterracino/color_tools/blob/main/docs/FAQ.md) | Color spaces, distance metrics, contributing |

## ✨ Features

- **Multiple Color Spaces**: RGB, HSL, LAB, LCH with accurate conversions
- **Perceptual Color Distance**: Delta E formulas (CIE76, CIE94, CIEDE2000, CMC, HyAB)
- **Color Databases**:
  - Complete CSS color names with hex/RGB/HSL/LAB/LCH values
  - Extensive 3D printing filament database (1,545 filaments) with manufacturer info
  - Unique semantic IDs for all filaments (e.g., "bambu-lab-pla-silk-red")
  - Alternative name support for regional variations and rebranding
  - Maker synonym support for flexible filament searches
  - **Retro/Classic Palettes**: 29 presentation-style built-in palettes
    including Amstrad CPC, BBC Micro, CGA, EGA, Game Boy, Intellivision,
    PICO-8, TIC-80, VIC-20, and ZX Spectrum
- **Image Transformations** *(with [image] extra)*:
  - **Color Vision Deficiency (CVD)**: Simulate and correct for colorblindness (protanopia, deuteranopia, tritanopia)
  - **Palette Quantization**: Convert images to retro palettes (CGA, EGA, VGA, Game Boy) with dithering support
  - **Unified Architecture**: All transformations leverage existing color science infrastructure
- **Gamut Checking**: Verify if colors are representable in sRGB
- **Agent Integration** *(with [mcp] extra)*: Typed MCP tools for color analysis, conversion,
  perceptual comparison, palette search, filament matching, gamut mapping, and CVD transforms
- **Context-Safe Configuration**: Frozen runtime settings isolated through `ContextVar`
- **Color Science Integrity**: Built-in verification of color constants

## 🎨 Demos

### Color Vision Deficiency (CVD) Simulation & Correction

![CVD Demo – Protanopia, Deuteranopia, Tritanopia](cvd_demo.png)

*Animated: Original → Simulated (colorblind view) → Corrected, for all three deficiency types (protanopia, deuteranopia, tritanopia).*

## 🚀 Quick Start

### Installation

Python 3.12 or newer is required. The CI test matrix covers Python 3.12, 3.13,
and 3.14. Python 3.10 and 3.11 users must remain on the 6.x release series.

```bash
# Base package (zero dependencies)
pip install color-match-tools

# With image processing support
pip install color-match-tools[image]

# With interactive filament library manager
pip install color-match-tools[interactive]

# With the PySide6 desktop filament manager
pip install color-match-tools[gui]

# With colorized console logging (Rich)
pip install color-match-tools[logging]

# With the Color Tools MCP server for agents
pip install color-match-tools[mcp]

# With all optional features
pip install color-match-tools[all]
```

See [Installation Guide](https://github.com/dterracino/color_tools/blob/main/docs/Installation.md) for development setup and detailed options.

### Creating and Exporting Custom Palettes

```python
from color_tools import Palette, PaletteMetadata, export_palette

palette = Palette.from_rgb(
    [(255, 127, 80), (30, 144, 255), (50, 205, 50)],
    auto_name=True,
)
path = export_palette(
    palette,
    "gpl",
    "my_palette.gpl",
    metadata=PaletteMetadata(name="My Custom Palette", author="Dave", columns=3),
)
```

By default, colors are named `Color 1`, `Color 2`, etc. Set `auto_name=True` to
use built-in CSS/descriptive names, or pass `names=["Accent", "Background", ...]`
to supply explicit names (these override auto-naming and must match the color count).
Use `Palette.from_hex(["#f00", "00ff00"])` for hex inputs, or
`ColorRecord.from_rgb()` / `ColorRecord.from_hex()` for individual records.
RGB requires exactly three built-in integers from 0 to 255 in a tuple or list;
booleans, floats, and integer subclasses are rejected without coercion.
Hex accepts 3, 4, 6, or 8 ASCII hexadecimal digits with an optional `#`.
Four/eight-digit forms use CSS/PNG RGBA order, not Windows/Android ARGB;
alpha is validated but dropped for now. Invalid values raise `ValueError`,
including through `hex_to_rgb()`; `rgb_to_hex()` no longer clips invalid RGB.
Factories preserve order and duplicate colors; auto-generated names may repeat.
For direct batch naming, `generate_color_names(colors)` returns all `(name, match_type)`
results after loading the CSS color data once. Use `iter_color_names(colors)` for lazy
processing; it waits until iteration begins and still shares one data load.

Choose a format explicitly using identifiers from `list_export_formats("colors")`;
use the matching filename extension. Exporters that do not support palette metadata
still export the colors. Pass exporter-specific `options` when needed, or use
`PaletteExportData` with embedded metadata instead of a searchable `Palette`.
Omitting the output path lets the exporter generate a filename.

#### Aseprite Native Palettes

```python
export_palette(
    palette,
    "aseprite",
    "my_palette.aseprite",
    metadata=PaletteMetadata(name="My Palette", columns=16),
)
```

The dependency-free `aseprite` exporter writes a single-frame swatch document
with an sRGB palette, color names, and compressed pixels. Use **`.aseprite`**:
the existing **`ase` / `.ase`** exporter remains Adobe Swatch Exchange.
Aseprite export rejects filenames with other extensions.

By default, a named transparent-black entry is prepended at index zero for editing.
All supplied colors remain opaque and shift by one index; input records are not
modified. To omit that entry:

```python
from color_tools.exporters import AsepriteExportOptions

export_palette(
    palette, "aseprite", "opaque_palette.aseprite",
    options=AsepriteExportOptions(include_transparent=False),
)
```

Order and duplicates are preserved. Up to 256 total entries use indexed
pixels; larger palettes use RGBA. The supported input size is 1-65,534 colors
with transparency enabled, or 1-65,535 with it disabled.
Positive `columns` selects the grid width (capped at the color count); zero or
None produces a horizontal strip. Layout includes the transparent slot.
Unused grid cells repeat entry zero.
The palette name becomes the background layer name, not a native palette-title
field. Author, description, tags, and arbitrary properties are not preserved.
Names must fit within 65,535 UTF-8 bytes.

#### GLSL Shader Palettes

```python
from color_tools.exporters import GLSLExportOptions

export_palette(
    palette,
    "glsl",
    "my_palette.glsl",
    options=GLSLExportOptions(
        representation="defines",
        normalized=False,
        identifier_prefix="GAME_",
    ),
)
```

The dependency-free `glsl` exporter supports constant arrays, named constants,
and `#define` macros. It emits normalized `vec3` values by default, with options
for opaque `vec4` output, raw 0-255 floating-point channels such as `255.0`,
palette metadata comments, and an optional `#version` directive.

### CLI Usage

After installation, `color-tools` is the canonical command. The legacy
`color_tools` spelling remains available as an alias. When developing from a
checkout, use `python -m color_tools` (or `py -m color_tools` on Windows) to
guarantee that Python runs the current source tree rather than an older launcher
elsewhere on `PATH`.

```bash
# Interactive wizard — guided prompts for color, filament, and convert
# (requires: pip install color-match-tools[interactive])
color-tools
color-tools --interactive

# Interactive filament library manager — manage owned filaments
# (--manage is also supported)
color-tools filament --interactive

# PySide6 desktop manager with color swatches
# (requires: pip install color-match-tools[gui])
color-tools filament --gui

# Find a CSS color by name
color-tools color --name coral

# Find nearest CSS color to an RGB value
color-tools color --nearest --value 255 128 64 --space rgb

# Generate a calm, dark triadic harmony
color-tools harmony --type triadic --hex "#E0006B" --mood calm --tone dark

# Find matching 3D printing filaments
color-tools filament --nearest --value 255 128 64

# Export Bambu Lab PLA records with TD values to a HueForge library
color-tools filament --all-filaments --maker "Bambu Lab" --type PLA --has-td --export hueforge --output bambu-pla-hueforge.json

# Convert between color spaces
color-tools convert --from rgb --to lab --value 255 128 64
color-tools convert --from rgb --to cmyk --value 255 128 64
color-tools convert --from cmyk --to rgb --value 0 50 75 0

# Simulate colorblindness on an image
color-tools image --file photo.jpg --cvd-simulate deuteranopia

# Convert image to retro CGA palette
color-tools image --file photo.jpg --quantize-palette cga4 --dither
```

### Library Usage

Runtime settings use frozen, context-local snapshots through `get_config()`,
`set_config()`, `reset_config()`, and `config_context()`. Version 7 removes the
old individual configuration setters and `--dual-color-mode`; use
`--multi-color-mode` with `first`, `last`, or `srgb_mean`. See the
[configuration guide](https://github.com/dterracino/color_tools/blob/main/docs/Customization.md)
for scope, migration, and multi-color filament representation.

Filaments preserve original `hex` text and an immutable ordered
`rgb_components` tuple. Compound hex accepts any number of components separated
by hyphen, space, comma, underscore, slash, colon, or semicolon. Every component
is validated, including those not selected. `rgb`, `lab`, and `effective_hex`
describe the color resolved at construction; later configuration changes do
not alter existing records. The separate `hex2` field has been removed.

```python
from color_tools import (
    FilamentCollections,
    FilamentFilterCriteria,
    FilamentPalette,
    Palette,
    delta_e_2000,
    rgb_to_lab,
)

# Convert RGB to LAB
lab = rgb_to_lab((255, 128, 64))
print(f"LAB: {lab}")

# Find nearest CSS color
palette = Palette.load_default()
nearest, distance = palette.nearest_color(lab, space="lab")
print(f"Nearest: {nearest.name} (ΔE: {distance:.2f})")

# Find matching filaments
filament_palette = FilamentPalette.load_default()
filament, distance = filament_palette.nearest_filament((255, 128, 64))
print(f"Filament: {filament.maker} {filament.color}")

# Include red or blue PLA but exclude silk finishes; matching is case-insensitive
filament, distance = filament_palette.nearest_filament_by_criteria(
    (255, 128, 64),
    include=FilamentFilterCriteria(type_name="pla", color=["red", "blue"]),
    exclude=FilamentFilterCriteria(finish="silk"),
)

# Use a predefined, immutable filament collection
for filament in FilamentCollections.BAMBU_PLA_BASIC:
    print(filament.color, filament.hex)
```

See [Usage Guide](https://github.com/dterracino/color_tools/blob/main/docs/Usage.md) for complete API reference and CLI documentation.

### Array RGB to LAB Conversion

Install the image extra to use the NumPy-based array APIs:

```bash
pip install "color-match-tools[image]"
```

`rgb_to_lab_array` accepts colors, palettes, and images shaped `(..., 3)` and preserves
their shape. Its `float64` LAB output can be passed directly to `delta_e_2000_array`:

```python
import numpy as np

from color_tools import delta_e_2000_array, rgb_to_lab_array

rgb = np.array([[255, 0, 0], [0, 255, 0], [0, 0, 255]], dtype=np.uint8)
lab = rgb_to_lab_array(rgb)
distances_from_red = delta_e_2000_array(lab, lab[0])
```

### Color Harmonies

Generate perceptual color harmonies in CIE LCH space from an RGB base color:

```python
from color_tools import generate_harmony

palette = generate_harmony(
  (224, 0, 107),
  "triadic",
  mood="calm",
  tone="dark",
)

print([color.hex for color in palette.colors])
```

Harmony schemes include analogous, complementary, split-complementary, triadic, square,
tetradic, monochromatic, and six-color rainbow/full-spectrum. Optional `warm`, `cool`,
`happy`, `calm`, `intense`, `sad`, and `energetic` mood presets adjust palette lightness and
chroma without changing the harmony's hue relationships. Independent `dark` and `light` tones
can be composed with any mood.

Mood presets are opinionated design heuristics rather than universal psychological rules. The
base color remains unchanged by default; pass `grade_base=True` to style it with the generated
colors.

### MCP Server

The optional MCP server exposes Color Tools to GitHub Copilot and other MCP-compatible agents as
typed, structured tools:

```bash
pip install "color-match-tools[mcp]"
color-tools-mcp
```

MCP clients normally launch the stdio server automatically with `python -m color_tools.mcp`.
See the [MCP server guide](https://github.com/dterracino/color_tools/blob/main/color_tools/mcp/README.md)
for the tool catalog and client configuration.

## 🎨 Color Spaces

| Space | Description | Range |
| ------- | ------------- | ------- |
| **RGB** | Red, Green, Blue | 0-255 per component |
| **HSL** | Hue, Saturation, Lightness | H: 0-360°, S: 0-100%, L: 0-100% |
| **LAB** | Perceptually uniform | L: 0-100, a/b: ±100 |
| **LCH** | Cylindrical LAB | L: 0-100, C: 0+, H: 0-360° |
| **CMY** | Subtractive (no black channel) | C/M/Y: 0-100% each |
| **CMYK** | Subtractive print model (with black) | C/M/Y/K: 0-100% each |

**Use LAB or LCH for color matching** - they're designed to match human perception.
**Use CMYK for basic print-model calculations** - the K channel produces richer
blacks than CMY alone. These generic conversions are not ICC-managed color
separations; production printing requires a device and media profile.

## 📏 Distance Metrics

| Metric | Use Case |
| -------- | ---------- |
| **CIEDE2000** (`de2000`) | **Recommended** - Gold standard for perceptual accuracy |
| **CIE94** (`de94`) | Good balance of accuracy and performance |
| **CIE76** (`de76`) | Fast, simple Euclidean in LAB space |
| **CMC** (`cmc`) | Textile industry standard |
| **HyAB** (`hyab`) | Best for large color differences and image quantization |

See [FAQ](https://github.com/dterracino/color_tools/blob/main/docs/FAQ.md) for detailed explanations of when to use each metric.

## 📦 Data Files

The library includes extensive color databases:

- **CSS Colors**: 147 named colors with full color space representations
- **3D Printing Filaments**: 1,545 filaments from major manufacturers
- **Retro Palettes**: 29 built-in palettes including Amstrad CPC, BBC Micro,
  CGA, EGA, VGA, Game Boy, Commodore 64, Intellivision, PICO-8, TIC-80,
  VIC-20, ZX Spectrum, and more

Built-in system and retro palettes are presentation-style sRGB
representations intended to evoke how a system would display an image on a
modern screen. They are not claims of electrically or historically exact RGB
output. Values may differ from published hardware specifications, emulator
tables, or captures because analog video, region, hardware revision, signal
path, display, gamma, and reproduction goals can all affect the visible result.

### Help improve the filament database

Have a filament that is missing, has the wrong color, or needs a transmission
distance (TD) value? **[Submit a filament update](https://github.com/dterracino/color_tools/issues/new?template=filament_data.yml)**—no code, Git, or JSON editing is required.

TD describes how readily light passes through a printed filament, expressed as
a distance in millimeters. Lower values describe more opaque filaments; higher
values describe filaments that transmit light through a greater thickness.
HueForge uses TD with color and layer thickness to predict how stacked filament
layers blend, so an accurate TD can materially improve a HueForge preview and
the resulting print. TD is not a percentage or a normalized 0.0–1.0 value.

New filaments, corrected colors, and measured or published TD values are all
welcome. The database stores TD values when available without claiming that
they are manufacturer-certified or tracking per-record provenance. See
[Contributing filament data](https://github.com/dterracino/color_tools/blob/main/CONTRIBUTING.md#adding-to-the-filament-database)
for the requested details and the code-contribution path.

Extend with your own data using [User Data Files](https://github.com/dterracino/color_tools/blob/main/docs/Customization.md#user-data-files-optional-extensions).

**Track your owned filaments** for personalized color matching - create an `owned-filaments.json` file to automatically filter searches to filaments you already have. See [Owned Filaments](https://github.com/dterracino/color_tools/blob/main/docs/Customization.md#owned-filamentsjson---filament-ownership-tracking) in the Customization Guide.

## 🔧 Export & Integration

Export colors and filaments to various formats for use with external tools:

### Available Formats

| Identifier | Output | Data | Palette metadata | Dependency |
| --- | --- | --- | --- | --- |
| `ase` | Adobe Swatch Exchange (`.ase`) | Colors | Yes | `swatch` via `[image]` |
| `aseprite` | Aseprite document (`.aseprite`) | Colors | Yes | None |
| `autoforge` | AutoForge CSV (`.csv`) | Filaments | No | None |
| `css` | CSS custom properties (`.css`) | Colors | No | None |
| `csv` | Generic CSV (`.csv`) | Colors and filaments | No | None |
| `glsl` | GLSL shader source (`.glsl`) | Colors | Yes | None |
| `gpl` | GIMP Palette (`.gpl`) | Colors | Yes | None |
| `hex` | Plain HEX list (`.hex`) | Colors | No | None |
| `hueforge` | HueForge filament library (`.json`) | Filaments | No | None |
| `jasc_pal` | JASC Paint Shop Pro palette (`.pal`) | Colors | No | None |
| `json` | Generic JSON (`.json`) | Colors and filaments | Yes for palettes | None |
| `kpl` | Krita palette (`.kpl`) | Colors | Yes | None |
| `lospec` | Lospec JSON (`.json`) | Colors | Yes | None |
| `paintnet` | PAINT.NET palette (`.txt`) | Colors | No | None |
| `palette_lut` | GPU palette LUT (`.png`) | Colors | No | None |
| `python` | Typed Python source (`.py`) | Colors | Yes | None |
| `riff_pal` | Microsoft RIFF palette (`.pal`) | Colors | No | None |
| `scribus` | Scribus XML palette (`.xml`) | Colors | Yes | None |
| `sketchpalette` | Sketch Palettes plugin (`.sketchpalette`) | Colors | No | None |
| `soc` | LibreOffice/OpenOffice palette (`.soc`) | Colors | No | None |
| `swatch_image` | Presentation swatch sheet (`.png`) | Colors | Yes | Pillow via `[image]` |

`list_export_formats()` returns only formats whose optional dependencies are installed by default.
Pass `available_only=False` to include unavailable formats. Install `color-match-tools[image]`
for ASE and presentation swatch images.

Plain `.hex` files use lowercase values by default. Python callers can pass
`HexExportOptions(uppercase=True)` for uppercase output. HueForge requires a TD
value for every selected filament; use the CLI `--has-td` filter or filter the
records explicitly in Python before export.

### Export Examples

```python
from color_tools import Palette, FilamentPalette
from color_tools.exporters import get_exporter, list_export_formats
from color_tools.exporters.palette_export_data import PaletteExportData
from color_tools.exporters.palette_metadata import PaletteMetadata
from color_tools.exporters.swatch_image_exporter import SwatchImageOptions

# List available formats for colors
formats = list_export_formats("colors")

# Export raw color records
palette = Palette.load_default()
get_exporter("gpl").export_colors(palette.records[:20], "colors.gpl")
get_exporter("jasc_pal").export_colors(palette.records[:20], "colors.pal")

# Preserve palette-level metadata when the format supports it
palette_data = PaletteExportData(
  colors=palette.records[:8],
  metadata=PaletteMetadata(
    name="Sample Palette",
    author="Color Tools",
    description="Eight colors exported with palette metadata.",
    columns=4,
  ),
)
get_exporter("json").export_palette(palette_data, "palette.json")

# Supply strongly typed, per-export options to configurable exporters
get_exporter("swatch_image").export_palette(
  palette_data,
  "palette.png",
  options=SwatchImageOptions(show_rgb=True, show_lab=True),
)

# Export filament records
filaments = FilamentPalette.load_default()
bambu_pla = filaments.filter(maker="Bambu Lab", type_name="PLA", owned=False)
get_exporter("autoforge").export_filaments(bambu_pla, "bambu_pla.csv")

# HueForge accepts only records with TD values
bambu_pla_with_td = [record for record in bambu_pla if record.td_value is not None]
get_exporter("hueforge").export_filaments(
    bambu_pla_with_td,
    "bambu_pla_hueforge.json",
)
```

The functions in `color_tools.export`, including `export_colors()` and `export_filaments()`,
remain available as backward-compatible facades. New integrations should use the exporter registry
when they need capability metadata, palette metadata, optional dependency checks, or typed options.

### Plugin Architecture

The exporter system uses a plugin architecture - new formats can be added without modifying existing code:

```python
from color_tools.exporters import register_exporter
from color_tools.exporters.base import PaletteExporter, ExporterMetadata

@register_exporter
class MyExporter(PaletteExporter):
    @property
    def metadata(self) -> ExporterMetadata:
        return ExporterMetadata(
            name="myformat",
            description="My custom format",
            file_extension="txt",
            supports_colors=True,
            supports_filaments=False,
        )

    def _export_colors_impl(self, colors, output_path) -> str:
        # Write the file and return its path.
        return str(output_path)
```

See [exporters/gpl_exporter.py](https://github.com/dterracino/color_tools/blob/main/color_tools/exporters/gpl_exporter.py) for a complete example.

## 📋 Logging

The library ships with a structured logging system that fans out to console and an
optional rotating file — one call, both destinations:

```python
from pathlib import Path
import logging
from color_tools import setup_logging, get_logger, log_info

# Console-only (INFO+ by default)
setup_logging()

# Console + rotating file (DEBUG+ to file, INFO+ to console)
setup_logging(log_file=Path("color_tools.log"), console_level=logging.DEBUG)

# Module-level logger (use __name__ to get "color_tools.mymodule")
logger = get_logger(__name__)
logger.info("Loaded %d colors", count)

# Convenience shortcuts on the library root logger
log_info("Processing %d filaments", n)
```

For colorized console output install the `[logging]` extra:

```bash
pip install color-match-tools[logging]   # adds Rich
```

The library registers a `NullHandler` at import time (Python library best practice), so
no output is produced until `setup_logging()` is explicitly called.

**CLI file logging** — write logs while using the command line:

```bash
color-tools --log-file color_tools.log color --nearest --hex "#FF8040"
color-tools --log-file debug.log --log-level DEBUG filament --nearest --hex "#FF0000"
```

See [Usage Guide](https://github.com/dterracino/color_tools/blob/main/docs/Usage.md#logging) for the full API reference.

## 🔒 Data Integrity

Core data, registered system palettes, and selected user files are protected
with SHA-256 hashes:

```bash
python -m color_tools --verify-all

# Validate user JSON schemas and merge rules without writing files
python -m color_tools --validate-user-files
```

See [Troubleshooting](https://github.com/dterracino/color_tools/blob/main/docs/Troubleshooting.md#data-integrity-verification) for verification details.

## 🤝 Contributing

**CRITICAL**: Color science constants should **NEVER** be modified. They represent fundamental values from international standards.

See [CONTRIBUTING.md](https://github.com/dterracino/color_tools/blob/main/CONTRIBUTING.md)
for contribution guidelines. Filament additions and corrections can be
[submitted without writing code](https://github.com/dterracino/color_tools/issues/new?template=filament_data.yml).

## 📄 License

MIT License - see [LICENSE](https://github.com/dterracino/color_tools/blob/main/LICENSE) for details.
