Expand description
This crate provides utilities for working with ICC color profiles and integrates with the Colorimetry Library.
§Use Cases
Parsing ICC profiles and conversion to TOML format for analysis
After installing the library, you can parse an ICC profile and convert it to a TOML format using the `cmx` command-line tool:cmx profile.icc -o profile.toml
Each ICC profile tag is mapped to a key in the TOML file, with the corresponding values serialized as key-value pairs. All values are written as single-line entries to ensure the TOML output remains human-readable and easy to inspect.
Example of a parsed ICC profile in TOML format:
profile_size = 548
cmm = "Apple"
version = "4.0"
device_class = "Display"
color_space = "RGB"
pcs = "XYZ"
creation_datetime = "2015-10-14 13:08:56 UTC"
primary_platform = "Apple"
manufacturer = "APPL"
rendering_intent = "Perceptual"
pcs_illuminant = [0.9642, 1.0, 0.8249]
creator = "appl"
profile_id = "53410ea9facdd9fb57cc74868defc33f"
[desc]
ascii = "SMPTE RP 431-2-2007 DCI (P3)"
[cprt]
text = "Copyright Apple Inc., 2015"
[wtpt]
xyz = [0.894592, 1.0, 0.954422]
[rXYZ]
xyz = [0.48616, 0.226685, -0.000809]
[gXYZ]
xyz = [0.323853, 0.710327, 0.043228]
[bXYZ]
xyz = [0.15419, 0.062988, 0.782471]
[rTRC]
g = 2.60001
[chad]
matrix = [
[1.073822, 0.038803, -0.036896],
[0.055573, 0.963989, -0.014343],
[-0.004272, 0.005295, 0.862778]
]
[bTRC]
g = 2.60001
[gTRC]
g = 2.60001
Generate ICC profiles
You can also use the cmx
library to create ICC profiles from scratch, or read existing
profiles and change them, using Rust.
The library provides a builder-style API for constructing, or read and change profiles, allowing you to set or change various tags and properties.
Here is an example for creating a Display P3 ICC profile:
use chrono::{DateTime, TimeZone};
use cmx::tag::tags::*;
use cmx::profile::DisplayProfile;
let display_p3_example = DisplayProfile::new()
// set creation date, if omitted, the current date and time are used
.with_creation_date(chrono::Utc.with_ymd_and_hms(2025, 8, 28, 0, 0, 0).unwrap())
.with_tag(ProfileDescriptionTag)
.as_text_description(|text| {
text.set_ascii("Display P3");
})
.with_tag(CopyrightTag)
.as_text(|text| {
text.set_text("CC0");
})
.with_tag(MediaWhitePointTag)
.as_xyz_array(|xyz| {
xyz.set([0.950455, 1.00000, 1.08905]);
})
.with_tag(RedMatrixColumnTag)
.as_xyz_array(|xyz| {
xyz.set([0.515121, 0.241196, -0.001053]);
})
.with_tag(GreenMatrixColumnTag)
.as_xyz_array(|xyz| {
xyz.set([0.291977, 0.692245, 0.041885]);
})
.with_tag(BlueMatrixColumnTag)
.as_xyz_array(|xyz| {
xyz.set([0.157104, 0.066574, 0.784073]);
})
.with_tag(RedTRCTag)
.as_parametric_curve(|para| {
para.set_parameters([2.39999, 0.94786, 0.05214, 0.07739, 0.04045]);
})
.with_tag(BlueTRCTag)
.as_parametric_curve(|para| {
para.set_parameters([2.39999, 0.94786, 0.05214, 0.07739, 0.04045]);
})
.with_tag(GreenTRCTag)
.as_parametric_curve(|para| {
para.set_parameters([2.39999, 0.94786, 0.05214, 0.07739, 0.04045]);
})
.with_tag(ChromaticAdaptationTag)
.as_sf15_fixed_16_array(|array| {
array.set([
1.047882, 0.022919, -0.050201,
0.029587, 0.990479, -0.017059,
-0.009232, 0.015076, 0.751678
]);
})
.with_profile_id() // calculate and add profile ID to the profile
;
display_p3_example.write("tmp/display_p3_example.icc").unwrap();
let display_p3_read_back = cmx::profile::Profile::read("tmp/display_p3_example.icc").unwrap();
assert_eq!(
display_p3_read_back.profile_id_as_hex_string(),
"617028e1 e1014e15 91f178a9 fb8efc92"
);
assert_eq!(display_p3_read_back.profile_size(), 524);
Not all ICC tag types are supported yet, but please submit a pull request, or an issue, on our GitHub CMX repo if you want additional tag types to be supported.
However, you can use the as_raw
method to set raw data for tags that are not yet supported.
§Installation
Install the cmx
tool using Cargo:
cargo install cmx
To use the cmx
library in your Rust project:
cargo add cmx
Documentation is available at docs.rs/cmx.
§Roadmap
- Parse full ICC profiles
- Convert to TOML format
- Add builder-style API for constructing ICC profiles
- Support basic ICC Type tags and color models
- Read TOML Color profiles and convert to binary ICC profiles
- Utilities for commandline profile conversion and manipulation
- Calibration and profiling tools
- X-Rite I1 Profiler support
- Support all ICC Type tags
- Enable spectral data and advanced color management
§Overview
Although the ICC specification is broad and complex, this crate aims to provide a robust foundation for working with ICC profiles in Rust.
It supports parsing, constructing, and changing of the primary ICC-defined tags, as well as some commonly used non-standard tags.
Even tags that cannot yet be parsed are still preserved when reading and serializing profiles, ensuring no data loss.
The long-term goal is to fully support advanced ICC color management, including spectral data and extended color models, while maintaining compatibility with existing profiles.
Re-exports§
pub use error::Error;
Modules§
Structs§
Functions§
- format_
hex_ with_ spaces - Render bytes as uppercase hex grouped into 4-byte (8-hex) chunks separated by spaces. Example: [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC] -> “12345678 9abc” This is used for displaying binary data in a human-readable format.
- is_
printable_ ascii_ bytes - parse_
hex_ string - Parse a hex string with optional spaces into a byte vector. Example: “12345678 9abc” -> [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC] This is used for converting human-readable hex strings back into binary data.