Skip to content

Commit c082bab

Browse files
committed
Auto merge of #22 - Ogeon:alpha, r=Ogeon
Extract the alpha component as a wrapper type This closes #11 by adding a wrapper type that bolts the alpha component to any color. This works well because of how passive the alpha is in most of the calculations and conversions, and results in a relatively low amount of code duplication. Each color space (and `Color`) has a sibling type alias with an `a` added to the name, such as `Rgba`. Those are alias for `Alpha<C<T>, T>`, where `C` is the color space type, and can be used more or less in the same way as their non-alpha variants. Conversion between alpha types and non-alpha types is as easy as always. This is a breaking change, since the alpha component is removed from every color and constructors are moved and/or renamed. The new constructors follows the same convention as the constructors in `Srgb` and `GammaRgb`, which is `new` for float values and `new_u8` for `u8` values. The constructors on `Color` are roughly the same as before, with the exception of changing things like `rgb8` to `rgb_u8`.
2 parents 2ce80b0 + 95a51dc commit c082bab

16 files changed

+576
-380
lines changed

README.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,13 @@ extern crate palette;
110110
use palette::{Rgb, Hsv, Gradient};
111111

112112
let grad1 = Gradient::new(vec![
113-
Rgb::rgb(1.0, 0.1, 0.1),
114-
Rgb::rgb(0.1, 1.0, 1.0)
113+
Rgb::new(1.0, 0.1, 0.1),
114+
Rgb::new(0.1, 1.0, 1.0)
115115
]);
116116

117117
let grad2 = Gradient::new(vec![
118-
Hsv::from(Rgb::rgb(1.0, 0.1, 0.1)),
119-
Hsv::from(Rgb::rgb(0.1, 1.0, 1.0))
118+
Hsv::from(Rgb::new(1.0, 0.1, 0.1)),
119+
Hsv::from(Rgb::new(0.1, 1.0, 1.0))
120120
]);
121121
```
122122

examples/gradient.rs

+12-12
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,30 @@ use image::{RgbImage, GenericImage};
99
fn main() {
1010
//A gradient of evenly spaced colors
1111
let grad1 = Gradient::new(vec![
12-
Rgb::rgb(1.0, 0.1, 0.1),
13-
Rgb::rgb(0.1, 0.1, 1.0),
14-
Rgb::rgb(0.1, 1.0, 0.1)
12+
Rgb::new(1.0, 0.1, 0.1),
13+
Rgb::new(0.1, 0.1, 1.0),
14+
Rgb::new(0.1, 1.0, 0.1)
1515
]);
1616

1717
//The same colors as in grad1, but with the blue point shifted down
1818
let grad2 = Gradient::with_domain(vec![
19-
(0.0, Rgb::rgb(1.0, 0.1, 0.1)),
20-
(0.25, Rgb::rgb(0.1, 0.1, 1.0)),
21-
(1.0, Rgb::rgb(0.1, 1.0, 0.1))
19+
(0.0, Rgb::new(1.0, 0.1, 0.1)),
20+
(0.25, Rgb::new(0.1, 0.1, 1.0)),
21+
(1.0, Rgb::new(0.1, 1.0, 0.1))
2222
]);
2323

2424
//The same colors and offsets as in grad1, but in a color space where the hue is a component
2525
let grad3 = Gradient::new(vec![
26-
Lch::from(Rgb::rgb(1.0, 0.1, 0.1)),
27-
Lch::from(Rgb::rgb(0.1, 0.1, 1.0)),
28-
Lch::from(Rgb::rgb(0.1, 1.0, 0.1))
26+
Lch::from(Rgb::new(1.0, 0.1, 0.1)),
27+
Lch::from(Rgb::new(0.1, 0.1, 1.0)),
28+
Lch::from(Rgb::new(0.1, 1.0, 0.1))
2929
]);
3030

3131
//The same colors and and color space as in grad3, but with the blue point shifted down
3232
let grad4 = Gradient::with_domain(vec![
33-
(0.0, Lch::from(Rgb::rgb(1.0, 0.1, 0.1))),
34-
(0.25, Lch::from(Rgb::rgb(0.1, 0.1, 1.0))),
35-
(1.0, Lch::from(Rgb::rgb(0.1, 1.0, 0.1)))
33+
(0.0, Lch::from(Rgb::new(1.0, 0.1, 0.1))),
34+
(0.25, Lch::from(Rgb::new(0.1, 0.1, 1.0))),
35+
(1.0, Lch::from(Rgb::new(0.1, 1.0, 0.1)))
3636
]);
3737

3838
let mut image = RgbImage::new(256, 128);

examples/readme_examples.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ extern crate num;
55
use image::{RgbImage, GenericImage};
66
use num::traits::Float;
77

8-
use palette::{Rgb, Gradient, Mix};
8+
use palette::{Rgba, Gradient, Mix};
99
use palette::pixel::Srgb;
1010

1111
mod color_spaces {
@@ -48,13 +48,13 @@ mod gradients {
4848

4949
pub fn run() {
5050
let grad1 = Gradient::new(vec![
51-
Rgb::rgb(1.0, 0.1, 0.1),
52-
Rgb::rgb(0.1, 1.0, 1.0)
51+
Rgb::new(1.0, 0.1, 0.1),
52+
Rgb::new(0.1, 1.0, 1.0)
5353
]);
5454

5555
let grad2 = Gradient::new(vec![
56-
Hsv::from(Rgb::rgb(1.0, 0.1, 0.1)),
57-
Hsv::from(Rgb::rgb(0.1, 1.0, 1.0))
56+
Hsv::from(Rgb::new(1.0, 0.1, 0.1)),
57+
Hsv::from(Rgb::new(0.1, 1.0, 1.0))
5858
]);
5959

6060
display_gradients("examples/readme_gradients.png", grad1, grad2);
@@ -76,8 +76,8 @@ fn display_colors(filename: &str, colors: &[[u8; 3]]) {
7676
}
7777

7878
fn display_gradients<T: Float, A: Mix<Scalar=T> + Clone, B: Mix<Scalar=T> + Clone>(filename: &str, grad1: Gradient<A>, grad2: Gradient<B>) where
79-
Rgb<T>: From<A>,
80-
Rgb<T>: From<B>,
79+
Rgba<T>: From<A>,
80+
Rgba<T>: From<B>,
8181
{
8282
let mut image = RgbImage::new(256, 64);
8383

examples/shade.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use image::{RgbImage, GenericImage};
88

99
fn main() {
1010
//The same color in linear RGB, CIE L*a*b*, and HSV
11-
let rgb = Rgb::rgb(0.5, 0.0, 0.0);
11+
let rgb = Rgb::new(0.5, 0.0, 0.0);
1212
let lab = Lab::from(rgb);
1313
let hsv = Hsv::from(rgb);
1414

src/alpha.rs

+193
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
use std::ops::{Deref, DerefMut, Add, Sub, Mul, Div};
2+
3+
use num::Float;
4+
5+
use {Mix, Shade, GetHue, Hue, Saturate};
6+
7+
///An alpha component wrapper for colors.
8+
#[derive(Clone, Copy, Debug, PartialEq)]
9+
pub struct Alpha<C, T: Float> {
10+
///The color.
11+
pub color: C,
12+
13+
///The transparency component. 0.0 is fully transparent and 1.0 is fully
14+
///opaque.
15+
pub alpha: T,
16+
}
17+
18+
impl<C, T: Float> Deref for Alpha<C, T> {
19+
type Target = C;
20+
21+
fn deref(&self) -> &C {
22+
&self.color
23+
}
24+
}
25+
26+
impl<C, T: Float> DerefMut for Alpha<C, T> {
27+
fn deref_mut(&mut self) -> &mut C {
28+
&mut self.color
29+
}
30+
}
31+
32+
impl<C: Mix> Mix for Alpha<C, C::Scalar> {
33+
type Scalar = C::Scalar;
34+
35+
fn mix(&self, other: &Alpha<C, C::Scalar>, factor: C::Scalar) -> Alpha<C, C::Scalar> {
36+
Alpha {
37+
color: self.color.mix(&other.color, factor),
38+
alpha: self.alpha + factor * (other.alpha - self.alpha),
39+
}
40+
}
41+
}
42+
43+
impl<C: Shade> Shade for Alpha<C, C::Scalar> {
44+
type Scalar = C::Scalar;
45+
46+
fn lighten(&self, amount: C::Scalar) -> Alpha<C, C::Scalar> {
47+
Alpha {
48+
color: self.color.lighten(amount),
49+
alpha: self.alpha,
50+
}
51+
}
52+
}
53+
54+
impl<C: GetHue, T: Float> GetHue for Alpha<C, T> {
55+
type Hue = C::Hue;
56+
57+
fn get_hue(&self) -> Option<C::Hue> {
58+
self.color.get_hue()
59+
}
60+
}
61+
62+
impl<C: Hue, T: Float> Hue for Alpha<C, T> {
63+
fn with_hue(&self, hue: C::Hue) -> Alpha<C, T> {
64+
Alpha {
65+
color: self.color.with_hue(hue),
66+
alpha: self.alpha,
67+
}
68+
}
69+
70+
fn shift_hue(&self, amount: C::Hue) -> Alpha<C, T> {
71+
Alpha {
72+
color: self.color.shift_hue(amount),
73+
alpha: self.alpha,
74+
}
75+
}
76+
}
77+
78+
impl<C: Saturate> Saturate for Alpha<C, C::Scalar> {
79+
type Scalar = C::Scalar;
80+
81+
fn saturate(&self, factor: C::Scalar) -> Alpha<C, C::Scalar> {
82+
Alpha {
83+
color: self.color.saturate(factor),
84+
alpha: self.alpha,
85+
}
86+
}
87+
}
88+
89+
impl<C: Default, T: Float> Default for Alpha<C, T> {
90+
fn default() -> Alpha<C, T> {
91+
Alpha {
92+
color: C::default(),
93+
alpha: T::one(),
94+
}
95+
}
96+
}
97+
98+
impl<C: Add, T: Float> Add for Alpha<C, T> {
99+
type Output = Alpha<C::Output, T>;
100+
101+
fn add(self, other: Alpha<C, T>) -> Alpha<C::Output, T> {
102+
Alpha {
103+
color: self.color + other.color,
104+
alpha: self.alpha + other.alpha,
105+
}
106+
}
107+
}
108+
109+
impl<T: Float + Clone, C: Add<T>> Add<T> for Alpha<C, T> {
110+
type Output = Alpha<C::Output, T>;
111+
112+
fn add(self, c: T) -> Alpha<C::Output, T> {
113+
Alpha {
114+
color: self.color + c.clone(),
115+
alpha: self.alpha + c,
116+
}
117+
}
118+
}
119+
120+
impl<C: Sub, T: Float> Sub for Alpha<C, T> {
121+
type Output = Alpha<C::Output, T>;
122+
123+
fn sub(self, other: Alpha<C, T>) -> Alpha<C::Output, T> {
124+
Alpha {
125+
color: self.color - other.color,
126+
alpha: self.alpha - other.alpha,
127+
}
128+
}
129+
}
130+
131+
impl<T: Float + Clone, C: Sub<T>> Sub<T> for Alpha<C, T> {
132+
type Output = Alpha<C::Output, T>;
133+
134+
fn sub(self, c: T) -> Alpha<C::Output, T> {
135+
Alpha {
136+
color: self.color - c.clone(),
137+
alpha: self.alpha - c,
138+
}
139+
}
140+
}
141+
142+
impl<C: Mul, T: Float> Mul for Alpha<C, T> {
143+
type Output = Alpha<C::Output, T>;
144+
145+
fn mul(self, other: Alpha<C, T>) -> Alpha<C::Output, T> {
146+
Alpha {
147+
color: self.color * other.color,
148+
alpha: self.alpha * other.alpha,
149+
}
150+
}
151+
}
152+
153+
impl<T: Float + Clone, C: Mul<T>> Mul<T> for Alpha<C, T> {
154+
type Output = Alpha<C::Output, T>;
155+
156+
fn mul(self, c: T) -> Alpha<C::Output, T> {
157+
Alpha {
158+
color: self.color * c.clone(),
159+
alpha: self.alpha * c,
160+
}
161+
}
162+
}
163+
164+
impl<C: Div, T: Float> Div for Alpha<C, T> {
165+
type Output = Alpha<C::Output, T>;
166+
167+
fn div(self, other: Alpha<C, T>) -> Alpha<C::Output, T> {
168+
Alpha {
169+
color: self.color / other.color,
170+
alpha: self.alpha / other.alpha,
171+
}
172+
}
173+
}
174+
175+
impl<T: Float + Clone, C: Div<T>> Div<T> for Alpha<C, T> {
176+
type Output = Alpha<C::Output, T>;
177+
178+
fn div(self, c: T) -> Alpha<C::Output, T> {
179+
Alpha {
180+
color: self.color / c.clone(),
181+
alpha: self.alpha / c,
182+
}
183+
}
184+
}
185+
186+
impl<C, T: Float> From<C> for Alpha<C, T> {
187+
fn from(color: C) -> Alpha<C, T> {
188+
Alpha {
189+
color: color,
190+
alpha: T::one(),
191+
}
192+
}
193+
}

src/gradient.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ mod test {
314314

315315
#[test]
316316
fn simple_slice() {
317-
let g1 = Gradient::new(vec![Rgb::rgb(1.0, 0.0, 0.0), Rgb::rgb(0.0, 0.0, 1.0)]);
317+
let g1 = Gradient::new(vec![Rgb::new(1.0, 0.0, 0.0), Rgb::new(0.0, 0.0, 1.0)]);
318318
let g2 = g1.slice(..0.5);
319319

320320
let v1: Vec<_> = g1.take(10).take(5).collect();

0 commit comments

Comments
 (0)