1use super::EncodableColor;
4use crate::channel::{AngularChannelScalar, PosNormalChannelScalar};
5use crate::color_space::{ColorSpace, SpacedColor, WithColorSpace};
6use crate::convert::{FromColor, FromHsi, FromYCbCr};
7use crate::encoding::encode::{ColorEncoding, LinearEncoding, TranscodableColor};
8use crate::hsi::{Hsi, HsiOutOfGamutMode};
9use crate::ycbcr::{YCbCr, YCbCrModel, YCbCrOutOfGamutMode};
10use crate::{Bounded, Broadcast, Color, Color3, Color4, FromTuple, Invert, Lerp, PolarColor};
11use angle::Angle;
12#[cfg(feature = "approx")]
13use approx;
14use num_traits;
15
16use std::fmt;
17use std::ops::{Deref, DerefMut};
18
19#[derive(Copy, Clone, Debug, PartialEq, Eq)]
24pub struct EncodedColor<C, E> {
25 color: C,
26 encoding: E,
27}
28
29pub type LinearColor<C> = EncodedColor<C, LinearEncoding>;
31
32impl<C, E> EncodedColor<C, E>
33where
34 C: Color + EncodableColor,
35 E: ColorEncoding,
36{
37 pub fn new(color: C, encoding: E) -> Self {
39 EncodedColor { color, encoding }
40 }
41}
42impl<C, E> EncodedColor<C, E>
43where
44 C: Color,
45 E: ColorEncoding,
46{
47 pub fn decompose(self) -> (C, E) {
49 (self.color, self.encoding)
50 }
51 pub fn color(&self) -> &C {
53 &self.color
54 }
55 pub fn color_mut(&mut self) -> &mut C {
57 &mut self.color
58 }
59 pub fn strip_encoding(self) -> C {
61 self.color
62 }
63 pub fn encoding(&self) -> &E {
65 &self.encoding
66 }
67}
68
69impl<C, E> EncodedColor<C, E>
70where
71 E: ColorEncoding,
72 C: TranscodableColor,
73{
74 pub fn decode(self) -> EncodedColor<C, LinearEncoding> {
78 let decoded_color = self.color.decode_color(&self.encoding);
79 EncodedColor::new(decoded_color, LinearEncoding::new())
80 }
81
82 pub fn transcode<Encoder>(self, new_encoding: Encoder) -> EncodedColor<C, Encoder>
86 where
87 Encoder: ColorEncoding,
88 {
89 let decoded_color = self.decode();
90 decoded_color.encode(new_encoding)
91 }
92}
93impl<C> EncodedColor<C, LinearEncoding>
94where
95 C: TranscodableColor,
96{
97 pub fn encode<Encoder>(self, encoding: Encoder) -> EncodedColor<C, Encoder>
99 where
100 Encoder: ColorEncoding,
101 {
102 self.color.encode_color(&encoding).encoded_as(encoding)
103 }
104}
105
106impl<C, E> EncodedColor<C, E>
107where
108 C: Color + Broadcast + EncodableColor,
109 E: ColorEncoding + PartialEq,
110{
111 pub fn broadcast(value: C::ChannelFormat, encoding: E) -> Self {
113 EncodedColor::new(C::broadcast(value), encoding)
114 }
115}
116
117impl<C, E> EncodedColor<C, E>
118where
119 C: Color + FromTuple + EncodableColor,
120 E: ColorEncoding + PartialEq,
121{
122 pub fn from_tuple(values: C::ChannelsTuple, encoding: E) -> Self {
124 EncodedColor::new(C::from_tuple(values), encoding)
125 }
126}
127
128impl<T, C, E, S> WithColorSpace<T, C, E, S> for EncodedColor<C, E>
129where
130 C: EncodableColor,
131 S: ColorSpace<T>,
132 E: ColorEncoding,
133 T: num_traits::Float,
134{
135 fn with_color_space(self, space: S) -> SpacedColor<T, C, E, S> {
136 SpacedColor::new(self, space)
137 }
138}
139
140impl<C, E> Color for EncodedColor<C, E>
141where
142 C: Color + EncodableColor,
143 E: ColorEncoding + PartialEq,
144{
145 type Tag = C::Tag;
146 type ChannelsTuple = C::ChannelsTuple;
147
148 fn num_channels() -> u32 {
149 C::num_channels()
150 }
151 fn to_tuple(self) -> Self::ChannelsTuple {
152 self.color.to_tuple()
153 }
154}
155
156impl<C, E> Color3 for EncodedColor<C, E>
157where
158 C: Color3 + EncodableColor,
159 E: ColorEncoding + PartialEq,
160{
161}
162
163impl<C, E> Color4 for EncodedColor<C, E>
164where
165 C: Color4 + EncodableColor,
166 E: ColorEncoding + PartialEq,
167{
168}
169
170impl<C, E> PolarColor for EncodedColor<C, E>
171where
172 C: Color + EncodableColor + PolarColor,
173 E: ColorEncoding + PartialEq,
174{
175 type Angular = C::Angular;
176 type Cartesian = C::Cartesian;
177}
178
179impl<C, E> Lerp for EncodedColor<C, E>
180where
181 C: Color + Lerp + EncodableColor,
182 E: ColorEncoding + PartialEq,
183{
184 type Position = C::Position;
185
186 fn lerp(&self, right: &Self, pos: Self::Position) -> Self {
187 if self.encoding != right.encoding {
188 panic!("Tried to interpolate between two different color encodings")
189 }
190 EncodedColor::new(self.color.lerp(&right.color(), pos), self.encoding.clone())
191 }
192}
193
194impl<C, E> Invert for EncodedColor<C, E>
195where
196 C: Color + Invert + EncodableColor,
197 E: ColorEncoding + PartialEq,
198{
199 fn invert(self) -> Self {
200 EncodedColor::new(self.color.invert(), self.encoding)
201 }
202}
203
204impl<C, E> Bounded for EncodedColor<C, E>
205where
206 C: Color + Bounded + EncodableColor,
207 E: ColorEncoding + PartialEq,
208{
209 fn normalize(self) -> Self {
210 EncodedColor::new(self.color.normalize(), self.encoding)
211 }
212 fn is_normalized(&self) -> bool {
213 self.color.is_normalized()
214 }
215}
216
217impl<C, E> EncodableColor for EncodedColor<C, E>
218where
219 C: EncodableColor,
220 E: ColorEncoding + PartialEq,
221{
222}
223
224impl<C, E> Deref for EncodedColor<C, E>
225where
226 C: EncodableColor,
227 E: ColorEncoding,
228{
229 type Target = C;
230
231 fn deref(&self) -> &C {
232 &self.color
233 }
234}
235impl<C, E> DerefMut for EncodedColor<C, E>
236where
237 C: EncodableColor,
238 E: ColorEncoding,
239{
240 fn deref_mut(&mut self) -> &mut C {
241 &mut self.color
242 }
243}
244
245impl<C, E, C2> FromColor<EncodedColor<C2, E>> for EncodedColor<C, E>
246where
247 C: Color + FromColor<C2> + EncodableColor,
248 E: ColorEncoding,
249 C2: EncodableColor,
250{
251 fn from_color(from: &EncodedColor<C2, E>) -> Self {
252 EncodedColor::new(FromColor::from_color(from.color()), from.encoding.clone())
253 }
254}
255
256impl<C, E, T, A> FromHsi<EncodedColor<Hsi<T, A>, E>> for EncodedColor<C, E>
257where
258 C: Color + EncodableColor + FromHsi<Hsi<T, A>>,
259 E: ColorEncoding,
260 T: PosNormalChannelScalar + num_traits::Float,
261 A: AngularChannelScalar + Angle<Scalar = T>,
262{
263 fn from_hsi(from: &EncodedColor<Hsi<T, A>, E>, out_of_gamut_mode: HsiOutOfGamutMode) -> Self {
264 EncodedColor::new(
265 C::from_hsi(&from.color, out_of_gamut_mode),
266 from.encoding.clone(),
267 )
268 }
269}
270impl<C, E, T, M> FromYCbCr<EncodedColor<YCbCr<T, M>, E>> for EncodedColor<C, E>
271where
272 C: Color + EncodableColor + FromYCbCr<YCbCr<T, M>>,
273 E: ColorEncoding,
274 T: PosNormalChannelScalar + num_traits::Float,
275 M: YCbCrModel<T>,
276{
277 fn from_ycbcr(
278 from: &EncodedColor<YCbCr<T, M>, E>,
279 out_of_gamut_mode: YCbCrOutOfGamutMode,
280 ) -> Self {
281 EncodedColor::new(
282 C::from_ycbcr(&from.color, out_of_gamut_mode),
283 from.encoding.clone(),
284 )
285 }
286}
287
288#[cfg(feature = "approx")]
289impl<C, E> approx::AbsDiffEq for EncodedColor<C, E>
290where
291 C: Color + EncodableColor + approx::AbsDiffEq,
292 E: ColorEncoding + PartialEq,
293{
294 type Epsilon = C::Epsilon;
295
296 fn default_epsilon() -> Self::Epsilon {
297 C::default_epsilon()
298 }
299 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
300 (self.encoding == other.encoding) && self.color.abs_diff_eq(&other.color, epsilon)
301 }
302}
303#[cfg(feature = "approx")]
304impl<C, E> approx::RelativeEq for EncodedColor<C, E>
305where
306 C: Color + EncodableColor + approx::RelativeEq,
307 E: ColorEncoding + PartialEq,
308{
309 fn default_max_relative() -> Self::Epsilon {
310 C::default_max_relative()
311 }
312 fn relative_eq(
313 &self,
314 other: &Self,
315 epsilon: Self::Epsilon,
316 max_relative: Self::Epsilon,
317 ) -> bool {
318 (self.encoding == other.encoding)
319 && self.color.relative_eq(&other.color, epsilon, max_relative)
320 }
321}
322
323#[cfg(feature = "approx")]
324impl<C, E> approx::UlpsEq for EncodedColor<C, E>
325where
326 C: Color + EncodableColor + approx::UlpsEq,
327 E: ColorEncoding + PartialEq,
328{
329 fn default_max_ulps() -> u32 {
330 C::default_max_ulps()
331 }
332 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
333 (self.encoding == other.encoding) && self.color.ulps_eq(&other.color, epsilon, max_ulps)
334 }
335}
336
337impl<C, E> fmt::Display for EncodedColor<C, E>
338where
339 C: Color + EncodableColor + fmt::Display,
340 E: ColorEncoding + fmt::Display,
341{
342 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
343 write!(f, "{} as {}", self.color, self.encoding)
344 }
345}
346
347#[cfg(test)]
348mod tests {
349 use super::*;
350 use crate::test;
351 use crate::{Hsv, Rgb};
352 use angle::Deg;
353 use approx::*;
354
355 #[test]
356 fn test_encode_as() {
357 let c1 = Rgb::new(0.5, 0.5, 0.5);
358 let e1 = c1.clone().encoded_as(LinearEncoding {});
359
360 assert_eq!(&c1, e1.color());
361 assert_eq!(e1.encoding(), &LinearEncoding {});
362
363 let e2 = c1.clone().linear();
364
365 assert_eq!(e1, e2);
366
367 let c3 = Rgb::new(0.25, 0.5, 0.75).linear().invert();
368 assert_eq!(c3, Rgb::new(0.75, 0.5, 0.25).linear());
369 }
370
371 #[test]
372 fn test_deref() {
373 let mut e1 = Rgb::new(1.0, 0.0, 0.5).srgb_encoded();
374
375 assert_eq!(e1.red(), 1.0);
376 assert_eq!(e1.green(), 0.0);
377 assert_eq!(e1.blue(), 0.5);
378 assert_eq!(e1.clone().to_tuple(), (1.0, 0.0, 0.5));
379 assert_eq!(&*e1, e1.color());
380
381 *e1.blue_mut() = 0.33;
382 assert_eq!(e1.blue(), 0.33);
383
384 let e2 = Hsv::new(Deg(180.0), 0.5, 0.25).srgb_encoded();
385 assert_eq!(e2.hue(), e2.color().hue());
386 assert_eq!(e2.hue(), Deg(180.0));
387 }
388
389 #[test]
390 fn test_convert() {
391 for color in test::build_hs_test_data() {
392 let rgb = color.rgb.clone().linear();
393 let hsv = color.hsv.clone().linear();
394
395 assert_relative_eq!(
396 EncodedColor::<Hsv<_>, _>::from_color(&rgb),
397 hsv,
398 epsilon = 1e-3
399 );
400 }
401 }
402}