Skip to content

Commit 420457c

Browse files
bors[bot]Veykril
andcommittedMay 28, 2018
Merge #104
104: Update image and approx crate dependency r=Ogeon a=Veykril Closes #101 and closes #100. I accidentally put both pull requests together. Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
2 parents 8f9634c + e429094 commit 420457c

16 files changed

+544
-178
lines changed
 

‎palette/Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ strict = []
2323
[dependencies]
2424
palette_derive = {version = "0.4.0", path = "../palette_derive"}
2525
num-traits = "0.2"
26-
approx = "0.1"
26+
approx = "0.2"
2727

2828
[dependencies.phf]
2929
version = "0.7"
@@ -36,7 +36,7 @@ features = ["serde_derive"]
3636
optional = true
3737

3838
[dev-dependencies]
39-
image = "0.18"
39+
image = "0.19"
4040
clap = "2"
4141
csv = "1.0.0-beta.3"
4242
serde = "1"

‎palette/examples/color_scheme.rs

+15-9
Original file line numberDiff line numberDiff line change
@@ -190,15 +190,21 @@ fn blit_shades<I: GenericImage<Pixel = image::Rgb<u8>> + 'static>(
190190
.into_format()
191191
.into_raw();
192192

193-
for (x, y, pixel) in canvas.pixels_mut() {
194-
if y < height / 2 {
195-
pixel.data = primary;
196-
} else if x < width / 3 {
197-
pixel.data = light;
198-
} else if x < (width / 3) * 2 {
199-
pixel.data = dark1;
200-
} else {
201-
pixel.data = dark2;
193+
194+
for x in 0..width {
195+
for y in 0..height {
196+
canvas.put_pixel(x, y, image::Rgb {
197+
data:
198+
if y < height / 2 {
199+
primary
200+
} else if x < width / 3 {
201+
light
202+
} else if x < (width / 3) * 2 {
203+
dark1
204+
} else {
205+
dark2
206+
}
207+
});
202208
}
203209
}
204210
}

‎palette/examples/gradient.rs

+41-8
Original file line numberDiff line numberDiff line change
@@ -49,20 +49,53 @@ fn main() {
4949
let c3 = Srgb::from_linear(c3.into()).into_format().into_raw();
5050
let c4 = Srgb::from_linear(c4.into()).into_format().into_raw();
5151

52-
for (_, _, pixel) in image.sub_image(i as u32, 0, 1, 31).pixels_mut() {
53-
pixel.data = c1
52+
53+
{
54+
let mut sub_image = image.sub_image(i as u32, 0, 1, 31);
55+
let (width, height) = sub_image.dimensions();
56+
for x in 0..width {
57+
for y in 0..height {
58+
sub_image.put_pixel(x, y, image::Rgb {
59+
data: c1
60+
});
61+
}
62+
}
5463
}
5564

56-
for (_, _, pixel) in image.sub_image(i as u32, 32, 1, 31).pixels_mut() {
57-
pixel.data = c2;
65+
{
66+
let mut sub_image = image.sub_image(i as u32, 32, 1, 31);
67+
let (width, height) = sub_image.dimensions();
68+
for x in 0..width {
69+
for y in 0..height {
70+
sub_image.put_pixel(x, y, image::Rgb {
71+
data: c2
72+
});
73+
}
74+
}
5875
}
5976

60-
for (_, _, pixel) in image.sub_image(i as u32, 65, 1, 31).pixels_mut() {
61-
pixel.data = c3;
77+
{
78+
let mut sub_image = image.sub_image(i as u32, 65, 1, 31);
79+
let (width, height) = sub_image.dimensions();
80+
for x in 0..width {
81+
for y in 0..height {
82+
sub_image.put_pixel(x, y, image::Rgb {
83+
data: c3
84+
});
85+
}
86+
}
6287
}
6388

64-
for (_, _, pixel) in image.sub_image(i as u32, 97, 1, 31).pixels_mut() {
65-
pixel.data = c4;
89+
{
90+
let mut sub_image = image.sub_image(i as u32, 97, 1, 31);
91+
let (width, height) = sub_image.dimensions();
92+
for x in 0..width {
93+
for y in 0..height {
94+
sub_image.put_pixel(x, y, image::Rgb {
95+
data: c4
96+
});
97+
}
98+
}
6699
}
67100
}
68101

‎palette/examples/readme_examples.rs

+30-11
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,12 @@ mod gradients {
6666
fn display_colors(filename: &str, colors: &[Srgb<u8>]) {
6767
let mut image = RgbImage::new(colors.len() as u32 * 64, 64);
6868
for (i, &color) in colors.iter().enumerate() {
69-
for (_, _, pixel) in image.sub_image(i as u32 * 64, 0, 64, 64).pixels_mut() {
70-
pixel.data = *color.as_raw();
69+
let mut sub_image = image.sub_image(i as u32 * 64, 0, 64, 64);
70+
let (width, height) = sub_image.dimensions();
71+
for x in 0..width {
72+
for y in 0..height {
73+
sub_image.put_pixel(x, y, image::Rgb { data: *color.as_raw() });
74+
}
7175
}
7276
}
7377

@@ -86,17 +90,32 @@ fn display_gradients<A: Mix<Scalar = f32> + Clone, B: Mix<Scalar = f32> + Clone>
8690
LinSrgb: From<B>,
8791
{
8892
let mut image = RgbImage::new(256, 64);
89-
90-
for (x, _, pixel) in image.sub_image(0, 0, 256, 32).pixels_mut() {
91-
pixel.data = Srgb::from_linear(grad1.get(x as f32 / 255.0).into())
92-
.into_format()
93-
.into_raw();
93+
{
94+
let mut sub_image = image.sub_image(0, 0, 256, 32);
95+
let (width, height) = sub_image.dimensions();
96+
for x in 0..width {
97+
for y in 0..height {
98+
sub_image.put_pixel(x, y, image::Rgb {
99+
data: Srgb::from_linear(grad1.get(x as f32 / 255.0).into())
100+
.into_format()
101+
.into_raw()
102+
});
103+
}
104+
}
94105
}
95106

96-
for (x, _, pixel) in image.sub_image(0, 32, 256, 32).pixels_mut() {
97-
pixel.data = Srgb::from_linear(grad2.get(x as f32 / 255.0).into())
98-
.into_format()
99-
.into_raw();
107+
{
108+
let mut sub_image = image.sub_image(0, 32, 256, 32);
109+
let (width, height) = sub_image.dimensions();
110+
for x in 0..width {
111+
for y in 0..height {
112+
sub_image.put_pixel(x, y, image::Rgb {
113+
data: Srgb::from_linear(grad2.get(x as f32 / 255.0).into())
114+
.into_format()
115+
.into_raw()
116+
});
117+
}
118+
}
100119
}
101120

102121
match image.save(filename) {

‎palette/examples/saturate.rs

+31-18
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,40 @@ fn main() {
1515

1616
//Increase the saturation by 80% (!) as HSL in the left half, and as LCh
1717
//in the right half. Notice the strong yellow tone in the HSL part.
18-
for (_, _, pixel) in image.sub_image(0, 0, width / 2, height).pixels_mut() {
19-
let color: Hsl = Srgb::from_raw(&pixel.data)
20-
.into_format()
21-
.into_linear()
22-
.into();
23-
24-
let saturated = color.saturate(0.8);
25-
pixel.data = Srgb::from_linear(saturated.into()).into_format().into_raw();
18+
{
19+
let mut sub_image = image.sub_image(0, 0, width / 2, height);
20+
let (width, height) = sub_image.dimensions();
21+
for x in 0..width {
22+
for y in 0..height {
23+
let color: Hsl = Srgb::from_raw(&sub_image.get_pixel(x, y).data)
24+
.into_format()
25+
.into_linear()
26+
.into();
27+
28+
let saturated = color.saturate(0.8);
29+
sub_image.put_pixel(x, y, image::Rgb {
30+
data: Srgb::from_linear(saturated.into()).into_format().into_raw()
31+
});
32+
}
33+
}
2634
}
2735

28-
for (_, _, pixel) in image
29-
.sub_image(width / 2, 0, width / 2, height)
30-
.pixels_mut()
3136
{
32-
let color: Lch = Srgb::from_raw(&pixel.data)
33-
.into_format()
34-
.into_linear()
35-
.into();
36-
37-
let saturated = color.saturate(0.8);
38-
pixel.data = Srgb::from_linear(saturated.into()).into_format().into_raw();
37+
let mut sub_image = image.sub_image(width / 2, 0, width / 2, height);
38+
let (width, height) = sub_image.dimensions();
39+
for x in 0..width {
40+
for y in 0..height {
41+
let color: Lch = Srgb::from_raw(&sub_image.get_pixel(x, y).data)
42+
.into_format()
43+
.into_linear()
44+
.into();
45+
46+
let saturated = color.saturate(0.8);
47+
sub_image.put_pixel(x, y, image::Rgb {
48+
data: Srgb::from_linear(saturated.into()).into_format().into_raw()
49+
});
50+
}
51+
}
3952
}
4053

4154
match image.save("examples/saturate.png") {

‎palette/examples/shade.rs

+48-12
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,24 @@ fn main() {
2121
.into_format()
2222
.into_raw();
2323

24-
for (_, _, pixel) in image.sub_image(i as u32 * 20, 0, 20, 31).pixels_mut() {
25-
pixel.data = rgb1;
24+
{
25+
let mut sub_image = image.sub_image(i as u32 * 20, 0, 20, 31);
26+
let (width, height) = sub_image.dimensions();
27+
for x in 0..width {
28+
for y in 0..height {
29+
sub_image.put_pixel(x, y, image::Rgb { data: rgb1 });
30+
}
31+
}
2632
}
2733

28-
for (_, _, pixel) in image.sub_image(i as u32 * 20, 32, 20, 31).pixels_mut() {
29-
pixel.data = rgb2;
34+
{
35+
let mut sub_image = image.sub_image(i as u32 * 20, 32, 20, 31);
36+
let (width, height) = sub_image.dimensions();
37+
for x in 0..width {
38+
for y in 0..height {
39+
sub_image.put_pixel(x, y, image::Rgb { data: rgb2 });
40+
}
41+
}
3042
}
3143

3244
let lab1 = Srgb::from_linear(lab.darken(0.05 * i as f32).into())
@@ -36,12 +48,24 @@ fn main() {
3648
.into_format()
3749
.into_raw();
3850

39-
for (_, _, pixel) in image.sub_image(i as u32 * 20, 65, 20, 31).pixels_mut() {
40-
pixel.data = lab1;
51+
{
52+
let mut sub_image = image.sub_image(i as u32 * 20, 65, 20, 31);
53+
let (width, height) = sub_image.dimensions();
54+
for x in 0..width {
55+
for y in 0..height {
56+
sub_image.put_pixel(x, y, image::Rgb { data: lab1 });
57+
}
58+
}
4159
}
4260

43-
for (_, _, pixel) in image.sub_image(i as u32 * 20, 97, 20, 31).pixels_mut() {
44-
pixel.data = lab2;
61+
{
62+
let mut sub_image = image.sub_image(i as u32 * 20, 97, 20, 31);
63+
let (width, height) = sub_image.dimensions();
64+
for x in 0..width {
65+
for y in 0..height {
66+
sub_image.put_pixel(x, y, image::Rgb { data: lab2 });
67+
}
68+
}
4569
}
4670

4771
let hsv1 = Srgb::from_linear(hsv.darken(0.05 * i as f32).into())
@@ -51,12 +75,24 @@ fn main() {
5175
.into_format()
5276
.into_raw();
5377

54-
for (_, _, pixel) in image.sub_image(i as u32 * 20, 130, 20, 31).pixels_mut() {
55-
pixel.data = hsv1;
78+
{
79+
let mut sub_image = image.sub_image(i as u32 * 20, 130, 20, 31);
80+
let (width, height) = sub_image.dimensions();
81+
for x in 0..width {
82+
for y in 0..height {
83+
sub_image.put_pixel(x, y, image::Rgb { data: hsv1 });
84+
}
85+
}
5686
}
5787

58-
for (_, _, pixel) in image.sub_image(i as u32 * 20, 162, 20, 31).pixels_mut() {
59-
pixel.data = hsv2;
88+
{
89+
let mut sub_image = image.sub_image(i as u32 * 20, 162, 20, 31);
90+
let (width, height) = sub_image.dimensions();
91+
for x in 0..width {
92+
for y in 0..height {
93+
sub_image.put_pixel(x, y, image::Rgb { data: hsv2 });
94+
}
95+
}
6096
}
6197
}
6298

‎palette/src/alpha.rs

+27-8
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::fmt;
33

44
use num_traits::Float;
55

6-
use approx::ApproxEq;
6+
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
77

88
use {clamp, Blend, Component, ComponentWise, GetHue, Hue, Limited, Mix, Pixel, Saturate, Shade};
99
use blend::PreAlpha;
@@ -159,10 +159,10 @@ impl<C: Default, T: Component> Default for Alpha<C, T> {
159159
}
160160
}
161161

162-
impl<C, T> ApproxEq for Alpha<C, T>
162+
impl<C, T> AbsDiffEq for Alpha<C, T>
163163
where
164-
C: ApproxEq<Epsilon = T::Epsilon>,
165-
T: ApproxEq,
164+
C: AbsDiffEq<Epsilon = T::Epsilon>,
165+
T: AbsDiffEq,
166166
T::Epsilon: Clone,
167167
{
168168
type Epsilon = T::Epsilon;
@@ -171,12 +171,20 @@ where
171171
T::default_epsilon()
172172
}
173173

174-
fn default_max_relative() -> Self::Epsilon {
175-
T::default_max_relative()
174+
fn abs_diff_eq(&self, other: &Self, epsilon: T::Epsilon) -> bool {
175+
self.color.abs_diff_eq(&other.color, epsilon.clone())
176+
&& self.alpha.abs_diff_eq(&other.alpha, epsilon)
176177
}
178+
}
177179

178-
fn default_max_ulps() -> u32 {
179-
T::default_max_ulps()
180+
impl<C, T> RelativeEq for Alpha<C, T>
181+
where
182+
C: RelativeEq<Epsilon = T::Epsilon>,
183+
T: RelativeEq,
184+
T::Epsilon: Clone,
185+
{
186+
fn default_max_relative() -> Self::Epsilon {
187+
T::default_max_relative()
180188
}
181189

182190
fn relative_eq(
@@ -189,6 +197,17 @@ where
189197
.relative_eq(&other.color, epsilon.clone(), max_relative.clone())
190198
&& self.alpha.relative_eq(&other.alpha, epsilon, max_relative)
191199
}
200+
}
201+
202+
impl<C, T> UlpsEq for Alpha<C, T>
203+
where
204+
C: UlpsEq<Epsilon = T::Epsilon>,
205+
T: UlpsEq,
206+
T::Epsilon: Clone,
207+
{
208+
fn default_max_ulps() -> u32 {
209+
T::default_max_ulps()
210+
}
192211

193212
fn ulps_eq(&self, other: &Alpha<C, T>, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
194213
self.color.ulps_eq(&other.color, epsilon.clone(), max_ulps)

‎palette/src/blend/pre_alpha.rs

+27-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::ops::{Add, Deref, DerefMut, Div, Mul, Sub};
2-
use approx::ApproxEq;
2+
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
33
use num_traits::Float;
44

55
use {clamp, Alpha, Blend, ComponentWise, Mix, Pixel};
@@ -139,10 +139,10 @@ impl<C: Default, T: Float> Default for PreAlpha<C, T> {
139139
}
140140
}
141141

142-
impl<C, T> ApproxEq for PreAlpha<C, T>
142+
impl<C, T> AbsDiffEq for PreAlpha<C, T>
143143
where
144-
C: ApproxEq<Epsilon = T::Epsilon>,
145-
T: ApproxEq + Float,
144+
C: AbsDiffEq <Epsilon = T::Epsilon>,
145+
T: AbsDiffEq + Float,
146146
T::Epsilon: Copy,
147147
{
148148
type Epsilon = T::Epsilon;
@@ -151,12 +151,20 @@ where
151151
T::default_epsilon()
152152
}
153153

154-
fn default_max_relative() -> Self::Epsilon {
155-
T::default_max_relative()
154+
fn abs_diff_eq(&self, other: &PreAlpha<C, T>, epsilon: Self::Epsilon) -> bool {
155+
self.color.abs_diff_eq(&other.color, epsilon)
156+
&& self.alpha.abs_diff_eq(&other.alpha, epsilon)
156157
}
158+
}
157159

158-
fn default_max_ulps() -> u32 {
159-
T::default_max_ulps()
160+
impl<C, T> RelativeEq for PreAlpha<C, T>
161+
where
162+
C: RelativeEq <Epsilon = T::Epsilon>,
163+
T: RelativeEq + Float,
164+
T::Epsilon: Copy,
165+
{
166+
fn default_max_relative() -> Self::Epsilon {
167+
T::default_max_relative()
160168
}
161169

162170
fn relative_eq(
@@ -168,6 +176,17 @@ where
168176
self.color.relative_eq(&other.color, epsilon, max_relative)
169177
&& self.alpha.relative_eq(&other.alpha, epsilon, max_relative)
170178
}
179+
}
180+
181+
impl<C, T> UlpsEq for PreAlpha<C, T>
182+
where
183+
C: UlpsEq <Epsilon = T::Epsilon>,
184+
T: UlpsEq + Float,
185+
T::Epsilon: Copy,
186+
{
187+
fn default_max_ulps() -> u32 {
188+
T::default_max_ulps()
189+
}
171190

172191
fn ulps_eq(&self, other: &PreAlpha<C, T>, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
173192
self.color.ulps_eq(&other.color, epsilon, max_ulps)

‎palette/src/equality.rs

+70-28
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,62 @@
11
use num_traits::Float;
2-
use approx::ApproxEq;
2+
3+
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
34

45
use {cast, Component, Lab, LabHue, Lch, RgbHue, Xyz, Yxy};
56
use white_point::WhitePoint;
67

78
macro_rules! impl_eq {
89
( $self_ty: ident , [$($element: ident),+]) => {
9-
impl<Wp, T> ApproxEq for $self_ty<Wp, T>
10-
where T: Component + Float + ApproxEq,
10+
impl<Wp, T> AbsDiffEq for $self_ty<Wp, T>
11+
where T: Component + Float + AbsDiffEq,
1112
T::Epsilon: Copy + Float,
12-
Wp: WhitePoint
13+
Wp: WhitePoint + PartialEq
1314
{
14-
type Epsilon = <T as ApproxEq>::Epsilon;
15+
type Epsilon = T::Epsilon;
1516

1617
fn default_epsilon() -> Self::Epsilon {
1718
T::default_epsilon()
1819
}
19-
fn default_max_relative() -> Self::Epsilon {
20-
T::default_max_relative()
20+
21+
fn abs_diff_eq(&self, other: &Self, epsilon: T::Epsilon) -> bool {
22+
$( self.$element.abs_diff_eq(&other.$element, epsilon) )&&+
2123
}
22-
fn default_max_ulps() -> u32 {
23-
T::default_max_ulps()
24+
fn abs_diff_ne(&self, other: &Self, epsilon: T::Epsilon) -> bool {
25+
$( self.$element.abs_diff_ne(&other.$element, epsilon) )||+
2426
}
25-
fn relative_eq(&self, other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon) -> bool {
27+
}
28+
29+
impl<Wp, T> RelativeEq for $self_ty<Wp, T>
30+
where T: Component + Float + RelativeEq,
31+
T::Epsilon: Copy + Float,
32+
Wp: WhitePoint + PartialEq
33+
{
34+
fn default_max_relative() -> T::Epsilon {
35+
T::default_max_relative()
36+
}
37+
38+
fn relative_eq(&self, other: &Self, epsilon: T::Epsilon, max_relative: T::Epsilon) -> bool {
2639
$( self.$element.relative_eq(&other.$element, epsilon, max_relative) )&&+
2740
}
28-
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool{
29-
$( self.$element.ulps_eq(&other.$element, epsilon, max_ulps) )&&+
41+
fn relative_ne(&self, other: &Self, epsilon: T::Epsilon, max_relative: T::Epsilon) -> bool {
42+
$( self.$element.relative_ne(&other.$element, epsilon, max_relative) )||+
3043
}
44+
}
3145

32-
fn relative_ne(&self, other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon) -> bool {
33-
$( self.$element.relative_ne(&other.$element, epsilon, max_relative) )&&+
46+
impl<Wp, T> UlpsEq for $self_ty<Wp, T>
47+
where T: Component + Float + UlpsEq,
48+
T::Epsilon: Copy + Float,
49+
Wp: WhitePoint + PartialEq
50+
{
51+
fn default_max_ulps() -> u32 {
52+
T::default_max_ulps()
3453
}
35-
fn ulps_ne(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
36-
$( self.$element.ulps_ne(&other.$element, epsilon, max_ulps) )&&+
54+
55+
fn ulps_eq(&self, other: &Self, epsilon: T::Epsilon, max_ulps: u32) -> bool {
56+
$( self.$element.ulps_eq(&other.$element, epsilon, max_ulps) )&&+
57+
}
58+
fn ulps_ne(&self, other: &Self, epsilon: T::Epsilon, max_ulps: u32) -> bool {
59+
$( self.$element.ulps_ne(&other.$element, epsilon, max_ulps) )||+
3760
}
3861
}
3962
}
@@ -54,39 +77,58 @@ impl_eq!(Lch, [l, chroma, hue]);
5477
// ulps. Because of this we loose some precision for values close to 0.0.
5578
macro_rules! impl_eq_hue {
5679
( $self_ty: ident ) => {
57-
impl<T: Float + ApproxEq> ApproxEq for $self_ty<T>
58-
where <T as ApproxEq>::Epsilon: Float
80+
impl<T: Float + AbsDiffEq> AbsDiffEq for $self_ty<T>
81+
where T::Epsilon: Float
5982
{
60-
type Epsilon = <T as ApproxEq>::Epsilon;
83+
type Epsilon = T::Epsilon;
6184

6285
fn default_epsilon() -> Self::Epsilon {
6386
T::default_epsilon() * cast(180.0)
6487
}
88+
89+
fn abs_diff_eq(&self, other: &Self, epsilon: T::Epsilon) -> bool {
90+
let diff: T = (*self - *other).to_degrees();
91+
T::abs_diff_eq(&diff, &T::zero(), epsilon)
92+
}
93+
fn abs_diff_ne(&self, other: &Self, epsilon: T::Epsilon) -> bool {
94+
let diff: T = (*self - *other).to_degrees();
95+
T::abs_diff_ne(&diff, &T::zero(), epsilon)
96+
}
97+
}
98+
99+
impl<T: Float + RelativeEq> RelativeEq for $self_ty<T>
100+
where T::Epsilon: Float
101+
{
65102
fn default_max_relative() -> Self::Epsilon {
66103
T::default_max_relative() * cast(180.0)
67104
}
68-
fn default_max_ulps() -> u32 {
69-
T::default_max_ulps() * 180
70-
}
71-
fn relative_eq(&self, other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon) -> bool {
105+
106+
fn relative_eq(&self, other: &Self, epsilon: T::Epsilon, max_relative: T::Epsilon) -> bool {
72107
let diff: T = (*self - *other).to_degrees();
73108
T::relative_eq(&diff, &T::zero(), epsilon, max_relative)
74109
}
75-
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool{
110+
fn relative_ne(&self, other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon) -> bool {
76111
let diff: T = (*self - *other).to_degrees();
77-
T::ulps_eq(&diff, &T::zero(), epsilon, max_ulps)
112+
T::relative_ne(&diff, &T::zero(), epsilon, max_relative)
78113
}
114+
}
79115

80-
fn relative_ne(&self, other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon) -> bool {
116+
impl<T: Float + UlpsEq> UlpsEq for $self_ty<T>
117+
where T::Epsilon: Float
118+
{
119+
fn default_max_ulps() -> u32 {
120+
T::default_max_ulps() * 180
121+
}
122+
123+
fn ulps_eq(&self, other: &Self, epsilon: T::Epsilon, max_ulps: u32) -> bool {
81124
let diff: T = (*self - *other).to_degrees();
82-
T::relative_ne(&diff, &T::zero(), epsilon, max_relative)
125+
T::ulps_eq(&diff, &T::zero(), epsilon, max_ulps)
83126
}
84127
fn ulps_ne(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
85128
let diff: T = (*self - *other).to_degrees();
86129
T::ulps_ne(&diff, &T::zero(), epsilon, max_ulps)
87130
}
88131
}
89-
90132
}
91133
}
92134

‎palette/src/gradient.rs

+35-7
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use num_traits::{Float, One, Zero};
44
use std::cmp::max;
5-
use approx::ApproxEq;
5+
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
66

77
use cast;
88

@@ -287,9 +287,9 @@ impl<T: Float> From<::std::ops::RangeFull> for Range<T> {
287287
}
288288
}
289289

290-
impl<T> ApproxEq for Range<T>
290+
impl<T> AbsDiffEq for Range<T>
291291
where
292-
T: ApproxEq + Float,
292+
T: AbsDiffEq + Float,
293293
T::Epsilon: Copy,
294294
{
295295
type Epsilon = T::Epsilon;
@@ -298,12 +298,30 @@ where
298298
T::default_epsilon()
299299
}
300300

301-
fn default_max_relative() -> Self::Epsilon {
302-
T::default_max_relative()
301+
fn abs_diff_eq(&self, other: &Self, epsilon: T::Epsilon) -> bool {
302+
let from = match (self.from, other.from) {
303+
(Some(s), Some(o)) => s.abs_diff_eq(&o, epsilon),
304+
(None, None) => true,
305+
_ => false,
306+
};
307+
308+
let to = match (self.to, other.to) {
309+
(Some(s), Some(o)) => s.abs_diff_eq(&o, epsilon),
310+
(None, None) => true,
311+
_ => false,
312+
};
313+
314+
from && to
303315
}
316+
}
304317

305-
fn default_max_ulps() -> u32 {
306-
T::default_max_ulps()
318+
impl<T> RelativeEq for Range<T>
319+
where
320+
T: RelativeEq + Float,
321+
T::Epsilon: Copy,
322+
{
323+
fn default_max_relative() -> Self::Epsilon {
324+
T::default_max_relative()
307325
}
308326

309327
fn relative_eq(
@@ -326,6 +344,16 @@ where
326344

327345
from && to
328346
}
347+
}
348+
349+
impl<T> UlpsEq for Range<T>
350+
where
351+
T: UlpsEq + Float,
352+
T::Epsilon: Copy,
353+
{
354+
fn default_max_ulps() -> u32 {
355+
T::default_max_ulps()
356+
}
329357

330358
fn ulps_eq(&self, other: &Range<T>, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
331359
let from = match (self.from, other.from) {

‎palette/src/hsl.rs

+35-12
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use approx::ApproxEq;
1+
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
22
use num_traits::Float;
33

44
use std::any::TypeId;
@@ -518,23 +518,35 @@ where
518518
}
519519
}
520520

521-
impl<S, T> ApproxEq for Hsl<S, T>
521+
impl<S, T> AbsDiffEq for Hsl<S, T>
522522
where
523-
T: Component + Float + ApproxEq,
523+
T: Component + Float + AbsDiffEq,
524524
T::Epsilon: Copy + Float,
525-
S: RgbSpace,
525+
S: RgbSpace + PartialEq,
526526
{
527-
type Epsilon = <T as ApproxEq>::Epsilon;
527+
type Epsilon = T::Epsilon;
528528

529529
fn default_epsilon() -> Self::Epsilon {
530530
T::default_epsilon()
531531
}
532+
533+
fn abs_diff_eq(&self, other: &Self, epsilon: T::Epsilon) -> bool {
534+
self.hue.abs_diff_eq(&other.hue, epsilon) &&
535+
self.saturation.abs_diff_eq(&other.saturation, epsilon) &&
536+
self.lightness.abs_diff_eq(&other.lightness, epsilon)
537+
}
538+
}
539+
540+
impl<S, T> RelativeEq for Hsl<S, T>
541+
where
542+
T: Component + Float + RelativeEq,
543+
T::Epsilon: Copy + Float,
544+
S: RgbSpace + PartialEq,
545+
{
532546
fn default_max_relative() -> Self::Epsilon {
533547
T::default_max_relative()
534548
}
535-
fn default_max_ulps() -> u32 {
536-
T::default_max_ulps()
537-
}
549+
538550
#[cfg_attr(rustfmt, rustfmt_skip)]
539551
fn relative_eq(
540552
&self,
@@ -543,15 +555,26 @@ where
543555
max_relative: Self::Epsilon,
544556
) -> bool {
545557
self.hue.relative_eq(&other.hue, epsilon, max_relative) &&
546-
self.saturation.relative_eq(&other.saturation, epsilon, max_relative) &&
547-
self.lightness.relative_eq(&other.lightness, epsilon, max_relative)
558+
self.saturation.relative_eq(&other.saturation, epsilon, max_relative) &&
559+
self.lightness.relative_eq(&other.lightness, epsilon, max_relative)
560+
}
561+
}
562+
563+
impl<S, T> UlpsEq for Hsl<S, T>
564+
where
565+
T: Component + Float + UlpsEq,
566+
T::Epsilon: Copy + Float,
567+
S: RgbSpace + PartialEq,
568+
{
569+
fn default_max_ulps() -> u32 {
570+
T::default_max_ulps()
548571
}
549572

550573
#[cfg_attr(rustfmt, rustfmt_skip)]
551574
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
552575
self.hue.ulps_eq(&other.hue, epsilon, max_ulps) &&
553-
self.saturation.ulps_eq(&other.saturation, epsilon, max_ulps) &&
554-
self.lightness.ulps_eq(&other.lightness, epsilon, max_ulps)
576+
self.saturation.ulps_eq(&other.saturation, epsilon, max_ulps) &&
577+
self.lightness.ulps_eq(&other.lightness, epsilon, max_ulps)
555578
}
556579
}
557580

‎palette/src/hsv.rs

+35-12
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use approx::ApproxEq;
1+
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
22
use num_traits::Float;
33

44
use std::any::TypeId;
@@ -529,23 +529,35 @@ where
529529
}
530530
}
531531

532-
impl<S, T> ApproxEq for Hsv<S, T>
532+
impl<S, T> AbsDiffEq for Hsv<S, T>
533533
where
534-
T: Component + Float + ApproxEq,
534+
T: Component + Float + AbsDiffEq,
535535
T::Epsilon: Copy + Float,
536-
S: RgbSpace,
536+
S: RgbSpace + PartialEq,
537537
{
538-
type Epsilon = <T as ApproxEq>::Epsilon;
538+
type Epsilon = T::Epsilon;
539539

540540
fn default_epsilon() -> Self::Epsilon {
541541
T::default_epsilon()
542542
}
543+
544+
fn abs_diff_eq(&self, other: &Self, epsilon: T::Epsilon) -> bool {
545+
self.hue.abs_diff_eq(&other.hue, epsilon) &&
546+
self.saturation.abs_diff_eq(&other.saturation, epsilon) &&
547+
self.value.abs_diff_eq(&other.value, epsilon)
548+
}
549+
}
550+
551+
impl<S, T> RelativeEq for Hsv<S, T>
552+
where
553+
T: Component + Float + RelativeEq,
554+
T::Epsilon: Copy + Float,
555+
S: RgbSpace + PartialEq,
556+
{
543557
fn default_max_relative() -> Self::Epsilon {
544558
T::default_max_relative()
545559
}
546-
fn default_max_ulps() -> u32 {
547-
T::default_max_ulps()
548-
}
560+
549561
#[cfg_attr(rustfmt, rustfmt_skip)]
550562
fn relative_eq(
551563
&self,
@@ -554,15 +566,26 @@ where
554566
max_relative: Self::Epsilon,
555567
) -> bool {
556568
self.hue.relative_eq(&other.hue, epsilon, max_relative) &&
557-
self.saturation.relative_eq(&other.saturation, epsilon, max_relative) &&
558-
self.value.relative_eq(&other.value, epsilon, max_relative)
569+
self.saturation.relative_eq(&other.saturation, epsilon, max_relative) &&
570+
self.value.relative_eq(&other.value, epsilon, max_relative)
571+
}
572+
}
573+
574+
impl<S, T> UlpsEq for Hsv<S, T>
575+
where
576+
T: Component + Float + UlpsEq,
577+
T::Epsilon: Copy + Float,
578+
S: RgbSpace + PartialEq,
579+
{
580+
fn default_max_ulps() -> u32 {
581+
T::default_max_ulps()
559582
}
560583

561584
#[cfg_attr(rustfmt, rustfmt_skip)]
562585
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
563586
self.hue.ulps_eq(&other.hue, epsilon, max_ulps) &&
564-
self.saturation.ulps_eq(&other.saturation, epsilon, max_ulps) &&
565-
self.value.ulps_eq(&other.value, epsilon, max_ulps)
587+
self.saturation.ulps_eq(&other.saturation, epsilon, max_ulps) &&
588+
self.value.ulps_eq(&other.value, epsilon, max_ulps)
566589
}
567590
}
568591

‎palette/src/hwb.rs

+52-12
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use approx::ApproxEq;
1+
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
22
use num_traits::Float;
33

44
use std::any::TypeId;
@@ -446,23 +446,48 @@ where
446446
}
447447
}
448448

449-
impl<S, T> ApproxEq for Hwb<S, T>
449+
impl<S, T> AbsDiffEq for Hwb<S, T>
450450
where
451-
T: Component + Float + ApproxEq,
451+
T: Component + Float + AbsDiffEq,
452452
T::Epsilon: Copy + Float,
453-
S: RgbSpace,
453+
S: RgbSpace + PartialEq,
454454
{
455-
type Epsilon = <T as ApproxEq>::Epsilon;
455+
type Epsilon = T::Epsilon;
456456

457457
fn default_epsilon() -> Self::Epsilon {
458458
T::default_epsilon()
459459
}
460+
461+
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
462+
let equal_shade = self
463+
.whiteness
464+
.abs_diff_eq(&other.whiteness, epsilon)
465+
&& self
466+
.blackness
467+
.abs_diff_eq(&other.blackness, epsilon);
468+
469+
// The hue doesn't matter that much when the color is gray, and may fluctuate
470+
// due to precision errors. This is a blunt tool, but works for now.
471+
let is_gray = self.blackness + self.whiteness >= T::one()
472+
|| other.blackness + other.whiteness >= T::one();
473+
if is_gray {
474+
equal_shade
475+
} else {
476+
self.hue.abs_diff_eq(&other.hue, epsilon) && equal_shade
477+
}
478+
}
479+
}
480+
481+
impl<S, T> RelativeEq for Hwb<S, T>
482+
where
483+
T: Component + Float + RelativeEq,
484+
T::Epsilon: Copy + Float,
485+
S: RgbSpace + PartialEq,
486+
{
460487
fn default_max_relative() -> Self::Epsilon {
461488
T::default_max_relative()
462489
}
463-
fn default_max_ulps() -> u32 {
464-
T::default_max_ulps()
465-
}
490+
466491
fn relative_eq(
467492
&self,
468493
other: &Self,
@@ -473,8 +498,8 @@ where
473498
.whiteness
474499
.relative_eq(&other.whiteness, epsilon, max_relative)
475500
&& self
476-
.blackness
477-
.relative_eq(&other.blackness, epsilon, max_relative);
501+
.blackness
502+
.relative_eq(&other.blackness, epsilon, max_relative);
478503

479504
// The hue doesn't matter that much when the color is gray, and may fluctuate
480505
// due to precision errors. This is a blunt tool, but works for now.
@@ -486,10 +511,25 @@ where
486511
self.hue.relative_eq(&other.hue, epsilon, max_relative) && equal_shade
487512
}
488513
}
514+
}
515+
516+
impl<S, T> UlpsEq for Hwb<S, T>
517+
where
518+
T: Component + Float + UlpsEq,
519+
T::Epsilon: Copy + Float,
520+
S: RgbSpace + PartialEq,
521+
{
522+
fn default_max_ulps() -> u32 {
523+
T::default_max_ulps()
524+
}
489525

490526
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
491-
let equal_shade = self.whiteness.ulps_eq(&other.whiteness, epsilon, max_ulps)
492-
&& self.blackness.ulps_eq(&other.blackness, epsilon, max_ulps);
527+
let equal_shade = self
528+
.whiteness
529+
.ulps_eq(&other.whiteness, epsilon, max_ulps)
530+
&& self
531+
.blackness
532+
.ulps_eq(&other.blackness, epsilon, max_ulps);
493533

494534
// The hue doesn't matter that much when the color is gray, and may fluctuate
495535
// due to precision errors. This is a blunt tool, but works for now.

‎palette/src/lib.rs

+33-11
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ extern crate serde_json;
158158

159159
use num_traits::{Float, NumCast, ToPrimitive, Zero};
160160

161-
use approx::ApproxEq;
161+
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
162162

163163
use blend::PreAlpha;
164164
use encoding::Linear;
@@ -394,7 +394,7 @@ macro_rules! make_color {
394394
///It's not recommended to use `Color` when full control is necessary,
395395
///but it can easily be converted to a fixed color space in those
396396
///cases.
397-
#[derive(Debug)]
397+
#[derive(Debug, PartialEq)]
398398
pub enum Color<S = encoding::Srgb, T = f32>
399399
where T: Float + Component,
400400
S: RgbSpace,
@@ -516,23 +516,34 @@ macro_rules! make_color {
516516
}
517517
}
518518

519-
impl<S, T> ApproxEq for Color<S, T>
520-
where T: Float + Component + ApproxEq,
521-
T::Epsilon: Float,
522-
S: RgbSpace,
519+
impl<S, T> AbsDiffEq for Color<S, T>
520+
where T: Float + Component + AbsDiffEq,
521+
T::Epsilon: Float,
522+
S: RgbSpace + PartialEq,
523+
<S as rgb::RgbSpace>::WhitePoint: PartialEq,
523524
{
524525
type Epsilon = T::Epsilon;
525526

526527
fn default_epsilon() -> Self::Epsilon {
527528
T::default_epsilon()
528529
}
529530

530-
fn default_max_relative() -> Self::Epsilon {
531-
T::default_max_relative()
531+
fn abs_diff_eq(&self, other: &Self, epsilon: T::Epsilon) -> bool {
532+
match (*self, *other) {
533+
$((Color::$variant(ref s), Color::$variant(ref o)) => s.abs_diff_eq(o, epsilon),)+
534+
_ => false
535+
}
532536
}
537+
}
533538

534-
fn default_max_ulps() -> u32 {
535-
T::default_max_ulps()
539+
impl<S, T> RelativeEq for Color<S, T>
540+
where T: Float + Component + RelativeEq,
541+
T::Epsilon: Float,
542+
S: RgbSpace + PartialEq,
543+
<S as rgb::RgbSpace>::WhitePoint: PartialEq,
544+
{
545+
fn default_max_relative() -> Self::Epsilon {
546+
T::default_max_relative()
536547
}
537548

538549
fn relative_eq(&self, other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon) -> bool {
@@ -541,8 +552,19 @@ macro_rules! make_color {
541552
_ => false
542553
}
543554
}
555+
}
556+
557+
impl<S, T> UlpsEq for Color<S, T>
558+
where T: Float + Component + UlpsEq,
559+
T::Epsilon: Float,
560+
S: RgbSpace + PartialEq,
561+
<S as rgb::RgbSpace>::WhitePoint: PartialEq,
562+
{
563+
fn default_max_ulps() -> u32 {
564+
T::default_max_ulps()
565+
}
544566

545-
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool{
567+
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
546568
match (*self, *other) {
547569
$((Color::$variant(ref s), Color::$variant(ref o)) => s.ulps_eq(o, epsilon, max_ulps),)+
548570
_ => false

‎palette/src/luma/luma.rs

+28-8
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::fmt;
22
use std::marker::PhantomData;
33
use std::ops::{Add, Div, Mul, Sub};
44

5-
use approx::ApproxEq;
5+
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
66

77
use num_traits::Float;
88

@@ -553,23 +553,32 @@ where
553553
}
554554
}
555555

556-
impl<S, T> ApproxEq for Luma<S, T>
556+
impl<S, T> AbsDiffEq for Luma<S, T>
557557
where
558-
T: Component + ApproxEq,
558+
T: Component + AbsDiffEq,
559559
T::Epsilon: Copy,
560-
S: LumaStandard,
560+
S: LumaStandard + PartialEq,
561561
{
562-
type Epsilon = <T as ApproxEq>::Epsilon;
562+
type Epsilon = T::Epsilon;
563563

564564
fn default_epsilon() -> Self::Epsilon {
565565
T::default_epsilon()
566566
}
567+
568+
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
569+
self.luma.abs_diff_eq(&other.luma, epsilon)
570+
}
571+
}
572+
573+
impl<S, T> RelativeEq for Luma<S, T>
574+
where
575+
T: Component + RelativeEq,
576+
T::Epsilon: Copy,
577+
S: LumaStandard + PartialEq,
578+
{
567579
fn default_max_relative() -> Self::Epsilon {
568580
T::default_max_relative()
569581
}
570-
fn default_max_ulps() -> u32 {
571-
T::default_max_ulps()
572-
}
573582

574583
fn relative_eq(
575584
&self,
@@ -579,6 +588,17 @@ where
579588
) -> bool {
580589
self.luma.relative_eq(&other.luma, epsilon, max_relative)
581590
}
591+
}
592+
593+
impl<S, T> UlpsEq for Luma<S, T>
594+
where
595+
T: Component + UlpsEq,
596+
T::Epsilon: Copy,
597+
S: LumaStandard + PartialEq,
598+
{
599+
fn default_max_ulps() -> u32 {
600+
T::default_max_ulps()
601+
}
582602

583603
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
584604
self.luma.ulps_eq(&other.luma, epsilon, max_ulps)

‎palette/src/rgb/rgb.rs

+35-12
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::fmt;
33
use std::marker::PhantomData;
44
use std::ops::{Add, Div, Mul, Sub};
55

6-
use approx::ApproxEq;
6+
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
77
use num_traits::Float;
88

99
use alpha::Alpha;
@@ -716,23 +716,35 @@ where
716716
}
717717
}
718718

719-
impl<S, T> ApproxEq for Rgb<S, T>
719+
impl<S, T> AbsDiffEq for Rgb<S, T>
720720
where
721-
T: Component + ApproxEq,
721+
T: Component + AbsDiffEq,
722722
T::Epsilon: Copy,
723-
S: RgbStandard,
723+
S: RgbStandard + PartialEq,
724724
{
725-
type Epsilon = <T as ApproxEq>::Epsilon;
725+
type Epsilon = T::Epsilon;
726726

727727
fn default_epsilon() -> Self::Epsilon {
728728
T::default_epsilon()
729729
}
730+
731+
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
732+
self.red.abs_diff_eq(&other.red, epsilon) &&
733+
self.green.abs_diff_eq(&other.green, epsilon) &&
734+
self.blue.abs_diff_eq(&other.blue, epsilon)
735+
}
736+
}
737+
738+
impl<S, T> RelativeEq for Rgb<S, T>
739+
where
740+
T: Component + RelativeEq,
741+
T::Epsilon: Copy,
742+
S: RgbStandard + PartialEq,
743+
{
730744
fn default_max_relative() -> Self::Epsilon {
731745
T::default_max_relative()
732746
}
733-
fn default_max_ulps() -> u32 {
734-
T::default_max_ulps()
735-
}
747+
736748
#[cfg_attr(rustfmt, rustfmt_skip)]
737749
fn relative_eq(
738750
&self,
@@ -741,15 +753,26 @@ where
741753
max_relative: Self::Epsilon,
742754
) -> bool {
743755
self.red.relative_eq(&other.red, epsilon, max_relative) &&
744-
self.green.relative_eq(&other.green, epsilon, max_relative) &&
745-
self.blue.relative_eq(&other.blue, epsilon, max_relative)
756+
self.green.relative_eq(&other.green, epsilon, max_relative) &&
757+
self.blue.relative_eq(&other.blue, epsilon, max_relative)
758+
}
759+
}
760+
761+
impl<S, T> UlpsEq for Rgb<S, T>
762+
where
763+
T: Component + UlpsEq,
764+
T::Epsilon: Copy,
765+
S: RgbStandard + PartialEq,
766+
{
767+
fn default_max_ulps() -> u32 {
768+
T::default_max_ulps()
746769
}
747770

748771
#[cfg_attr(rustfmt, rustfmt_skip)]
749772
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
750773
self.red.ulps_eq(&other.red, epsilon, max_ulps) &&
751-
self.green.ulps_eq(&other.green, epsilon, max_ulps) &&
752-
self.blue.ulps_eq(&other.blue, epsilon, max_ulps)
774+
self.green.ulps_eq(&other.green, epsilon, max_ulps) &&
775+
self.blue.ulps_eq(&other.blue, epsilon, max_ulps)
753776
}
754777
}
755778

0 commit comments

Comments
 (0)
Please sign in to comment.