1use crate::{flat::ViewOfPixel, math::Rect, 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 fn to_pixel_view(&self) -> Option<ViewOfPixel<'_, Self::Pixel>> {
213 let inner = self.image.to_pixel_view()?;
214
215 let mut descriptor = inner.into_inner();
217
218 let offset = descriptor.index(0, self.xoffset, self.yoffset)?;
219 descriptor.samples = descriptor.samples.get(offset..)?;
220 descriptor.layout.width = self.xstride;
221 descriptor.layout.height = self.ystride;
222
223 descriptor.into_view().ok()
224 }
225}
226
227#[allow(deprecated)]
228impl<I> GenericImage for SubImageInner<I>
229where
230 I: DerefMut,
231 I::Target: GenericImage + Sized,
232{
233 fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut Self::Pixel {
234 self.image.get_pixel_mut(x + self.xoffset, y + self.yoffset)
235 }
236
237 fn put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
238 self.image
239 .put_pixel(x + self.xoffset, y + self.yoffset, pixel);
240 }
241
242 fn blend_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
244 self.image
245 .blend_pixel(x + self.xoffset, y + self.yoffset, pixel);
246 }
247
248 fn copy_from<O>(&mut self, other: &O, x: u32, y: u32) -> Result<(), crate::ImageError>
249 where
250 O: GenericImageView<Pixel = Self::Pixel>,
251 {
252 Rect::from_image_at(other, x, y).test_in_bounds(self)?;
253 self.image
256 .copy_from(other, x + self.xoffset, y + self.yoffset)
257 }
258}
259
260#[cfg(test)]
261mod tests {
262 use crate::{metadata::Cicp, GenericImageView, RgbaImage};
263
264 #[test]
265 fn preserves_color_space() {
266 let mut buffer = RgbaImage::new(16, 16);
267 buffer[(0, 0)] = crate::Rgba([0xff, 0, 0, 255]);
268 buffer.set_rgb_primaries(Cicp::DISPLAY_P3.primaries);
269
270 let view = buffer.view(0, 0, 16, 16);
271 let result = view.buffer_like();
272
273 assert_eq!(buffer.color_space(), result.color_space());
274 }
275
276 #[test]
277 fn deep_preserves_color_space() {
278 let mut buffer = RgbaImage::new(16, 16);
279 buffer[(0, 0)] = crate::Rgba([0xff, 0, 0, 255]);
280 buffer.set_rgb_primaries(Cicp::DISPLAY_P3.primaries);
281
282 let view = buffer.view(0, 0, 16, 16);
283 let view = view.view(0, 0, 16, 16);
284 let result = view.buffer_like();
285
286 assert_eq!(buffer.color_space(), result.color_space());
287 }
288}