1use crate::error::{ImageError, ImageResult};
2use crate::flat::ViewOfPixel;
3use crate::math::Rect;
4use crate::traits::Pixel;
5use crate::{ImageBuffer, SubImage};
6use alloc::vec::Vec;
7
8pub trait GenericImageView {
17 type Pixel: Pixel;
19
20 fn dimensions(&self) -> (u32, u32);
22
23 fn width(&self) -> u32 {
25 let (w, _) = self.dimensions();
26 w
27 }
28
29 fn height(&self) -> u32 {
31 let (_, h) = self.dimensions();
32 h
33 }
34
35 fn in_bounds(&self, x: u32, y: u32) -> bool {
37 let (width, height) = self.dimensions();
38 x < width && y < height
39 }
40
41 fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel;
47
48 unsafe fn unsafe_get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
57 self.get_pixel(x, y)
58 }
59
60 fn pixels(&self) -> Pixels<'_, Self>
64 where
65 Self: Sized,
66 {
67 let (width, height) = self.dimensions();
68
69 Pixels {
70 image: self,
71 x: 0,
72 y: 0,
73 width,
74 height,
75 }
76 }
77
78 fn view(&self, x: u32, y: u32, width: u32, height: u32) -> SubImage<&Self>
86 where
87 Self: Sized,
88 {
89 assert!(u64::from(x) + u64::from(width) <= u64::from(self.width()));
90 assert!(u64::from(y) + u64::from(height) <= u64::from(self.height()));
91 SubImage::new(self, x, y, width, height)
92 }
93
94 fn try_view(
97 &self,
98 x: u32,
99 y: u32,
100 width: u32,
101 height: u32,
102 ) -> Result<SubImage<&Self>, ImageError>
103 where
104 Self: Sized,
105 {
106 let rect = Rect {
107 x,
108 y,
109 width,
110 height,
111 };
112
113 rect.test_in_bounds(self)?;
114 Ok(SubImage::new(self, x, y, width, height))
115 }
116
117 fn buffer_like(&self) -> ImageBuffer<Self::Pixel, Vec<<Self::Pixel as Pixel>::Subpixel>> {
126 let (w, h) = self.dimensions();
127 self.buffer_with_dimensions(w, h)
128 }
129
130 fn buffer_with_dimensions(
137 &self,
138 width: u32,
139 height: u32,
140 ) -> ImageBuffer<Self::Pixel, Vec<<Self::Pixel as Pixel>::Subpixel>> {
141 ImageBuffer::new(width, height)
142 }
143
144 fn to_pixel_view(&self) -> Option<ViewOfPixel<'_, Self::Pixel>> {
155 None
156 }
157}
158
159#[derive(Debug)]
161pub struct Pixels<'a, I: ?Sized + 'a> {
162 image: &'a I,
163 x: u32,
164 y: u32,
165 width: u32,
166 height: u32,
167}
168
169impl<I: GenericImageView> Iterator for Pixels<'_, I> {
170 type Item = (u32, u32, I::Pixel);
171
172 fn next(&mut self) -> Option<(u32, u32, I::Pixel)> {
173 if self.x >= self.width {
174 self.x = 0;
175 self.y += 1;
176 }
177
178 if self.y >= self.height {
179 None
180 } else {
181 let pixel = self.image.get_pixel(self.x, self.y);
182 let p = (self.x, self.y, pixel);
183
184 self.x += 1;
185
186 Some(p)
187 }
188 }
189}
190
191impl<I: ?Sized> Clone for Pixels<'_, I> {
192 fn clone(&self) -> Self {
193 Pixels { ..*self }
194 }
195}
196
197pub trait GenericImage: GenericImageView {
199 #[deprecated(since = "0.24.0", note = "Use `get_pixel` and `put_pixel` instead.")]
220 fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut Self::Pixel;
221
222 fn put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel);
228
229 unsafe fn unsafe_put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
238 self.put_pixel(x, y, pixel);
239 }
240
241 #[deprecated(
243 since = "0.24.0",
244 note = "Use iterator `pixels_mut` to blend the pixels directly"
245 )]
246 fn blend_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel);
247
248 fn copy_from<O>(&mut self, other: &O, x: u32, y: u32) -> ImageResult<()>
264 where
265 O: GenericImageView<Pixel = Self::Pixel>,
266 {
267 if let Some(flat) = other.to_pixel_view() {
268 return self.copy_from_samples(flat, x, y);
269 }
270
271 Rect::from_image_at(other, x, y).test_in_bounds(self)?;
274
275 for k in 0..other.height() {
276 for i in 0..other.width() {
277 let p = other.get_pixel(i, k);
278 self.put_pixel(i + x, k + y, p);
279 }
280 }
281
282 Ok(())
283 }
284
285 fn copy_from_samples(
287 &mut self,
288 samples: ViewOfPixel<'_, Self::Pixel>,
289 x: u32,
290 y: u32,
291 ) -> ImageResult<()> {
292 Rect::from_image_at(&samples, x, y).test_in_bounds(self)?;
295
296 for k in 0..samples.height() {
297 for i in 0..samples.width() {
298 let p = samples.get_pixel(i, k);
299 self.put_pixel(i + x, k + y, p);
300 }
301 }
302
303 Ok(())
304 }
305
306 fn copy_within(&mut self, source: Rect, x: u32, y: u32) -> bool {
314 let Rect {
315 x: sx,
316 y: sy,
317 width,
318 height,
319 } = source;
320 let dx = x;
321 let dy = y;
322 assert!(sx < self.width() && dx < self.width());
323 assert!(sy < self.height() && dy < self.height());
324 if self.width() - dx.max(sx) < width || self.height() - dy.max(sy) < height {
325 return false;
326 }
327 macro_rules! copy_within_impl_ {
330 ($xiter:expr, $yiter:expr) => {
331 for y in $yiter {
332 let sy = sy + y;
333 let dy = dy + y;
334 for x in $xiter {
335 let sx = sx + x;
336 let dx = dx + x;
337 let pixel = self.get_pixel(sx, sy);
338 self.put_pixel(dx, dy, pixel);
339 }
340 }
341 };
342 }
343 match (sx < dx, sy < dy) {
345 (true, true) => copy_within_impl_!((0..width).rev(), (0..height).rev()),
346 (true, false) => copy_within_impl_!((0..width).rev(), 0..height),
347 (false, true) => copy_within_impl_!(0..width, (0..height).rev()),
348 (false, false) => copy_within_impl_!(0..width, 0..height),
349 }
350 true
351 }
352
353 fn sub_image(&mut self, x: u32, y: u32, width: u32, height: u32) -> SubImage<&mut Self>
357 where
358 Self: Sized,
359 {
360 assert!(u64::from(x) + u64::from(width) <= u64::from(self.width()));
361 assert!(u64::from(y) + u64::from(height) <= u64::from(self.height()));
362 SubImage::new(self, x, y, width, height)
363 }
364}
365
366#[cfg(test)]
367mod tests {
368 use super::{GenericImage, GenericImageView};
369
370 use crate::color::Rgba;
371 use crate::math::Rect;
372 use crate::{GrayImage, ImageBuffer};
373
374 #[test]
375 #[allow(deprecated)]
376 fn test_image_alpha_blending() {
378 let mut target = ImageBuffer::new(1, 1);
379 target.put_pixel(0, 0, Rgba([255u8, 0, 0, 255]));
380 assert!(*target.get_pixel(0, 0) == Rgba([255, 0, 0, 255]));
381 target.blend_pixel(0, 0, Rgba([0, 255, 0, 255]));
382 assert!(*target.get_pixel(0, 0) == Rgba([0, 255, 0, 255]));
383
384 target.blend_pixel(0, 0, Rgba([255, 0, 0, 127]));
386 assert!(*target.get_pixel(0, 0) == Rgba([127, 127, 0, 255]));
387
388 target.put_pixel(0, 0, Rgba([0, 255, 0, 127]));
390 target.blend_pixel(0, 0, Rgba([255, 0, 0, 127]));
391 assert!(*target.get_pixel(0, 0) == Rgba([169, 85, 0, 190]));
392 }
393
394 #[test]
395 fn test_in_bounds() {
396 let mut target = ImageBuffer::new(2, 2);
397 target.put_pixel(0, 0, Rgba([255u8, 0, 0, 255]));
398
399 assert!(target.in_bounds(0, 0));
400 assert!(target.in_bounds(1, 0));
401 assert!(target.in_bounds(0, 1));
402 assert!(target.in_bounds(1, 1));
403
404 assert!(!target.in_bounds(2, 0));
405 assert!(!target.in_bounds(0, 2));
406 assert!(!target.in_bounds(2, 2));
407 }
408
409 #[test]
410 fn test_can_subimage_clone_nonmut() {
411 let mut source = ImageBuffer::new(3, 3);
412 source.put_pixel(1, 1, Rgba([255u8, 0, 0, 255]));
413
414 let source = source.clone();
416
417 let cloned = source.view(1, 1, 1, 1).to_image();
419
420 assert!(cloned.get_pixel(0, 0) == source.get_pixel(1, 1));
421 }
422
423 #[test]
424 fn test_can_nest_views() {
425 let mut source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
426
427 {
428 let mut sub1 = source.sub_image(0, 0, 2, 2);
429 let mut sub2 = sub1.sub_image(1, 1, 1, 1);
430 sub2.put_pixel(0, 0, Rgba([0, 0, 0, 0]));
431 }
432
433 assert_eq!(*source.get_pixel(1, 1), Rgba([0, 0, 0, 0]));
434
435 let view1 = source.view(0, 0, 2, 2);
436 assert_eq!(*source.get_pixel(1, 1), view1.get_pixel(1, 1));
437
438 let view2 = view1.view(1, 1, 1, 1);
439 assert_eq!(*source.get_pixel(1, 1), view2.get_pixel(0, 0));
440 }
441
442 #[test]
443 #[should_panic]
444 fn test_view_out_of_bounds() {
445 let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
446 source.view(1, 1, 3, 3);
447 }
448
449 #[test]
450 #[should_panic]
451 fn test_view_coordinates_out_of_bounds() {
452 let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
453 source.view(3, 3, 3, 3);
454 }
455
456 #[test]
457 #[should_panic]
458 fn test_view_width_out_of_bounds() {
459 let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
460 source.view(1, 1, 3, 2);
461 }
462
463 #[test]
464 #[should_panic]
465 fn test_view_height_out_of_bounds() {
466 let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
467 source.view(1, 1, 2, 3);
468 }
469
470 #[test]
471 #[should_panic]
472 fn test_view_x_out_of_bounds() {
473 let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
474 source.view(3, 1, 3, 3);
475 }
476
477 #[test]
478 #[should_panic]
479 fn test_view_y_out_of_bounds() {
480 let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
481 source.view(1, 3, 3, 3);
482 }
483
484 #[test]
485 fn test_view_in_bounds() {
486 let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
487 source.view(0, 0, 3, 3);
488 source.view(1, 1, 2, 2);
489 source.view(2, 2, 0, 0);
490 }
491
492 #[test]
493 fn test_copy_sub_image() {
494 let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
495 let view = source.view(0, 0, 3, 3);
496 let _view2 = view;
497 view.to_image();
498 }
499
500 #[test]
501 fn test_generic_image_copy_within_oob() {
502 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, vec![0u8; 16]).unwrap();
503 assert!(!image.sub_image(0, 0, 4, 4).copy_within(
504 Rect {
505 x: 0,
506 y: 0,
507 width: 5,
508 height: 4
509 },
510 0,
511 0
512 ));
513 assert!(!image.sub_image(0, 0, 4, 4).copy_within(
514 Rect {
515 x: 0,
516 y: 0,
517 width: 4,
518 height: 5
519 },
520 0,
521 0
522 ));
523 assert!(!image.sub_image(0, 0, 4, 4).copy_within(
524 Rect {
525 x: 1,
526 y: 0,
527 width: 4,
528 height: 4
529 },
530 0,
531 0
532 ));
533 assert!(!image.sub_image(0, 0, 4, 4).copy_within(
534 Rect {
535 x: 0,
536 y: 0,
537 width: 4,
538 height: 4
539 },
540 1,
541 0
542 ));
543 assert!(!image.sub_image(0, 0, 4, 4).copy_within(
544 Rect {
545 x: 0,
546 y: 1,
547 width: 4,
548 height: 4
549 },
550 0,
551 0
552 ));
553 assert!(!image.sub_image(0, 0, 4, 4).copy_within(
554 Rect {
555 x: 0,
556 y: 0,
557 width: 4,
558 height: 4
559 },
560 0,
561 1
562 ));
563 assert!(!image.sub_image(0, 0, 4, 4).copy_within(
564 Rect {
565 x: 1,
566 y: 1,
567 width: 4,
568 height: 4
569 },
570 0,
571 0
572 ));
573 }
574
575 #[test]
576 fn test_generic_image_copy_within_tl() {
577 let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
578 let expected = [0, 1, 2, 3, 4, 0, 1, 2, 8, 4, 5, 6, 12, 8, 9, 10];
579 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
580 assert!(image.sub_image(0, 0, 4, 4).copy_within(
581 Rect {
582 x: 0,
583 y: 0,
584 width: 3,
585 height: 3
586 },
587 1,
588 1
589 ));
590 assert_eq!(&image.into_raw(), &expected);
591 }
592
593 #[test]
594 fn test_generic_image_copy_within_tr() {
595 let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
596 let expected = [0, 1, 2, 3, 1, 2, 3, 7, 5, 6, 7, 11, 9, 10, 11, 15];
597 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
598 assert!(image.sub_image(0, 0, 4, 4).copy_within(
599 Rect {
600 x: 1,
601 y: 0,
602 width: 3,
603 height: 3
604 },
605 0,
606 1
607 ));
608 assert_eq!(&image.into_raw(), &expected);
609 }
610
611 #[test]
612 fn test_generic_image_copy_within_bl() {
613 let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
614 let expected = [0, 4, 5, 6, 4, 8, 9, 10, 8, 12, 13, 14, 12, 13, 14, 15];
615 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
616 assert!(image.sub_image(0, 0, 4, 4).copy_within(
617 Rect {
618 x: 0,
619 y: 1,
620 width: 3,
621 height: 3
622 },
623 1,
624 0
625 ));
626 assert_eq!(&image.into_raw(), &expected);
627 }
628
629 #[test]
630 fn test_generic_image_copy_within_br() {
631 let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
632 let expected = [5, 6, 7, 3, 9, 10, 11, 7, 13, 14, 15, 11, 12, 13, 14, 15];
633 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
634 assert!(image.sub_image(0, 0, 4, 4).copy_within(
635 Rect {
636 x: 1,
637 y: 1,
638 width: 3,
639 height: 3
640 },
641 0,
642 0
643 ));
644 assert_eq!(&image.into_raw(), &expected);
645 }
646}