1use crate::{flat::ViewOfPixel, math::Rect, GenericImage, GenericImageView, ImageBuffer, Pixel};
2use alloc::vec::Vec;
3use core::ops::{Deref, DerefMut};
4
5#[derive(Copy, Clone)]
27pub struct SubImage<I> {
28 inner: SubImageInner<I>,
29}
30
31#[derive(Copy, Clone)]
36pub struct SubImageInner<I> {
37 image: I,
38 xoffset: u32,
39 yoffset: u32,
40 xstride: u32,
41 ystride: u32,
42}
43
44type DerefPixel<I> = <<I as Deref>::Target as GenericImageView>::Pixel;
46
47type DerefSubpixel<I> = <DerefPixel<I> as Pixel>::Subpixel;
49
50impl<I> SubImage<I> {
51 pub fn new(image: I, x: u32, y: u32, width: u32, height: u32) -> SubImage<I> {
54 SubImage {
55 inner: SubImageInner {
56 image,
57 xoffset: x,
58 yoffset: y,
59 xstride: width,
60 ystride: height,
61 },
62 }
63 }
64
65 pub fn change_bounds(&mut self, x: u32, y: u32, width: u32, height: u32) {
67 self.inner.xoffset = x;
68 self.inner.yoffset = y;
69 self.inner.xstride = width;
70 self.inner.ystride = height;
71 }
72
73 pub fn offsets(&self) -> (u32, u32) {
75 (self.inner.xoffset, self.inner.yoffset)
76 }
77
78 pub fn to_image(&self) -> ImageBuffer<DerefPixel<I>, Vec<DerefSubpixel<I>>>
80 where
81 I: Deref,
82 I::Target: GenericImageView + 'static,
83 {
84 let borrowed = &*self.inner.image;
85 let mut out = borrowed.buffer_with_dimensions(self.inner.xstride, self.inner.ystride);
86
87 for y in 0..self.inner.ystride {
88 for x in 0..self.inner.xstride {
89 let p = borrowed.get_pixel(x + self.inner.xoffset, y + self.inner.yoffset);
90 out.put_pixel(x, y, p);
91 }
92 }
93
94 out
95 }
96}
97
98impl<I> SubImage<I>
100where
101 I: Deref,
102 I::Target: GenericImageView,
103{
104 pub fn view(&self, x: u32, y: u32, width: u32, height: u32) -> SubImage<&I::Target> {
123 use crate::GenericImageView as _;
124 assert!(u64::from(x) + u64::from(width) <= u64::from(self.inner.width()));
125 assert!(u64::from(y) + u64::from(height) <= u64::from(self.inner.height()));
126 let x = self.inner.xoffset.saturating_add(x);
127 let y = self.inner.yoffset.saturating_add(y);
128 SubImage::new(&*self.inner.image, x, y, width, height)
129 }
130
131 pub fn inner(&self) -> &I::Target {
133 &self.inner.image
134 }
135}
136
137impl<I> SubImage<I>
138where
139 I: DerefMut,
140 I::Target: GenericImage,
141{
142 pub fn sub_image(
146 &mut self,
147 x: u32,
148 y: u32,
149 width: u32,
150 height: u32,
151 ) -> SubImage<&mut I::Target> {
152 assert!(u64::from(x) + u64::from(width) <= u64::from(self.inner.width()));
153 assert!(u64::from(y) + u64::from(height) <= u64::from(self.inner.height()));
154 let x = self.inner.xoffset.saturating_add(x);
155 let y = self.inner.yoffset.saturating_add(y);
156 SubImage::new(&mut *self.inner.image, x, y, width, height)
157 }
158
159 pub fn inner_mut(&mut self) -> &mut I::Target {
161 &mut self.inner.image
162 }
163}
164
165impl<I> Deref for SubImage<I>
166where
167 I: Deref,
168{
169 type Target = SubImageInner<I>;
170
171 fn deref(&self) -> &Self::Target {
172 &self.inner
173 }
174}
175
176impl<I> DerefMut for SubImage<I>
177where
178 I: DerefMut,
179{
180 fn deref_mut(&mut self) -> &mut Self::Target {
181 &mut self.inner
182 }
183}
184
185#[allow(deprecated)]
186impl<I> GenericImageView for SubImageInner<I>
187where
188 I: Deref,
189 I::Target: GenericImageView,
190{
191 type Pixel = DerefPixel<I>;
192
193 fn dimensions(&self) -> (u32, u32) {
194 (self.xstride, self.ystride)
195 }
196
197 fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
198 self.image.get_pixel(x + self.xoffset, y + self.yoffset)
199 }
200
201 fn buffer_with_dimensions(
203 &self,
204 width: u32,
205 height: u32,
206 ) -> ImageBuffer<
207 <I::Target as GenericImageView>::Pixel,
208 Vec<<<I::Target as GenericImageView>::Pixel as Pixel>::Subpixel>,
209 > {
210 self.image.buffer_with_dimensions(width, height)
211 }
212
213 fn to_pixel_view(&self) -> Option<ViewOfPixel<'_, Self::Pixel>> {
214 let inner = self.image.to_pixel_view()?;
215
216 let mut descriptor = inner.into_inner();
218
219 let offset = descriptor.index(0, self.xoffset, self.yoffset)?;
220 descriptor.samples = descriptor.samples.get(offset..)?;
221 descriptor.layout.width = self.xstride;
222 descriptor.layout.height = self.ystride;
223
224 descriptor.into_view().ok()
225 }
226}
227
228#[allow(deprecated)]
229impl<I> GenericImage for SubImageInner<I>
230where
231 I: DerefMut,
232 I::Target: GenericImage + Sized,
233{
234 fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut Self::Pixel {
235 self.image.get_pixel_mut(x + self.xoffset, y + self.yoffset)
236 }
237
238 fn put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
239 self.image
240 .put_pixel(x + self.xoffset, y + self.yoffset, pixel);
241 }
242
243 fn blend_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
245 self.image
246 .blend_pixel(x + self.xoffset, y + self.yoffset, pixel);
247 }
248
249 fn copy_from<O>(&mut self, other: &O, x: u32, y: u32) -> Result<(), crate::ImageError>
250 where
251 O: GenericImageView<Pixel = Self::Pixel>,
252 {
253 Rect::from_image_at(other, x, y).test_in_bounds(self)?;
254 self.image
257 .copy_from(other, x + self.xoffset, y + self.yoffset)
258 }
259}
260
261#[cfg(test)]
262mod tests {
263 use crate::{metadata::Cicp, GenericImageView, RgbaImage};
264
265 #[test]
266 fn preserves_color_space() {
267 let mut buffer = RgbaImage::new(16, 16);
268 buffer[(0, 0)] = crate::Rgba([0xff, 0, 0, 255]);
269 buffer.set_rgb_primaries(Cicp::DISPLAY_P3.primaries);
270
271 let view = buffer.view(0, 0, 16, 16);
272 let result = view.buffer_like();
273
274 assert_eq!(buffer.color_space(), result.color_space());
275 }
276
277 #[test]
278 fn deep_preserves_color_space() {
279 let mut buffer = RgbaImage::new(16, 16);
280 buffer[(0, 0)] = crate::Rgba([0xff, 0, 0, 255]);
281 buffer.set_rgb_primaries(Cicp::DISPLAY_P3.primaries);
282
283 let view = buffer.view(0, 0, 16, 16);
284 let view = view.view(0, 0, 16, 16);
285 let result = view.buffer_like();
286
287 assert_eq!(buffer.color_space(), result.color_space());
288 }
289}