Files
another-boids-in-rust/vendor/moxcms/src/cicp.rs

643 lines
26 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* // Copyright (c) Radzivon Bartoshyk 2/2025. All rights reserved.
* //
* // Redistribution and use in source and binary forms, with or without modification,
* // are permitted provided that the following conditions are met:
* //
* // 1. Redistributions of source code must retain the above copyright notice, this
* // list of conditions and the following disclaimer.
* //
* // 2. Redistributions in binary form must reproduce the above copyright notice,
* // this list of conditions and the following disclaimer in the documentation
* // and/or other materials provided with the distribution.
* //
* // 3. Neither the name of the copyright holder nor the names of its
* // contributors may be used to endorse or promote products derived from
* // this software without specific prior written permission.
* //
* // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
use crate::gamma::{
bt1361_to_linear, hlg_to_linear, iec61966_to_linear, log100_sqrt10_to_linear, log100_to_linear,
pq_to_linear, smpte240_to_linear, smpte428_to_linear,
};
use crate::{
Chromaticity, ColorProfile, Matrix3d, Matrix3f, XyYRepresentable,
err::CmsError,
trc::{ToneReprCurve, build_trc_table, curve_from_gamma},
};
use std::convert::TryFrom;
/// See [Rec. ITU-T H.273 (12/2016)](https://www.itu.int/rec/T-REC-H.273-201612-I/en) Table 2
/// Values 0, 3, 1321, 23255 are all reserved so all map to the same variant
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum CicpColorPrimaries {
/// For future use by ITU-T | ISO/IEC
Reserved,
/// Rec. ITU-R BT.709-6<br />
/// Rec. ITU-R BT.1361-0 conventional colour gamut system and extended colour gamut system (historical)<br />
/// IEC 61966-2-1 sRGB or sYCC IEC 61966-2-4<br />
/// Society of Motion Picture and Television Engineers (MPTE) RP 177 (1993) Annex B<br />
Bt709 = 1,
/// Unspecified<br />
/// Image characteristics are unknown or are determined by the application.
Unspecified = 2,
/// Rec. ITU-R BT.470-6 System M (historical)<br />
/// United States National Television System Committee 1953 Recommendation for transmission standards for color television<br />
/// United States Federal Communications Commission (2003) Title 47 Code of Federal Regulations 73.682 (a) (20)<br />
Bt470M = 4,
/// Rec. ITU-R BT.470-6 System B, G (historical) Rec. ITU-R BT.601-7 625<br />
/// Rec. ITU-R BT.1358-0 625 (historical)<br />
/// Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM<br />
Bt470Bg = 5,
/// Rec. ITU-R BT.601-7 525<br />
/// Rec. ITU-R BT.1358-1 525 or 625 (historical) Rec. ITU-R BT.1700-0 NTSC<br />
/// SMPTE 170M (2004)<br />
/// (functionally the same as the value 7)<br />
Bt601 = 6,
/// SMPTE 240M (1999) (historical) (functionally the same as the value 6)<br />
Smpte240 = 7,
/// Generic film (colour filters using Illuminant C)<br />
GenericFilm = 8,
/// Rec. ITU-R BT.2020-2<br />
/// Rec. ITU-R BT.2100-0<br />
Bt2020 = 9,
/// SMPTE ST 428-1<br />
/// (CIE 1931 XYZ as in ISO 11664-1)<br />
Xyz = 10,
/// SMPTE RP 431-2 (2011)<br />
Smpte431 = 11,
/// SMPTE EG 432-1 (2010)<br />
Smpte432 = 12,
/// EBU Tech. 3213-E (1975)<br />
Ebu3213 = 22,
}
impl TryFrom<u8> for CicpColorPrimaries {
type Error = CmsError;
#[allow(unreachable_patterns)]
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
// Values 0, 3, 1321, 23255 are all reserved so all map to the
// same variant.
0 | 3 | 13..=21 | 23..=255 => Ok(Self::Reserved),
1 => Ok(Self::Bt709),
2 => Ok(Self::Unspecified),
4 => Ok(Self::Bt470M),
5 => Ok(Self::Bt470Bg),
6 => Ok(Self::Bt601),
7 => Ok(Self::Smpte240),
8 => Ok(Self::GenericFilm),
9 => Ok(Self::Bt2020),
10 => Ok(Self::Xyz),
11 => Ok(Self::Smpte431),
12 => Ok(Self::Smpte432),
22 => Ok(Self::Ebu3213),
_ => Err(CmsError::InvalidCicp),
}
}
}
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct ColorPrimaries {
pub red: Chromaticity,
pub green: Chromaticity,
pub blue: Chromaticity,
}
/// See [Rec. ITU-T H.273 (12/2016)](https://www.itu.int/rec/T-REC-H.273-201612-I/en) Table 2.
impl ColorPrimaries {
/// [ACEScg](https://en.wikipedia.org/wiki/Academy_Color_Encoding_System#ACEScg).
pub const ACES_CG: ColorPrimaries = ColorPrimaries {
red: Chromaticity { x: 0.713, y: 0.293 },
green: Chromaticity { x: 0.165, y: 0.830 },
blue: Chromaticity { x: 0.128, y: 0.044 },
};
/// [ACES2065-1](https://en.wikipedia.org/wiki/Academy_Color_Encoding_System#ACES2065-1).
pub const ACES_2065_1: ColorPrimaries = ColorPrimaries {
red: Chromaticity {
x: 0.7347,
y: 0.2653,
},
green: Chromaticity {
x: 0.0000,
y: 1.0000,
},
blue: Chromaticity {
x: 0.0001,
y: -0.0770,
},
};
/// [Adobe RGB](https://en.wikipedia.org/wiki/Adobe_RGB_color_space) (1998).
pub const ADOBE_RGB: ColorPrimaries = ColorPrimaries {
red: Chromaticity { x: 0.64, y: 0.33 },
green: Chromaticity { x: 0.21, y: 0.71 },
blue: Chromaticity { x: 0.15, y: 0.06 },
};
/// [DCI P3](https://en.wikipedia.org/wiki/DCI-P3#DCI_P3).
///
/// This is the same as [`DISPLAY_P3`](Self::DISPLAY_P3),
/// [`SMPTE_431`](Self::SMPTE_431) and [`SMPTE_432`](Self::SMPTE_432).
pub const DCI_P3: ColorPrimaries = ColorPrimaries {
red: Chromaticity { x: 0.680, y: 0.320 },
green: Chromaticity { x: 0.265, y: 0.690 },
blue: Chromaticity { x: 0.150, y: 0.060 },
};
/// [Diplay P3](https://en.wikipedia.org/wiki/DCI-P3#Display_P3).
///
/// This is the same as [`DCI_P3`](Self::DCI_P3),
/// [`SMPTE_431`](Self::SMPTE_431) and [`SMPTE_432`](Self::SMPTE_432).
pub const DISPLAY_P3: ColorPrimaries = Self::DCI_P3;
/// SMPTE RP 431-2 (2011).
///
/// This is the same as [`DCI_P3`](Self::DCI_P3),
/// [`DISPLAY_P3`](Self::DISPLAY_P3) and [`SMPTE_432`](Self::SMPTE_432).
pub const SMPTE_431: ColorPrimaries = Self::DCI_P3;
/// SMPTE EG 432-1 (2010).
///
/// This is the same as [`DCI_P3`](Self::DCI_P3),
/// [`DISPLAY_P3`](Self::DISPLAY_P3) and [`SMPTE_431`](Self::SMPTE_431).
pub const SMPTE_432: ColorPrimaries = Self::DCI_P3;
/// [ProPhoto RGB](https://en.wikipedia.org/wiki/ProPhoto_RGB_color_space).
pub const PRO_PHOTO_RGB: ColorPrimaries = ColorPrimaries {
red: Chromaticity {
x: 0.734699,
y: 0.265301,
},
green: Chromaticity {
x: 0.159597,
y: 0.840403,
},
blue: Chromaticity {
x: 0.036598,
y: 0.000105,
},
};
/// Rec. ITU-R BT.709-6
///
/// Rec. ITU-R BT.1361-0 conventional colour gamut system and extended
/// colour gamut system (historical).
///
/// IEC 61966-2-1 sRGB or sYCC IEC 61966-2-4).
///
/// Society of Motion Picture and Television Engineers (MPTE) RP 177 (1993) Annex B.
pub const BT_709: ColorPrimaries = ColorPrimaries {
red: Chromaticity { x: 0.64, y: 0.33 },
green: Chromaticity { x: 0.30, y: 0.60 },
blue: Chromaticity { x: 0.15, y: 0.06 },
};
/// Rec. ITU-R BT.470-6 System M (historical).
///
/// United States National Television System Committee 1953 Recommendation
/// for transmission standards for color television.
///
/// United States Federal Communications Commission (2003) Title 47 Code of
/// Federal Regulations 73.682 (a) (20).
pub const BT_470M: ColorPrimaries = ColorPrimaries {
red: Chromaticity { x: 0.67, y: 0.33 },
green: Chromaticity { x: 0.21, y: 0.71 },
blue: Chromaticity { x: 0.14, y: 0.08 },
};
/// Rec. ITU-R BT.470-6 System B, G (historical) Rec. ITU-R BT.601-7 625.
///
/// Rec. ITU-R BT.1358-0 625 (historical).
/// Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM.
pub const BT_470BG: ColorPrimaries = ColorPrimaries {
red: Chromaticity { x: 0.64, y: 0.33 },
green: Chromaticity { x: 0.29, y: 0.60 },
blue: Chromaticity { x: 0.15, y: 0.06 },
};
/// Rec. ITU-R BT.601-7 525.
///
/// Rec. ITU-R BT.1358-1 525 or 625 (historical) Rec. ITU-R BT.1700-0 NTSC.
///
/// SMPTE 170M (2004) (functionally the same as the [`SMPTE_240`](Self::SMPTE_240)).
pub const BT_601: ColorPrimaries = ColorPrimaries {
red: Chromaticity { x: 0.630, y: 0.340 },
green: Chromaticity { x: 0.310, y: 0.595 },
blue: Chromaticity { x: 0.155, y: 0.070 },
};
/// SMPTE 240M (1999) (historical) (functionally the same as [`BT_601`](Self::BT_601)).
pub const SMPTE_240: ColorPrimaries = Self::BT_601;
/// Generic film (colour filters using Illuminant C).
pub const GENERIC_FILM: ColorPrimaries = ColorPrimaries {
red: Chromaticity { x: 0.681, y: 0.319 },
green: Chromaticity { x: 0.243, y: 0.692 },
blue: Chromaticity { x: 0.145, y: 0.049 },
};
/// Rec. ITU-R BT.2020-2.
///
/// Rec. ITU-R BT.2100-0.
pub const BT_2020: ColorPrimaries = ColorPrimaries {
red: Chromaticity { x: 0.708, y: 0.292 },
green: Chromaticity { x: 0.170, y: 0.797 },
blue: Chromaticity { x: 0.131, y: 0.046 },
};
/// SMPTE ST 428-1 (CIE 1931 XYZ as in ISO 11664-1).
pub const XYZ: ColorPrimaries = ColorPrimaries {
red: Chromaticity { x: 1.0, y: 0.0 },
green: Chromaticity { x: 0.0, y: 1.0 },
blue: Chromaticity { x: 0.0, y: 0.0 },
};
/// EBU Tech. 3213-E (1975).
pub const EBU_3213: ColorPrimaries = ColorPrimaries {
red: Chromaticity { x: 0.630, y: 0.340 },
green: Chromaticity { x: 0.295, y: 0.605 },
blue: Chromaticity { x: 0.155, y: 0.077 },
};
}
impl ColorPrimaries {
/// Returns RGB -> XYZ conversion matrix
///
/// # Arguments
///
/// * `white_point`: [Chromaticity] or [crate::XyY] or any item conforming [XyYRepresentable]
///
/// returns: [Matrix3d]
pub fn transform_to_xyz_d(self, white_point: impl XyYRepresentable) -> Matrix3d {
let red_xyz = self.red.to_scaled_xyzd();
let green_xyz = self.green.to_scaled_xyzd();
let blue_xyz = self.blue.to_scaled_xyzd();
let xyz_matrix = Matrix3d {
v: [
[red_xyz.x, green_xyz.x, blue_xyz.x],
[red_xyz.y, green_xyz.y, blue_xyz.y],
[red_xyz.z, green_xyz.z, blue_xyz.z],
],
};
ColorProfile::rgb_to_xyz_d(xyz_matrix, white_point.to_xyy().to_xyzd())
}
/// Returns RGB -> XYZ conversion matrix
///
/// # Arguments
///
/// * `white_point`: [Chromaticity] or [crate::XyY] or any item conforming [XyYRepresentable]
///
/// returns: [Matrix3f]
pub fn transform_to_xyz(self, white_point: impl XyYRepresentable) -> Matrix3f {
let red_xyz = self.red.to_scaled_xyz();
let green_xyz = self.green.to_scaled_xyz();
let blue_xyz = self.blue.to_scaled_xyz();
let xyz_matrix = Matrix3f {
v: [
[red_xyz.x, green_xyz.x, blue_xyz.x],
[red_xyz.y, green_xyz.y, blue_xyz.y],
[red_xyz.z, green_xyz.z, blue_xyz.z],
],
};
ColorProfile::rgb_to_xyz_static(xyz_matrix, white_point.to_xyy().to_xyz())
}
}
/// See [Rec. ITU-T H.273 (12/2016)](https://www.itu.int/rec/T-REC-H.273-201612-I/en) Table 3
/// Values 0, 3, 19255 are all reserved so all map to the same variant
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum TransferCharacteristics {
/// For future use by ITU-T | ISO/IEC
Reserved,
/// Rec. ITU-R BT.709-6<br />
/// Rec. ITU-R BT.1361-0 conventional colour gamut system (historical)<br />
/// (functionally the same as the values 6, 14 and 15) <br />
Bt709 = 1,
/// Image characteristics are unknown or are determined by the application.<br />
Unspecified = 2,
/// Rec. ITU-R BT.470-6 System M (historical)<br />
/// United States National Television System Committee 1953 Recommendation for transmission standards for color television<br />
/// United States Federal Communications Commission (2003) Title 47 Code of Federal Regulations 73.682 (a) (20)<br />
/// Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM<br />
Bt470M = 4,
/// Rec. ITU-R BT.470-6 System B, G (historical)<br />
Bt470Bg = 5,
/// Rec. ITU-R BT.601-7 525 or 625<br />
/// Rec. ITU-R BT.1358-1 525 or 625 (historical)<br />
/// Rec. ITU-R BT.1700-0 NTSC SMPTE 170M (2004)<br />
/// (functionally the same as the values 1, 14 and 15)<br />
Bt601 = 6,
/// SMPTE 240M (1999) (historical)<br />
Smpte240 = 7,
/// Linear transfer characteristics<br />
Linear = 8,
/// Logarithmic transfer characteristic (100:1 range)<br />
Log100 = 9,
/// Logarithmic transfer characteristic (100 * Sqrt( 10 ) : 1 range)<br />
Log100sqrt10 = 10,
/// IEC 61966-2-4<br />
Iec61966 = 11,
/// Rec. ITU-R BT.1361-0 extended colour gamut system (historical)<br />
Bt1361 = 12,
/// IEC 61966-2-1 sRGB or sYCC<br />
Srgb = 13,
/// Rec. ITU-R BT.2020-2 (10-bit system)<br />
/// (functionally the same as the values 1, 6 and 15)<br />
Bt202010bit = 14,
/// Rec. ITU-R BT.2020-2 (12-bit system)<br />
/// (functionally the same as the values 1, 6 and 14)<br />
Bt202012bit = 15,
/// SMPTE ST 2084 for 10-, 12-, 14- and 16-bitsystems<br />
/// Rec. ITU-R BT.2100-0 perceptual quantization (PQ) system<br />
Smpte2084 = 16,
/// SMPTE ST 428-1<br />
Smpte428 = 17,
/// ARIB STD-B67<br />
/// Rec. ITU-R BT.2100-0 hybrid log- gamma (HLG) system<br />
Hlg = 18,
}
impl TryFrom<u8> for TransferCharacteristics {
type Error = CmsError;
#[allow(unreachable_patterns)]
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 | 3 | 19..=255 => Ok(Self::Reserved),
1 => Ok(Self::Bt709),
2 => Ok(Self::Unspecified),
4 => Ok(Self::Bt470M),
5 => Ok(Self::Bt470Bg),
6 => Ok(Self::Bt601),
7 => Ok(Self::Smpte240), // unimplemented
8 => Ok(Self::Linear),
9 => Ok(Self::Log100),
10 => Ok(Self::Log100sqrt10),
11 => Ok(Self::Iec61966), // unimplemented
12 => Ok(Self::Bt1361), // unimplemented
13 => Ok(Self::Srgb),
14 => Ok(Self::Bt202010bit),
15 => Ok(Self::Bt202012bit),
16 => Ok(Self::Smpte2084),
17 => Ok(Self::Smpte428), // unimplemented
18 => Ok(Self::Hlg),
_ => Err(CmsError::InvalidCicp),
}
}
}
impl CicpColorPrimaries {
pub(crate) const fn has_chromaticity(self) -> bool {
self as u8 != Self::Reserved as u8 && self as u8 != Self::Unspecified as u8
}
pub(crate) const fn white_point(self) -> Result<Chromaticity, CmsError> {
Ok(match self {
Self::Reserved => return Err(CmsError::UnsupportedColorPrimaries(self as u8)),
Self::Bt709
| Self::Bt470Bg
| Self::Bt601
| Self::Smpte240
| Self::Bt2020
| Self::Smpte432
| Self::Ebu3213 => Chromaticity::D65,
Self::Unspecified => return Err(CmsError::UnsupportedColorPrimaries(self as u8)),
Self::Bt470M => Chromaticity { x: 0.310, y: 0.316 },
Self::GenericFilm => Chromaticity { x: 0.310, y: 0.316 },
Self::Xyz => Chromaticity {
x: 1. / 3.,
y: 1. / 3.,
},
Self::Smpte431 => Chromaticity { x: 0.314, y: 0.351 },
})
}
}
impl TryFrom<CicpColorPrimaries> for ColorPrimaries {
type Error = CmsError;
fn try_from(value: CicpColorPrimaries) -> Result<Self, Self::Error> {
match value {
CicpColorPrimaries::Reserved => Err(CmsError::UnsupportedColorPrimaries(value as u8)),
CicpColorPrimaries::Bt709 => Ok(ColorPrimaries::BT_709),
CicpColorPrimaries::Unspecified => {
Err(CmsError::UnsupportedColorPrimaries(value as u8))
}
CicpColorPrimaries::Bt470M => Ok(ColorPrimaries::BT_470M),
CicpColorPrimaries::Bt470Bg => Ok(ColorPrimaries::BT_470BG),
CicpColorPrimaries::Bt601 | CicpColorPrimaries::Smpte240 => Ok(ColorPrimaries::BT_601),
CicpColorPrimaries::GenericFilm => Ok(ColorPrimaries::GENERIC_FILM),
CicpColorPrimaries::Bt2020 => Ok(ColorPrimaries::BT_2020),
CicpColorPrimaries::Xyz => Ok(ColorPrimaries::XYZ),
// These two share primaries, but have distinct white points
CicpColorPrimaries::Smpte431 | CicpColorPrimaries::Smpte432 => {
Ok(ColorPrimaries::SMPTE_431)
}
CicpColorPrimaries::Ebu3213 => Ok(ColorPrimaries::EBU_3213),
}
}
}
impl TransferCharacteristics {
pub(crate) fn has_transfer_curve(self) -> bool {
self != Self::Reserved && self != Self::Unspecified
}
}
pub(crate) fn create_rec709_parametric() -> [f32; 5] {
const POW_EXP: f32 = 0.45;
const G: f32 = 1. / POW_EXP;
const B: f32 = (0.09929682680944f64 / 1.09929682680944f64) as f32;
const C: f32 = 1f32 / 4.5f32;
const D: f32 = (4.5f64 * 0.018053968510807f64) as f32;
const A: f32 = (1. / 1.09929682680944f64) as f32;
[G, A, B, C, D]
}
impl TryFrom<TransferCharacteristics> for ToneReprCurve {
type Error = CmsError;
/// See [ICC.1:2010](https://www.color.org/specification/ICC1v43_2010-12.pdf)
/// See [Rec. ITU-R BT.2100-2](https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.2100-2-201807-I!!PDF-E.pdf)
fn try_from(value: TransferCharacteristics) -> Result<Self, Self::Error> {
const NUM_TRC_TABLE_ENTRIES: i32 = 1024;
Ok(match value {
TransferCharacteristics::Reserved => {
return Err(CmsError::UnsupportedTrc(value as u8));
}
TransferCharacteristics::Bt709
| TransferCharacteristics::Bt601
| TransferCharacteristics::Bt202010bit
| TransferCharacteristics::Bt202012bit => {
// The opto-electronic transfer characteristic function (OETF)
// as defined in ITU-T H.273 table 3, row 1:
//
// V = (α * Lc^0.45) (α 1) for 1 >= Lc >= β
// V = 4.500 * Lc for β > Lc >= 0
//
// Inverting gives the electro-optical transfer characteristic
// function (EOTF) which can be represented as ICC
// parametricCurveType with 4 parameters (ICC.1:2010 Table 5).
// Converting between the two (Lc ↔︎ Y, V ↔︎ X):
//
// Y = (a * X + b)^g for (X >= d)
// Y = c * X for (X < d)
//
// g, a, b, c, d can then be defined in terms of α and β:
//
// g = 1 / 0.45
// a = 1 / α
// b = 1 - α
// c = 1 / 4.500
// d = 4.500 * β
//
// α and β are determined by solving the piecewise equations to
// ensure continuity of both value and slope at the value β.
// We use the values specified for 10-bit systems in
// https://www.itu.int/rec/R-REC-BT.2020-2-201510-I Table 4
// since this results in the similar values as available ICC
// profiles after converting to s15Fixed16Number, providing us
// good test coverage.
ToneReprCurve::Parametric(create_rec709_parametric().to_vec())
}
TransferCharacteristics::Unspecified => {
return Err(CmsError::UnsupportedTrc(value as u8));
}
TransferCharacteristics::Bt470M => curve_from_gamma(2.2),
TransferCharacteristics::Bt470Bg => curve_from_gamma(2.8),
TransferCharacteristics::Smpte240 => {
let table = build_trc_table(NUM_TRC_TABLE_ENTRIES, smpte240_to_linear);
ToneReprCurve::Lut(table)
}
TransferCharacteristics::Linear => curve_from_gamma(1.),
TransferCharacteristics::Log100 => {
let table = build_trc_table(NUM_TRC_TABLE_ENTRIES, log100_to_linear);
ToneReprCurve::Lut(table)
}
TransferCharacteristics::Log100sqrt10 => {
let table = build_trc_table(NUM_TRC_TABLE_ENTRIES, log100_sqrt10_to_linear);
ToneReprCurve::Lut(table)
}
TransferCharacteristics::Iec61966 => {
let table = build_trc_table(NUM_TRC_TABLE_ENTRIES, iec61966_to_linear);
ToneReprCurve::Lut(table)
}
TransferCharacteristics::Bt1361 => {
let table = build_trc_table(NUM_TRC_TABLE_ENTRIES, bt1361_to_linear);
ToneReprCurve::Lut(table)
}
TransferCharacteristics::Srgb => {
ToneReprCurve::Parametric(vec![2.4, 1. / 1.055, 0.055 / 1.055, 1. / 12.92, 0.04045])
}
TransferCharacteristics::Smpte2084 => {
let table = build_trc_table(NUM_TRC_TABLE_ENTRIES, pq_to_linear);
ToneReprCurve::Lut(table)
}
TransferCharacteristics::Smpte428 => {
let table = build_trc_table(NUM_TRC_TABLE_ENTRIES, smpte428_to_linear);
ToneReprCurve::Lut(table)
}
TransferCharacteristics::Hlg => {
let table = build_trc_table(NUM_TRC_TABLE_ENTRIES, hlg_to_linear);
ToneReprCurve::Lut(table)
}
})
}
}
/// Matrix Coefficients Enum (from ISO/IEC 23091-4 / MPEG CICP)
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(C)]
pub enum MatrixCoefficients {
Identity = 0, // RGB (Identity matrix)
Bt709 = 1, // Rec. 709
Unspecified = 2, // Unspecified
Reserved = 3, // Reserved
Fcc = 4, // FCC
Bt470Bg = 5, // BT.470BG / BT.601-625
Smpte170m = 6, // SMPTE 170M / BT.601-525
Smpte240m = 7, // SMPTE 240M
YCgCo = 8, // YCgCo
Bt2020Ncl = 9, // BT.2020 (non-constant luminance)
Bt2020Cl = 10, // BT.2020 (constant luminance)
Smpte2085 = 11, // SMPTE ST 2085
ChromaticityDerivedNCL = 12, // Chromaticity-derived non-constant luminance
ChromaticityDerivedCL = 13, // Chromaticity-derived constant luminance
ICtCp = 14, // ICtCp
}
impl TryFrom<u8> for MatrixCoefficients {
type Error = CmsError;
fn try_from(value: u8) -> Result<Self, CmsError> {
match value {
0 => Ok(MatrixCoefficients::Identity),
1 => Ok(MatrixCoefficients::Bt709),
2 => Ok(MatrixCoefficients::Unspecified),
3 => Ok(MatrixCoefficients::Reserved),
4 => Ok(MatrixCoefficients::Fcc),
5 => Ok(MatrixCoefficients::Bt470Bg),
6 => Ok(MatrixCoefficients::Smpte170m),
7 => Ok(MatrixCoefficients::Smpte240m),
8 => Ok(MatrixCoefficients::YCgCo),
9 => Ok(MatrixCoefficients::Bt2020Ncl),
10 => Ok(MatrixCoefficients::Bt2020Cl),
11 => Ok(MatrixCoefficients::Smpte2085),
12 => Ok(MatrixCoefficients::ChromaticityDerivedNCL),
13 => Ok(MatrixCoefficients::ChromaticityDerivedCL),
14 => Ok(MatrixCoefficients::ICtCp),
_ => Err(CmsError::InvalidCicp),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::WHITE_POINT_D65;
#[test]
fn test_to_xyz_using_absolute_coordinates() {
let conversion_matrix = ColorPrimaries::BT_709.transform_to_xyz_d(WHITE_POINT_D65);
assert!((conversion_matrix.v[0][0] - 0.4121524015214193).abs() < 1e-14);
assert!((conversion_matrix.v[1][1] - 0.7153537403945436).abs() < 1e-14);
assert!((conversion_matrix.v[2][2] - 0.9497138466283235).abs() < 1e-14);
}
#[test]
fn test_to_xyz_using_absolute_coordinates_xyz() {
let conversion_matrix = ColorPrimaries::XYZ.transform_to_xyz_d(WHITE_POINT_D65);
assert!((conversion_matrix.v[0][0] - 0.95015469385536477).abs() < 1e-14);
assert!((conversion_matrix.v[1][1] - 1.0).abs() < 1e-14);
assert!((conversion_matrix.v[2][2] - 1.0882590676722474).abs() < 1e-14);
}
#[test]
fn test_to_xyz_using_absolute_coordinates_f() {
let conversion_matrix = ColorPrimaries::BT_709.transform_to_xyz(WHITE_POINT_D65);
assert!((conversion_matrix.v[0][0] - 0.4121524015214193).abs() < 1e-5);
assert!((conversion_matrix.v[1][1] - 0.7153537403945436).abs() < 1e-5);
assert!((conversion_matrix.v[2][2] - 0.9497138466283235).abs() < 1e-5);
}
}