1
//! Pixel iterators for `SharedImageSurface`.
2
use crate::rect::IRect;
3
use crate::util::clamp;
4

            
5
use super::shared_surface::SharedImageSurface;
6
use super::{EdgeMode, Pixel};
7

            
8
/// Iterator over pixels of a `SharedImageSurface`.
9
pub struct Pixels<'a> {
10
    surface: &'a SharedImageSurface,
11
    bounds: IRect,
12
    x: u32,
13
    y: u32,
14
    offset: isize,
15
}
16

            
17
/// Iterator over a (potentially out of bounds) rectangle of pixels of a `SharedImageSurface`.
18
pub struct PixelRectangle<'a> {
19
    surface: &'a SharedImageSurface,
20
    bounds: IRect,
21
    rectangle: IRect,
22
    edge_mode: EdgeMode,
23
    x: i32,
24
    y: i32,
25
}
26

            
27
impl<'a> Pixels<'a> {
28
    /// Creates an iterator over the image surface pixels
29
    #[inline]
30
30971
    pub fn new(surface: &'a SharedImageSurface) -> Self {
31
30971
        let bounds = IRect::from_size(surface.width(), surface.height());
32
30971

            
33
30971
        Self::within(surface, bounds)
34
30971
    }
35

            
36
    /// Creates an iterator over the image surface pixels, constrained within the given bounds.
37
    #[inline]
38
43937
    pub fn within(surface: &'a SharedImageSurface, bounds: IRect) -> Self {
39
43937
        // Sanity checks.
40
43937
        assert!(bounds.x0 >= 0);
41
43937
        assert!(bounds.x0 <= surface.width());
42
43937
        assert!(bounds.x1 >= bounds.x0);
43
43937
        assert!(bounds.x1 <= surface.width());
44
43937
        assert!(bounds.y0 >= 0);
45
43937
        assert!(bounds.y0 <= surface.height());
46
43937
        assert!(bounds.y1 >= bounds.y0);
47
43937
        assert!(bounds.y1 <= surface.height());
48

            
49
43937
        Self {
50
43937
            surface,
51
43937
            bounds,
52
43937
            x: bounds.x0 as u32,
53
43937
            y: bounds.y0 as u32,
54
43937
            offset: bounds.y0 as isize * surface.stride() + bounds.x0 as isize * 4,
55
43937
        }
56
43937
    }
57
}
58

            
59
impl<'a> PixelRectangle<'a> {
60
    /// Creates an iterator over the image surface pixels
61
    #[inline]
62
1
    pub fn new(surface: &'a SharedImageSurface, rectangle: IRect, edge_mode: EdgeMode) -> Self {
63
1
        let bounds = IRect::from_size(surface.width(), surface.height());
64
1

            
65
1
        Self::within(surface, bounds, rectangle, edge_mode)
66
1
    }
67

            
68
    /// Creates an iterator over the image surface pixels, constrained within the given bounds.
69
    #[inline]
70
7237310
    pub fn within(
71
7237310
        surface: &'a SharedImageSurface,
72
7237310
        bounds: IRect,
73
7237310
        rectangle: IRect,
74
7237310
        edge_mode: EdgeMode,
75
7237310
    ) -> Self {
76
7237310
        // Sanity checks.
77
7237310
        assert!(bounds.x0 >= 0);
78
7237310
        assert!(bounds.x0 <= surface.width());
79
7237310
        assert!(bounds.x1 >= bounds.x0);
80
7237310
        assert!(bounds.x1 <= surface.width());
81
7237310
        assert!(bounds.y0 >= 0);
82
7237310
        assert!(bounds.y0 <= surface.height());
83
7237310
        assert!(bounds.y1 >= bounds.y0);
84
7237310
        assert!(bounds.y1 <= surface.height());
85

            
86
        // Non-None EdgeMode values need at least one pixel available.
87
7237310
        if edge_mode != EdgeMode::None {
88
3058392
            assert!(bounds.x1 > bounds.x0);
89
3058392
            assert!(bounds.y1 > bounds.y0);
90
4178918
        }
91

            
92
7237310
        assert!(rectangle.x1 >= rectangle.x0);
93
7237310
        assert!(rectangle.y1 >= rectangle.y0);
94

            
95
7237310
        Self {
96
7237310
            surface,
97
7237310
            bounds,
98
7237310
            rectangle,
99
7237310
            edge_mode,
100
7237310
            x: rectangle.x0,
101
7237310
            y: rectangle.y0,
102
7237310
        }
103
7237310
    }
104
}
105

            
106
impl<'a> Iterator for Pixels<'a> {
107
    type Item = (u32, u32, Pixel);
108

            
109
    #[inline]
110
2794620002
    fn next(&mut self) -> Option<Self::Item> {
111
2794620002
        // This means we hit the end on the last iteration.
112
2794620002
        if self.x == self.bounds.x1 as u32 || self.y == self.bounds.y1 as u32 {
113
28452
            return None;
114
2794591550
        }
115
2794591550

            
116
2794591550
        let rv = Some((
117
2794591550
            self.x,
118
2794591550
            self.y,
119
2794591550
            self.surface.get_pixel_by_offset(self.offset),
120
2794591550
        ));
121
2794591550

            
122
2794591550
        if self.x + 1 == self.bounds.x1 as u32 {
123
6168226
            self.x = self.bounds.x0 as u32;
124
6168226
            self.y += 1;
125
6168226
            self.offset += self.surface.stride() - (self.bounds.width() - 1) as isize * 4;
126
2788423324
        } else {
127
2788423324
            self.x += 1;
128
2788423324
            self.offset += 4;
129
2788423324
        }
130

            
131
2794591550
        rv
132
2794620002
    }
133
}
134

            
135
impl<'a> Iterator for PixelRectangle<'a> {
136
    type Item = (i32, i32, Pixel);
137

            
138
    #[inline(always)]
139
83009357
    fn next(&mut self) -> Option<Self::Item> {
140
83009357
        // This means we hit the end on the last iteration.
141
83009357
        if self.x == self.rectangle.x1 || self.y == self.rectangle.y1 {
142
7237310
            return None;
143
75772047
        }
144
75772047

            
145
75772047
        let rv = {
146
75772047
            let get_pixel = |x, y| {
147
75772047
                if !self.bounds.contains(x, y) {
148
1459506
                    match self.edge_mode {
149
892356
                        EdgeMode::None => Pixel {
150
892356
                            r: 0,
151
892356
                            g: 0,
152
892356
                            b: 0,
153
892356
                            a: 0,
154
892356
                        },
155
                        EdgeMode::Duplicate => {
156
363850
                            let x = clamp(x, self.bounds.x0, self.bounds.x1 - 1);
157
363850
                            let y = clamp(y, self.bounds.y0, self.bounds.y1 - 1);
158
363850
                            self.surface.get_pixel(x as u32, y as u32)
159
                        }
160
                        EdgeMode::Wrap => {
161
406600
                            let wrap = |mut x, v| {
162
421876
                                while x < 0 {
163
15276
                                    x += v;
164
15276
                                }
165
406600
                                x % v
166
406600
                            };
167

            
168
203300
                            let x = self.bounds.x0 + wrap(x - self.bounds.x0, self.bounds.width());
169
203300
                            let y = self.bounds.y0 + wrap(y - self.bounds.y0, self.bounds.height());
170
203300
                            self.surface.get_pixel(x as u32, y as u32)
171
                        }
172
                    }
173
                } else {
174
74312541
                    self.surface.get_pixel(x as u32, y as u32)
175
                }
176
75772047
            };
177

            
178
75772047
            Some((self.x, self.y, get_pixel(self.x, self.y)))
179
75772047
        };
180
75772047

            
181
75772047
        if self.x + 1 == self.rectangle.x1 {
182
24882169
            self.x = self.rectangle.x0;
183
24882169
            self.y += 1;
184
50889878
        } else {
185
50889878
            self.x += 1;
186
50889878
        }
187

            
188
75772047
        rv
189
83009357
    }
190
}
191

            
192
#[cfg(test)]
193
mod tests {
194
    use super::*;
195
    use crate::surface_utils::shared_surface::SurfaceType;
196

            
197
    #[test]
198
1
    fn pixels_count() {
199
        const WIDTH: i32 = 32;
200
        const HEIGHT: i32 = 64;
201

            
202
1
        let surface = SharedImageSurface::empty(WIDTH, HEIGHT, SurfaceType::SRgb).unwrap();
203
1

            
204
1
        // Full image.
205
1
        assert_eq!(Pixels::new(&surface).count(), (WIDTH * HEIGHT) as usize);
206

            
207
        // 1-wide column.
208
1
        let bounds = IRect::from_size(1, HEIGHT);
209
1
        assert_eq!(Pixels::within(&surface, bounds).count(), HEIGHT as usize);
210

            
211
        // 1-tall row.
212
1
        let bounds = IRect::from_size(WIDTH, 1);
213
1
        assert_eq!(Pixels::within(&surface, bounds).count(), WIDTH as usize);
214

            
215
        // 1×1.
216
1
        let bounds = IRect::from_size(1, 1);
217
1
        assert_eq!(Pixels::within(&surface, bounds).count(), 1);
218

            
219
        // Nothing (x0 == x1).
220
1
        let bounds = IRect::from_size(0, HEIGHT);
221
1
        assert_eq!(Pixels::within(&surface, bounds).count(), 0);
222

            
223
        // Nothing (y0 == y1).
224
1
        let bounds = IRect::from_size(WIDTH, 0);
225
1
        assert_eq!(Pixels::within(&surface, bounds).count(), 0);
226

            
227
        // Nothing (x0 == x1, y0 == y1).
228
1
        let bounds = IRect::new(0, 0, 0, 0);
229
1
        assert_eq!(Pixels::within(&surface, bounds).count(), 0);
230
1
    }
231

            
232
    #[test]
233
1
    fn pixel_rectangle() {
234
        const WIDTH: i32 = 32;
235
        const HEIGHT: i32 = 64;
236

            
237
1
        let surface = SharedImageSurface::empty(WIDTH, HEIGHT, SurfaceType::SRgb).unwrap();
238
1

            
239
1
        let rect_bounds = IRect::new(-8, -8, 8, 8);
240
1
        assert_eq!(
241
1
            PixelRectangle::new(&surface, rect_bounds, EdgeMode::None).count(),
242
1
            (16 * 16) as usize
243
1
        );
244
1
    }
245
}