Skip to main content

material_color_utils/
lib.rs

1//! # material-color-utils
2//!
3//! A high-performance Rust port of [Material Color Utilities](https://github.com/material-foundation/material-color-utilities).
4//!
5//! This crate provides algorithms and utilities for working with Material 3 (M3) dynamic color,
6//! including the HCT color space, color quantization, and scheme generation.
7//!
8//! ## Core Concepts
9//!
10//! *   **HCT (Hue, Chroma, Tone):** A perceptually accurate color space that separates hue from lightness (tone).
11//! *   **Dynamic Color:** A system that generates adaptive, accessible color schemes based on a user's source color.
12//! *   **Materialized Theme:** A flattened representation of a color scheme.
13//!
14//! ## Usage Examples
15//!
16//! ### High-Level Helpers (Simplified Theme Generation)
17//!
18//! The easiest way to get started is with the high-level `theme_from_color` helper.
19//!
20//! ```rust
21//! use material_color_utils::utils::color_utils::Argb;
22//! use material_color_utils::theme_from_color;
23//!
24//! // Create a theme from a source ARGB color
25//! let source_color = Argb::from_hex("#4285F4").unwrap(); // Blue
26//! // Builder with optional arguments for contrast, scheme variant, and more:
27//! let theme = theme_from_color(source_color).call();
28//!
29//! // Access light and dark schemes
30//! let primary_light = theme.schemes.light.primary;
31//! let primary_dark = theme.schemes.dark.primary;
32//!
33//! println!("Light Primary: {}", primary_light);
34//! println!("Dark Primary: {}", primary_dark);
35//!
36//! // The materialized theme structs support serde (de)serialization
37//! println!("Theme json: {}", serde_json::to_string_pretty(&theme).unwrap())
38//! ```
39//!
40//! ### Color Extraction from Image
41//!
42//! The `image` feature enables extracting prominent colors from images to use as source colors.
43//!
44//! ```rust
45//! use material_color_utils::{extract_image_colors, theme_from_image};
46//!
47//! let img = image::open("tests/assets/img/river.png").unwrap();
48//!
49//! // Extract colors from an image
50//! let colors = extract_image_colors(&img).call();
51//! println!("Colors in 'river.png' to make a theme from: {:?}", colors);
52//!
53//! // Generate a theme directly from an image
54//! let theme = theme_from_image(&img).call().unwrap();
55//! ```
56//!
57//! ### Dynamic API (HCT & Custom Schemes)
58//!
59//! For more control, and lazy evaluation,
60//! you can work directly with the HCT color space and individual scheme builders.
61//!
62//! ```rust
63//! use material_color_utils::hct::Hct;
64//! use material_color_utils::scheme::SchemeTonalSpot;
65//! use material_color_utils::dynamic::material_dynamic_colors::MaterialDynamicColors;
66//! use material_color_utils::dynamic::color_spec::SpecVersion;
67//! use material_color_utils::utils::color_utils::Argb;
68//!
69//! // 1. Create a color in HCT space
70//! let hct = Hct::from_argb(Argb(0xFF4285F4));
71//! println!("H: {}, C: {}, T: {}", hct.hue(), hct.chroma(), hct.tone());
72//!
73//! // 2. Manually build a scheme (Tonal Spot, Dark Mode, High Contrast)
74//! let scheme = SchemeTonalSpot::builder(hct.to_argb(), true, 0.5)
75//!     .spec_version(SpecVersion::Spec2026)
76//!     .build();
77//!
78//! // 3. Extract specific color roles using MaterialDynamicColors
79//! let mdc = MaterialDynamicColors::new();
80//! let primary = mdc.primary().get_argb(&scheme);
81//! let on_primary = mdc.on_primary().get_argb(&scheme);
82//!
83//! println!("Primary: {:?}", primary);
84//! println!("On-Primary: {:?}", on_primary);
85//! ```
86//!
87//! ### Contrast Helpers
88//!
89//! Utilities for calculating contrast ratios and adjusting colors to meet accessibility standards.
90//!
91//! ```rust
92//! use material_color_utils::utils::color_utils::Argb;
93//! use material_color_utils::{get_contrast_ratio, lighter_tone, darker_tone, lighter_tone_unsafe, darker_tone_unsafe};
94//!
95//! let color1 = Argb(0xFF4285F4);
96//! let color2 = Argb::from_hex("#FFFFFF").unwrap();
97//!
98//! // Calculate contrast ratio
99//! let ratio = get_contrast_ratio(color1, color2);
100//! println!("Contrast ratio: {:.2}", ratio);
101//!
102//! // Find a color that meets a target contrast ratio
103//! if let Some(lighter) = lighter_tone(color1, 4.5) {
104//!     println!("Lighter color with 4.5 contrast: {}", lighter);
105//! }
106//!
107//! // lighter_tone_unsafe will clip to white if it can't reach the desired contrast ratio.
108//! let lighter_unsafe = lighter_tone_unsafe(color1, 4.5);
109//! let darker_unsafe = darker_tone_unsafe(color1, 4.5);
110//! println!("Lighter color, clipped if necessary at tone=100 (white): {}", lighter_unsafe);
111//! println!("Darker color, clipped if necessary at tone=0 (black): {}", lighter_unsafe);
112//! ```
113//!
114//! ### UI Integration
115//!
116//! Dynamic colors are designed for lazy evaluation, allowing for high-performance,
117//! interfaces where only the colors used in the UI are calculated.
118//!
119//! ```rust
120//! use material_color_utils::dynamic::dynamic_scheme::DynamicScheme;
121//! use material_color_utils::dynamic::material_dynamic_colors::MaterialDynamicColors;
122//!
123//! struct MyUIComponent {
124//!     scheme: DynamicScheme,
125//!     mdc: MaterialDynamicColors,
126//! }
127//!
128//! impl MyUIComponent {
129//!     fn on_render(&self) {
130//!         // Colors are evaluated on-demand from the current scheme
131//!         let bg = self.mdc.surface().get_argb(&self.scheme);
132//!         let primary = self.mdc.primary().get_argb(&self.scheme);
133//!
134//!         // ... apply bg and primary to UI elements ...
135//!     }
136//! }
137//! ```
138
139#![deny(clippy::unwrap_used)]
140#![allow(
141    clippy::similar_names,
142    clippy::unreadable_literal,
143    clippy::many_single_char_names,
144    clippy::while_float,
145    clippy::too_many_lines,
146    clippy::too_many_arguments,
147    clippy::match_wildcard_for_single_variants,
148    clippy::cast_sign_loss,
149    clippy::cast_possible_truncation,
150    clippy::too_long_first_doc_paragraph,
151    clippy::cast_possible_wrap,
152    clippy::cast_precision_loss
153)]
154pub mod blend;
155pub mod contrast;
156pub mod dislike;
157pub mod dynamic;
158pub mod hct;
159mod helpers;
160pub mod palettes;
161pub mod quantize;
162pub mod scheme;
163pub mod score;
164pub mod temperature;
165pub mod utils;
166
167pub use helpers::*;