color/
luma.rs

1// Copyright 2013 The color-rs developers. For a full listing of the authors,
2// refer to the AUTHORS file at the top-level directory of this distribution.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//     http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use num_traits::{Saturating, NumCast, Num};
17use std::ops::{Mul, Div, Add, Sub};
18use std::marker::PhantomData;
19
20use {Color, FloatColor};
21use {Channel, FloatChannel};
22use {Hsv, ToHsv};
23use {ToRgb, Rgb};
24use alpha::{ToRgba, Rgba};
25use color_space::{Srgb, TransferFunction};
26
27
28#[derive(Serialize, Deserialize, Debug)]
29pub struct Luma<T, S = Srgb> { pub l: T, pub standard: PhantomData<S> }
30
31impl<T: Clone, S> Clone for Luma<T, S>{
32    fn clone(&self) -> Luma<T, S>{
33        Luma{ l: self.l.clone(), standard: PhantomData }
34    }
35}
36
37impl<T: Copy, S> Copy for Luma<T, S>{}
38
39impl<N: PartialEq, S> PartialEq for Luma<N, S>{
40	#[inline]
41	fn eq(&self, other: &Luma<N, S>) -> bool{
42		self.l.eq(&other.l)
43	}
44}
45
46impl<N: Clone + PartialEq + Eq + Num + NumCast, S> Eq for Luma<N, S>{}
47
48impl<T, S> Luma<T, S> {
49    pub const fn new(l: T) -> Luma<T, S> {
50        Luma { l, standard: PhantomData }
51    }
52}
53
54impl<T:Channel, S> Luma<T, S> {
55    pub fn from_hex(hex: u8) -> Luma<T> {
56        Luma::<u8>::new(hex).to_luma()
57    }
58}
59
60impl<T:Channel, S> Color<T> for Luma<T, S> {
61    /// Clamps the components of the color to the range `(lo,hi)`.
62    #[inline]
63    fn clamp_s(self, lo: T, hi: T) -> Luma<T,S> {
64        Luma::new(self.l.clamp(lo, hi))
65    }
66
67    /// Clamps the components of the color component-wise between `lo` and `hi`.
68    #[inline]
69    fn clamp_c(self, lo: Luma<T,S>, hi: Luma<T,S>) -> Luma<T,S> {
70        Luma::new(self.l.clamp(lo.l, hi.l))
71    }
72
73    /// Inverts the color.
74    #[inline]
75    fn inverse(self) -> Luma<T,S> {
76        Luma::new(self.l.invert_channel())
77    }
78
79    #[inline]
80    fn mix(self, other: Self, value: T) -> Self {
81        Luma::new(self.l.mix(other.l, value))
82    }
83}
84
85impl<T:FloatChannel, S> FloatColor<T> for Luma<T, S> {
86    /// Clamps the components of the color to the range `(0,1)`.
87    #[inline]
88    fn saturate(self) -> Luma<T, S> {
89        Luma::new(self.l.saturate())
90    }
91}
92
93pub trait ToLuma {
94    type Standard: TransferFunction;
95    fn to_luma<U:Channel>(&self) -> Luma<U, Self::Standard>;
96}
97
98impl ToLuma for u8 {
99    type Standard = Srgb;
100    fn to_luma<U: Channel>(&self) -> Luma<U, Srgb> {
101        Luma::new(Channel::from(*self))
102    }
103}
104
105impl<T: Channel, S: TransferFunction> ToLuma for Luma<T, S> {
106    type Standard = S;
107    fn to_luma<U: Channel>(&self) -> Luma<U, S> {
108        Luma::new(Channel::from(self.l))
109    }
110}
111
112impl<T:Clone + Channel, S: TransferFunction> ToRgb for Luma<T, S> {
113    type Standard = S;
114    #[inline]
115    fn to_rgb<U:Channel>(&self) -> Rgb<U, S> {
116        let r = self.l.to_channel();
117        Rgb::new(r, r, r)
118    }
119}
120
121impl<T:Clone + Channel, S: TransferFunction> ToRgba for Luma<T, S> {
122    type Standard = S;
123    #[inline]
124    fn to_rgba<U:Channel>(&self) -> Rgba<U, S> {
125        let r = self.l.to_channel();
126        Rgba::new(Rgb::new(r, r, r), 1f32.to_channel())
127    }
128}
129
130impl<T:Channel + NumCast + Num, S: TransferFunction> ToHsv for Luma<T,S> {
131    type Standard = S;
132    #[inline]
133    fn to_hsv<U:Channel + NumCast + Num>(&self) -> Hsv<U, S> {
134        self.to_rgb::<U>().to_hsv()
135    }
136}
137
138impl<T:Channel, S> Mul for Luma<T, S> {
139    type Output = Luma<T, S>;
140
141    #[inline]
142    fn mul(self, rhs: Luma<T, S>) -> Luma<T, S> {
143        Luma::new(self.l.normalized_mul(rhs.l))
144    }
145}
146
147impl<T:Channel + Mul<T,Output=T>, S> Mul<T> for Luma<T, S> {
148    type Output = Luma<T, S>;
149
150    #[inline]
151    fn mul(self, rhs: T) -> Luma<T, S> {
152        Luma::new(self.l * rhs)
153    }
154}
155
156
157impl<T:Channel, S> Div for Luma<T, S> {
158    type Output = Luma<T, S>;
159
160    #[inline]
161    fn div(self, rhs: Luma<T, S>) -> Luma<T, S> {
162        Luma::new(self.l.normalized_div(rhs.l))
163    }
164}
165
166impl<T:Channel + Div<T,Output=T>, S> Div<T> for Luma<T, S> {
167    type Output = Luma<T, S>;
168
169    #[inline]
170    fn div(self, rhs: T) -> Luma<T, S> {
171        Luma::new(self.l / rhs)
172    }
173}
174
175impl<T:Channel + Add<T,Output=T>, S> Add for Luma<T, S> {
176    type Output = Luma<T, S>;
177
178    #[inline]
179    fn add(self, rhs: Luma<T, S>) -> Luma<T, S> {
180        Luma::new(self.l + rhs.l)
181    }
182}
183
184impl<T:Channel + Sub<T,Output=T>, S> Sub for Luma<T, S> {
185    type Output = Luma<T, S>;
186
187    #[inline]
188    fn sub(self, rhs: Luma<T, S>) -> Luma<T, S> {
189        Luma::new(self.l - rhs.l)
190    }
191}
192
193impl<T:Channel + Saturating, S> Saturating for Luma<T, S> {
194    fn saturating_add(self, v: Luma<T, S>) -> Luma<T, S> {
195        Luma::new(self.l.saturating_add(v.l))
196    }
197
198    fn saturating_sub(self, v: Luma<T, S>) -> Luma<T, S> {
199        Luma::new(self.l.saturating_sub(v.l))
200    }
201}