Skip to content

Commit f189e06

Browse files
committed
Provide ImageBuffer::set_color_space
1 parent c82bfa4 commit f189e06

File tree

4 files changed

+42
-19
lines changed

4 files changed

+42
-19
lines changed

src/error.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ pub enum ParameterErrorKind {
125125
DimensionMismatch,
126126
/// Repeated an operation for which error that could not be cloned was emitted already.
127127
FailedAlready,
128+
/// The cicp is required to be RGB-like but had other matrix transforms or narrow range.
129+
RgbCicpRequired(Cicp),
128130
/// A string describing the parameter.
129131
/// This is discouraged and is likely to get deprecated (but not removed).
130132
Generic(String),
@@ -427,6 +429,10 @@ impl fmt::Display for ParameterError {
427429
fmt,
428430
"The end the image stream has been reached due to a previous error"
429431
),
432+
ParameterErrorKind::RgbCicpRequired(cicp) => {
433+
write!(fmt, "The CICP {cicp:?} can not be used for RGB images",)
434+
}
435+
430436
ParameterErrorKind::Generic(message) => {
431437
write!(fmt, "The parameter is malformed: {message}",)
432438
}

src/images/buffer.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,6 +1024,19 @@ impl<P: Pixel, Container> ImageBuffer<P, Container> {
10241024
pub fn color_space(&self) -> Cicp {
10251025
self.color.into()
10261026
}
1027+
1028+
/// Set primaries and transfer characteristics from a Cicp color space.
1029+
///
1030+
/// Returns an error if `cicp` uses features that are not support with an RGB color space, e.g.
1031+
/// a matrix or narrow range (studio encoding) channels.
1032+
pub fn set_color_space(&mut self, cicp: Cicp) -> ImageResult<()> {
1033+
self.color = cicp.try_into_rgb()?;
1034+
Ok(())
1035+
}
1036+
1037+
pub(crate) fn set_rgb_color_space(&mut self, color: CicpRgb) {
1038+
self.color = color;
1039+
}
10271040
}
10281041

10291042
impl<P, Container> ImageBuffer<P, Container>

src/images/dynimage.rs

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,14 @@ impl DynamicImage {
745745
dynamic_map!(self, ref p, p.color_space())
746746
}
747747

748+
/// Set primaries and transfer characteristics from a Cicp color space.
749+
///
750+
/// Returns an error if `cicp` uses features that are not support with an RGB color space, e.g.
751+
/// a matrix or narrow range (studio encoding) channels.
752+
pub fn set_color_space(&mut self, cicp: Cicp) -> ImageResult<()> {
753+
dynamic_map!(self, ref mut p, p.set_color_space(cicp))
754+
}
755+
748756
/// Whether the image contains an alpha channel
749757
///
750758
/// This is a convenience wrapper around `self.color().has_alpha()`.
@@ -1189,20 +1197,12 @@ impl DynamicImage {
11891197
return Ok(());
11901198
}
11911199

1192-
// Forward compatibility: make sure we do not drop any details here.
1193-
if Cicp::from(cicp.into_rgb()) != cicp {
1194-
return Err(ImageError::Parameter(ParameterError::from_kind(
1195-
ParameterErrorKind::Generic("Not an RGB like CICP color space".to_string()),
1196-
)));
1197-
}
1198-
11991200
// We could conceivably do this in-place faster but to handle the Luma conversion as we
12001201
// want this requires the full machinery as `CicpTransform::transform_dynamic` which is
12011202
// quite the replication. Let's just see if it is fast enough. Feel free to PR something if
12021203
// it is easy enough to review.
12031204
let mut target = self.clone();
1204-
target.set_rgb_primaries(cicp.primaries);
1205-
target.set_transfer_function(cicp.transfer);
1205+
target.set_color_space(cicp)?;
12061206
target.copy_from_color_space(self, options)?;
12071207

12081208
*self = target;
@@ -1233,16 +1233,9 @@ impl DynamicImage {
12331233
}
12341234

12351235
// Forward compatibility: make sure we do not drop any details here.
1236-
if Cicp::from(cicp.into_rgb()) != cicp {
1237-
return Err(ImageError::Parameter(ParameterError::from_kind(
1238-
ParameterErrorKind::Generic("Not an RGB like CICP color space".to_string()),
1239-
)));
1240-
}
1241-
1236+
let rgb = cicp.try_into_rgb()?;
12421237
let mut target = DynamicImage::new(self.width(), self.height(), color);
1243-
1244-
target.set_rgb_primaries(cicp.primaries);
1245-
target.set_transfer_function(cicp.transfer);
1238+
dynamic_map!(target, ref mut p, p.set_rgb_color_space(rgb));
12461239
target.copy_from_color_space(self, options)?;
12471240

12481241
*self = target;

src/metadata/cicp.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ use std::sync::Arc;
33
/// CICP (coding independent code points) defines the colorimetric interpretation of rgb-ish color
44
/// components.
55
use crate::{
6+
error::{ParameterError, ParameterErrorKind},
67
math::multiply_accumulate,
78
traits::{
89
private::{LayoutWithColor, SealedPixelWithColorType},
910
PixelWithColorType,
1011
},
11-
ColorType, DynamicImage,
12+
ColorType, DynamicImage, ImageError,
1213
};
1314

1415
/// Reference: <https://www.itu.int/rec/T-REC-H.273-202407-I/en> (V4)
@@ -1204,6 +1205,16 @@ impl Cicp {
12041205
luminance: DerivedLuminance::NonConstant,
12051206
}
12061207
}
1208+
1209+
pub(crate) fn try_into_rgb(self) -> Result<CicpRgb, ImageError> {
1210+
if Cicp::from(self.into_rgb()) != self {
1211+
Err(ImageError::Parameter(ParameterError::from_kind(
1212+
ParameterErrorKind::RgbCicpRequired(self),
1213+
)))
1214+
} else {
1215+
Ok(self.into_rgb())
1216+
}
1217+
}
12071218
}
12081219

12091220
impl CicpRgb {

0 commit comments

Comments
 (0)