1use crate::{GenericImage, GenericImageView, ImageBuffer, Pixel};
2use std::ops::{Deref, DerefMut};
3
4#[derive(Copy, Clone)]
26pub struct SubImage<I> {
27 inner: SubImageInner<I>,
28}
29
30#[derive(Copy, Clone)]
35pub struct SubImageInner<I> {
36 image: I,
37 xoffset: u32,
38 yoffset: u32,
39 xstride: u32,
40 ystride: u32,
41}
42
43type DerefPixel<I> = <<I as Deref>::Target as GenericImageView>::Pixel;
45
46type DerefSubpixel<I> = <DerefPixel<I> as Pixel>::Subpixel;
48
49impl<I> SubImage<I> {
50 pub fn new(image: I, x: u32, y: u32, width: u32, height: u32) -> SubImage<I> {
53 SubImage {
54 inner: SubImageInner {
55 image,
56 xoffset: x,
57 yoffset: y,
58 xstride: width,
59 ystride: height,
60 },
61 }
62 }
63
64 pub fn change_bounds(&mut self, x: u32, y: u32, width: u32, height: u32) {
66 self.inner.xoffset = x;
67 self.inner.yoffset = y;
68 self.inner.xstride = width;
69 self.inner.ystride = height;
70 }
71
72 pub fn offsets(&self) -> (u32, u32) {
74 (self.inner.xoffset, self.inner.yoffset)
75 }
76
77 pub fn to_image(&self) -> ImageBuffer<DerefPixel<I>, Vec<DerefSubpixel<I>>>
79 where
80 I: Deref,
81 I::Target: GenericImageView + 'static,
82 {
83 let borrowed = &*self.inner.image;
84 let mut out = borrowed.buffer_with_dimensions(self.inner.xstride, self.inner.ystride);
85
86 for y in 0..self.inner.ystride {
87 for x in 0..self.inner.xstride {
88 let p = borrowed.get_pixel(x + self.inner.xoffset, y + self.inner.yoffset);
89 out.put_pixel(x, y, p);
90 }
91 }
92
93 out
94 }
95}
96
97impl<I> SubImage<I>
99where
100 I: Deref,
101 I::Target: GenericImageView,
102{
103 pub fn view(&self, x: u32, y: u32, width: u32, height: u32) -> SubImage<&I::Target> {
122 use crate::GenericImageView as _;
123 assert!(u64::from(x) + u64::from(width) <= u64::from(self.inner.width()));
124 assert!(u64::from(y) + u64::from(height) <= u64::from(self.inner.height()));
125 let x = self.inner.xoffset.saturating_add(x);
126 let y = self.inner.yoffset.saturating_add(y);
127 SubImage::new(&*self.inner.image, x, y, width, height)
128 }
129
130 pub fn inner(&self) -> &I::Target {
132 &self.inner.image
133 }
134}
135
136impl<I> SubImage<I>
137where
138 I: DerefMut,
139 I::Target: GenericImage,
140{
141 pub fn sub_image(
145 &mut self,
146 x: u32,
147 y: u32,
148 width: u32,
149 height: u32,
150 ) -> SubImage<&mut I::Target> {
151 assert!(u64::from(x) + u64::from(width) <= u64::from(self.inner.width()));
152 assert!(u64::from(y) + u64::from(height) <= u64::from(self.inner.height()));
153 let x = self.inner.xoffset.saturating_add(x);
154 let y = self.inner.yoffset.saturating_add(y);
155 SubImage::new(&mut *self.inner.image, x, y, width, height)
156 }
157
158 pub fn inner_mut(&mut self) -> &mut I::Target {
160 &mut self.inner.image
161 }
162}
163
164impl<I> Deref for SubImage<I>
165where
166 I: Deref,
167{
168 type Target = SubImageInner<I>;
169
170 fn deref(&self) -> &Self::Target {
171 &self.inner
172 }
173}
174
175impl<I> DerefMut for SubImage<I>
176where
177 I: DerefMut,
178{
179 fn deref_mut(&mut self) -> &mut Self::Target {
180 &mut self.inner
181 }
182}
183
184#[allow(deprecated)]
185impl<I> GenericImageView for SubImageInner<I>
186where
187 I: Deref,
188 I::Target: GenericImageView,
189{
190 type Pixel = DerefPixel<I>;
191
192 fn dimensions(&self) -> (u32, u32) {
193 (self.xstride, self.ystride)
194 }
195
196 fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
197 self.image.get_pixel(x + self.xoffset, y + self.yoffset)
198 }
199
200 fn buffer_with_dimensions(
202 &self,
203 width: u32,
204 height: u32,
205 ) -> ImageBuffer<
206 <I::Target as GenericImageView>::Pixel,
207 Vec<<<I::Target as GenericImageView>::Pixel as Pixel>::Subpixel>,
208 > {
209 self.image.buffer_with_dimensions(width, height)
210 }
211}
212
213#[allow(deprecated)]
214impl<I> GenericImage for SubImageInner<I>
215where
216 I: DerefMut,
217 I::Target: GenericImage + Sized,
218{
219 fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut Self::Pixel {
220 self.image.get_pixel_mut(x + self.xoffset, y + self.yoffset)
221 }
222
223 fn put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
224 self.image
225 .put_pixel(x + self.xoffset, y + self.yoffset, pixel);
226 }
227
228 fn blend_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
230 self.image
231 .blend_pixel(x + self.xoffset, y + self.yoffset, pixel);
232 }
233}
234
235#[cfg(test)]
236mod tests {
237 use crate::{metadata::Cicp, GenericImageView, RgbaImage};
238
239 #[test]
240 fn preserves_color_space() {
241 let mut buffer = RgbaImage::new(16, 16);
242 buffer[(0, 0)] = crate::Rgba([0xff, 0, 0, 255]);
243 buffer.set_rgb_primaries(Cicp::DISPLAY_P3.primaries);
244
245 let view = buffer.view(0, 0, 16, 16);
246 let result = view.buffer_like();
247
248 assert_eq!(buffer.color_space(), result.color_space());
249 }
250
251 #[test]
252 fn deep_preserves_color_space() {
253 let mut buffer = RgbaImage::new(16, 16);
254 buffer[(0, 0)] = crate::Rgba([0xff, 0, 0, 255]);
255 buffer.set_rgb_primaries(Cicp::DISPLAY_P3.primaries);
256
257 let view = buffer.view(0, 0, 16, 16);
258 let view = view.view(0, 0, 16, 16);
259 let result = view.buffer_like();
260
261 assert_eq!(buffer.color_space(), result.color_space());
262 }
263}