1#![no_std]
53
54extern crate alloc;
55#[cfg(test)]
56extern crate std;
57
58use alloc::borrow::{Cow, ToOwned};
59use alloc::vec::Vec;
60use core::slice;
61
62mod traits;
63
64mod iter;
65mod ops;
66pub use iter::*;
67
68pub type ImgVec<Pixel> = Img<Vec<Pixel>>;
74
75pub type ImgRef<'slice, Pixel> = Img<&'slice [Pixel]>;
80
81pub type ImgRefMut<'slice, Pixel> = Img<&'slice mut [Pixel]>;
85
86pub trait ImgExt<Pixel> {
94 #[cfg(feature = "deprecated")]
100 fn width_padded(&self) -> usize;
101
102 #[cfg(feature = "deprecated")]
109 fn height_padded(&self) -> usize;
110
111 #[cfg(feature = "deprecated")]
115 fn rows_padded(&self) -> slice::Chunks<'_, Pixel>;
116
117 fn as_ref(&self) -> ImgRef<Pixel>;
119}
120
121pub trait ImgExtMut<Pixel> {
129 #[cfg(feature = "deprecated")]
133 fn rows_padded_mut(&mut self) -> slice::ChunksMut<'_, Pixel>;
134
135 fn as_mut(&mut self) -> ImgRefMut<Pixel>;
137}
138
139#[derive(Debug, Copy, Clone)]
143pub struct Img<Container> {
144 #[deprecated(note = "Don't access struct fields directly. Use buf(), buf_mut() or into_buf()")]
148 #[cfg(feature = "deprecated")]
149 pub buf: Container,
150
151 #[cfg(not(feature = "deprecated"))]
152 buf: Container,
153
154 #[deprecated(note = "Don't access struct fields directly. Use stride()")]
158 #[cfg(feature = "deprecated")]
159 pub stride: usize,
160
161 #[cfg(not(feature = "deprecated"))]
162 stride: usize,
163
164 #[deprecated(note = "Don't access struct fields directly. Use width()")]
168 #[cfg(feature = "deprecated")]
169 pub width: u32,
170
171 #[cfg(not(feature = "deprecated"))]
172 width: u32,
173
174 #[deprecated(note = "Don't access struct fields directly. Use height()")]
176 #[cfg(feature = "deprecated")]
177 pub height: u32,
178
179 #[cfg(not(feature = "deprecated"))]
180 height: u32,
181}
182
183impl<Container> Img<Container> {
184 #[inline(always)]
188 #[allow(deprecated)]
189 pub const fn width(&self) -> usize { self.width as usize }
190
191 #[inline(always)]
193 #[allow(deprecated)]
194 pub const fn height(&self) -> usize { self.height as usize }
195
196 #[inline(always)]
201 #[allow(deprecated)]
202 pub const fn stride(&self) -> usize { self.stride }
203
204 #[inline(always)]
208 #[allow(deprecated)]
209 pub const fn buf(&self) -> &Container { &self.buf }
210
211 #[inline(always)]
215 #[allow(deprecated)]
216 pub fn buf_mut(&mut self) -> &mut Container { &mut self.buf }
217
218 #[inline(always)]
220 #[allow(deprecated)]
221 pub fn into_buf(self) -> Container { self.buf }
222
223 #[deprecated(note = "this was meant to be private, use new_buf() and/or rows()")]
224 #[cfg(feature = "deprecated")]
225 #[doc(hidden)]
226 pub fn rows_buf<'buf, T: 'buf>(&self, buf: &'buf [T]) -> RowsIter<'buf, T> {
227 self.rows_buf_internal(buf)
228 }
229
230 #[inline]
231 #[track_caller]
232 fn rows_buf_internal<'buf, T: 'buf>(&self, buf: &'buf [T]) -> RowsIter<'buf, T> {
233 let stride = self.stride();
234 debug_assert!(self.width() <= self.stride());
235 debug_assert!(buf.len() >= self.width() * self.height());
236 assert!(stride > 0);
237 let non_padded = &buf[0..stride * self.height() + self.width() - stride];
238 RowsIter {
239 width: self.width(),
240 inner: non_padded.chunks(stride),
241 }
242 }
243}
244
245impl<Pixel,Container> ImgExt<Pixel> for Img<Container> where Container: AsRef<[Pixel]> {
246 #[inline(always)]
247 #[cfg(feature = "deprecated")]
248 fn width_padded(&self) -> usize {
249 self.stride()
250 }
251
252 #[inline(always)]
253 #[cfg(feature = "deprecated")]
254 fn height_padded(&self) -> usize {
255 let len = self.buf().as_ref().len();
256 assert_eq!(0, len % self.stride());
257 len / self.stride()
258 }
259
260 #[inline(always)]
264 #[cfg(feature = "deprecated")]
265 fn rows_padded(&self) -> slice::Chunks<'_, Pixel> {
266 self.buf().as_ref().chunks(self.stride())
267 }
268
269 #[inline(always)]
270 #[allow(deprecated)]
271 fn as_ref(&self) -> ImgRef<Pixel> {
272 Img {
273 buf: self.buf.as_ref(),
274 width: self.width,
275 height: self.height,
276 stride: self.stride,
277 }
278 }
279}
280
281impl<Pixel,Container> ImgExtMut<Pixel> for Img<Container> where Container: AsMut<[Pixel]> {
282 #[inline]
290 #[must_use]
291 #[cfg(feature = "deprecated")]
292 fn rows_padded_mut(&mut self) -> slice::ChunksMut<'_, Pixel> {
293 let stride = self.stride();
294 self.buf_mut().as_mut().chunks_mut(stride)
295 }
296
297 #[inline(always)]
298 #[allow(deprecated)]
299 fn as_mut(&mut self) -> ImgRefMut<Pixel> {
300 Img {
301 buf: self.buf.as_mut(),
302 width: self.width,
303 height: self.height,
304 stride: self.stride,
305 }
306 }
307}
308
309#[inline]
310fn sub_image(left: usize, top: usize, width: usize, height: usize, stride: usize, buf_len: usize) -> (usize, usize, usize) {
311 let start = stride * top + left;
312 let full_strides_end = start + stride * height;
313 let end = if buf_len >= full_strides_end {
315 full_strides_end
316 } else {
317 debug_assert!(height > 0);
318 let min_strides_len = full_strides_end + width - stride;
319 debug_assert!(buf_len >= min_strides_len, "the buffer is too small to fit the subimage");
320 min_strides_len
322 };
323 (start, end, stride)
324}
325
326impl<'slice, T> ImgRef<'slice, T> {
327 #[inline]
334 #[must_use]
335 #[track_caller]
336 pub fn sub_image(&self, left: usize, top: usize, width: usize, height: usize) -> Self {
337 assert!(top + height <= self.height());
338 assert!(left + width <= self.width());
339 let (start, end, stride) = sub_image(left, top, width, height, self.stride(), self.buf().len());
340 let buf = &self.buf()[start..end];
341 Self::new_stride(buf, width, height, stride)
342 }
343
344 #[inline]
345 pub fn rows(&self) -> RowsIter<'slice, T> {
353 self.rows_buf_internal(self.buf())
354 }
355
356 #[deprecated(note = "Size of this buffer is unpredictable. Use .rows() instead")]
360 #[cfg(feature = "deprecated")]
361 #[doc(hidden)]
362 pub fn iter(&self) -> slice::Iter<'slice, T> {
363 self.buf().iter()
364 }
365}
366
367impl<'a, T: Clone> ImgRef<'a, T> {
368 #[allow(deprecated)]
374 #[must_use]
375 pub fn to_contiguous_buf(&self) -> (Cow<'a, [T]>, usize, usize) {
376 let width = self.width();
377 let height = self.height();
378 let stride = self.stride();
379 if width == stride {
380 return (Cow::Borrowed(self.buf), width, height);
381 }
382 let mut buf = Vec::with_capacity(width * height);
383 for row in self.rows() {
384 buf.extend_from_slice(row);
385 }
386 (Cow::Owned(buf), width, height)
387 }
388}
389
390impl<'slice, T> ImgRefMut<'slice, T> {
391 #[inline]
393 #[allow(deprecated)]
394 #[must_use]
395 pub fn sub_image(&'slice self, left: usize, top: usize, width: usize, height: usize) -> ImgRef<'slice, T> {
396 self.as_ref().sub_image(left, top, width, height)
397 }
398
399 #[inline]
403 #[allow(deprecated)]
404 #[must_use]
405 #[track_caller]
406 pub fn sub_image_mut(&mut self, left: usize, top: usize, width: usize, height: usize) -> ImgRefMut<'_, T> {
407 assert!(top + height <= self.height());
408 assert!(left + width <= self.width());
409 let (start, end, stride) = sub_image(left, top, width, height, self.stride(), self.buf.len());
410 let buf = &mut self.buf[start..end];
411 ImgRefMut::new_stride(buf, width, height, stride)
412 }
413
414 #[inline]
416 #[must_use]
417 pub fn as_ref(&self) -> ImgRef<'_, T> {
418 self.new_buf(self.buf().as_ref())
419 }
420}
421
422impl<'slice, T: Copy> ImgRef<'slice, T> {
423 #[inline]
431 #[track_caller]
432 pub fn pixels(&self) -> PixelsIter<'slice, T> {
433 PixelsIter::new(*self)
434 }
435}
436
437impl<'slice, T> ImgRef<'slice, T> {
438 #[inline]
446 pub fn pixels_ref(&self) -> PixelsRefIter<'slice, T> {
447 PixelsRefIter::new(*self)
448 }
449}
450
451impl<T: Copy> ImgRefMut<'_, T> {
452 #[inline]
458 pub fn pixels(&self) -> PixelsIter<'_, T> {
459 PixelsIter::new(self.as_ref())
460 }
461
462 #[inline]
467 pub fn pixels_mut(&mut self) -> PixelsIterMut<'_, T> {
468 PixelsIterMut::new(self)
469 }
470}
471
472impl<T: Copy> ImgVec<T> {
473 #[inline]
478 pub fn pixels(&self) -> PixelsIter<'_, T> {
479 PixelsIter::new(self.as_ref())
480 }
481
482 #[inline]
487 pub fn pixels_mut(&mut self) -> PixelsIterMut<'_, T> {
488 PixelsIterMut::new(&mut self.as_mut())
489 }
490}
491
492impl<T> ImgRefMut<'_, T> {
493 #[inline]
499 pub fn rows(&self) -> RowsIter<'_, T> {
500 self.rows_buf_internal(&self.buf()[..])
501 }
502
503 #[inline]
509 #[allow(deprecated)]
510 pub fn rows_mut(&mut self) -> RowsIterMut<'_, T> {
511 let stride = self.stride();
512 let width = self.width();
513 let height = self.height();
514 let non_padded = &mut self.buf[0..stride * height + width - stride];
515 RowsIterMut {
516 width,
517 inner: non_padded.chunks_mut(stride),
518 }
519 }
520}
521
522#[cfg(feature = "deprecated")]
524impl<Container> IntoIterator for Img<Container> where Container: IntoIterator {
525 type Item = Container::Item;
526 type IntoIter = Container::IntoIter;
527 fn into_iter(self) -> Container::IntoIter {
529 self.into_buf().into_iter()
530 }
531}
532
533impl<T> ImgVec<T> {
534 #[allow(deprecated)]
536 #[must_use]
537 #[track_caller]
538 pub fn sub_image_mut(&mut self, left: usize, top: usize, width: usize, height: usize) -> ImgRefMut<'_, T> {
539 assert!(top + height <= self.height());
540 assert!(left + width <= self.width());
541 let start = self.stride * top + left;
542 let min_buf_size = if self.height > 0 { self.stride * height + width - self.stride } else {0};
543 let buf = &mut self.buf[start .. start + min_buf_size];
544 Img::new_stride(buf, width, height, self.stride)
545 }
546
547 #[inline]
548 #[must_use]
549 pub fn sub_image(&self, left: usize, top: usize, width: usize, height: usize) -> ImgRef<'_, T> {
551 self.as_ref().sub_image(left, top, width, height)
552 }
553
554 #[inline]
560 #[must_use]
561 pub fn as_ref(&self) -> ImgRef<'_, T> {
562 self.new_buf(self.buf().as_ref())
563 }
564
565 #[inline]
571 pub fn as_mut(&mut self) -> ImgRefMut<'_, T> {
572 let width = self.width();
573 let height = self.height();
574 let stride = self.stride();
575 Img::new_stride(self.buf_mut().as_mut(), width, height, stride)
576 }
577
578 #[deprecated(note = "Size of this buffer may be unpredictable. Use .rows() instead")]
579 #[cfg(feature = "deprecated")]
580 #[doc(hidden)]
581 pub fn iter(&self) -> slice::Iter<'_, T> {
582 self.buf().iter()
583 }
584
585 #[inline]
591 pub fn rows(&self) -> RowsIter<'_, T> {
592 self.rows_buf_internal(self.buf())
593 }
594
595 #[inline]
601 #[allow(deprecated)]
602 pub fn rows_mut(&mut self) -> RowsIterMut<'_, T> {
603 let stride = self.stride();
604 let width = self.width();
605 let height = self.height();
606 let non_padded = &mut self.buf[0..stride * height + width - stride];
607 RowsIterMut {
608 width,
609 inner: non_padded.chunks_mut(stride),
610 }
611 }
612}
613
614impl<Container> Img<Container> {
615 #[inline]
621 #[allow(deprecated)]
622 #[track_caller]
623 pub fn new_stride(buf: Container, width: usize, height: usize, stride: usize) -> Self {
624 assert!(stride > 0);
625 assert!(stride >= width);
626 debug_assert!(height < u32::MAX as usize);
627 debug_assert!(width < u32::MAX as usize);
628 Self {
629 buf,
630 width: width as u32,
631 height: height as u32,
632 stride,
633 }
634 }
635
636 #[inline]
642 pub fn new(buf: Container, width: usize, height: usize) -> Self {
643 Self::new_stride(buf, width, height, width)
644 }
645}
646
647impl<T: Copy> Img<Vec<T>> {
648 #[allow(deprecated)]
653 #[must_use]
654 pub fn into_contiguous_buf(mut self) -> (Vec<T>, usize, usize) {
655 let (_, w, h) = self.as_contiguous_buf();
656 (self.buf, w, h)
657 }
658
659 #[allow(deprecated)]
664 #[must_use]
665 pub fn as_contiguous_buf(&mut self) -> (&[T], usize, usize) {
666 let width = self.width();
667 let height = self.height();
668 let stride = self.stride();
669 if width != stride {
670 for row in 1..height {
671 self.buf.copy_within(row * stride .. row * stride + width, row * width);
672 }
673 }
674 self.buf.truncate(width * height);
675 (&mut self.buf, width, height)
676 }
677}
678
679impl<OldContainer> Img<OldContainer> {
680 #[inline]
682 #[track_caller]
683 pub fn map_buf<NewContainer, OldPixel, NewPixel, F>(self, callback: F) -> Img<NewContainer>
684 where NewContainer: AsRef<[NewPixel]>, OldContainer: AsRef<[OldPixel]>, F: FnOnce(OldContainer) -> NewContainer {
685 let width = self.width();
686 let height = self.height();
687 let stride = self.stride();
688 let old_buf_len = self.buf().as_ref().len();
689 #[allow(deprecated)]
690 let new_buf = callback(self.buf);
691 assert_eq!(old_buf_len, new_buf.as_ref().len());
692 Img::new_stride(new_buf, width, height, stride)
693 }
694
695 #[inline]
697 #[track_caller]
698 pub fn new_buf<NewContainer, OldPixel, NewPixel>(&self, new_buf: NewContainer) -> Img<NewContainer>
699 where NewContainer: AsRef<[NewPixel]>, OldContainer: AsRef<[OldPixel]> {
700 assert_eq!(self.buf().as_ref().len(), new_buf.as_ref().len());
701 Img::new_stride(new_buf, self.width(), self.height(), self.stride())
702 }
703}
704
705impl<T: Clone> From<Img<Cow<'_, [T]>>> for Img<Vec<T>> {
706 #[allow(deprecated)]
707 fn from(img: Img<Cow<'_, [T]>>) -> Self {
708 Self {
709 width: img.width,
710 height: img.height,
711 stride: img.stride,
712 buf: img.buf.into_owned(),
713 }
714 }
715}
716
717impl<T: Clone> From<ImgVec<T>> for Img<Cow<'static, [T]>> {
718 #[allow(deprecated)]
719 fn from(img: ImgVec<T>) -> Self {
720 Img {
721 width: img.width,
722 height: img.height,
723 stride: img.stride,
724 buf: img.buf.into(),
725 }
726 }
727}
728
729impl<'a, T: Clone> From<ImgRef<'a, T>> for Img<Cow<'a, [T]>> {
730 #[allow(deprecated)]
731 fn from(img: ImgRef<'a, T>) -> Self {
732 Img {
733 buf: img.buf.into(),
734 width: img.width,
735 height: img.height,
736 stride: img.stride,
737 }
738 }
739}
740
741impl<T: Clone> Img<Cow<'_, [T]>> {
742 #[allow(deprecated)]
746 #[must_use]
747 pub fn into_owned(self) -> ImgVec<T> {
748 match self.buf {
749 Cow::Borrowed(_) => {
750 let tmp = self.as_ref();
751 let (buf, w, h) = tmp.to_contiguous_buf();
752 ImgVec::new(buf.into_owned(), w, h)
753 },
754 Cow::Owned(buf) => Img {
755 buf,
756 width: self.width,
757 height: self.height,
758 stride: self.stride,
759 },
760 }
761 }
762}
763
764impl<T> Img<T> where T: ToOwned {
765 #[allow(deprecated)]
769 pub fn to_owned(&self) -> Img<T::Owned> {
770 Img {
771 buf: self.buf.to_owned(),
772 width: self.width,
773 height: self.height,
774 stride: self.stride,
775 }
776 }
777}
778
779#[cfg(test)]
780mod tests {
781 use super::*;
782 use alloc::vec;
783
784 mod with_opinionated_container {
785 use super::*;
786
787 struct IDontDeriveAnything;
788
789 #[test]
790 fn compiles() {
791 let _ = Img::new(IDontDeriveAnything, 1, 1);
792 }
793 }
794
795 #[test]
796 fn with_vec() {
797 let bytes = vec![0u8;20];
798 let old = Img::new_stride(bytes, 10,2,10);
799 let _ = old.new_buf(vec![6u16;20]);
800 }
801
802 #[test]
803 fn zero() {
804 let bytes = vec![0u8];
805 let mut img = Img::new_stride(bytes,0,0,1);
806 let _ = img.sub_image(0,0,0,0);
807 let _ = img.sub_image_mut(0,0,0,0);
808 let _ = img.as_ref();
809 }
810
811 #[test]
812 fn zero_width() {
813 let bytes = vec![0u8];
814 let mut img = Img::new_stride(bytes,0,1,1);
815 let _ = img.sub_image(0,1,0,0);
816 let _ = img.sub_image_mut(0,0,0,1);
817 }
818
819 #[test]
820 fn zero_height() {
821 let bytes = vec![0u8];
822 let mut img = Img::new_stride(bytes,1,0,1);
823 assert_eq!(0, img.rows().count());
824 let _ = img.sub_image(1,0,0,0);
825 let _ = img.sub_image_mut(0,0,1,0);
826 }
827
828 #[test]
829 #[allow(deprecated)]
830 fn with_slice() {
831 let bytes = vec![0u8;20];
832 let _ = Img::new_stride(bytes.as_slice(), 10,2,10);
833 let vec = ImgVec::new_stride(bytes, 10,2,10);
834
835 #[cfg(feature = "deprecated")]
836 for _ in vec.iter() {}
837
838 assert_eq!(2, vec.rows().count());
839 for _ in *vec.as_ref().buf() {}
840
841 #[cfg(feature = "deprecated")]
842 for _ in vec {}
843 }
844
845 #[test]
846 fn sub() {
847 let img = Img::new_stride(vec![1,2,3,4,
848 5,6,7,8,
849 9], 3, 2, 4);
850 assert_eq!(img.buf()[img.stride()], 5);
851 assert_eq!(img.buf()[img.stride() + img.width()-1], 7);
852
853 assert_eq!(img.pixels().count(), img.width() * img.height());
854 assert_eq!(img.pixels().sum::<i32>(), 24);
855
856 {
857 let refimg = img.as_ref();
858 let refimg2 = refimg; let s1 = refimg.sub_image(1, 0, refimg.width()-1, refimg.height());
862 let _ = s1.sub_image(1, 0, s1.width()-1, s1.height());
863
864 let subimg = refimg.sub_image(1, 1, 2, 1);
865 assert_eq!(subimg.pixels().count(), subimg.width() * subimg.height());
866
867 assert_eq!(subimg.buf()[0], 6);
868 assert_eq!(subimg.stride(), refimg2.stride());
869 assert!(subimg.stride() * subimg.height() + subimg.width() - subimg.stride() <= subimg.buf().len());
870 assert_eq!(refimg.buf()[0], 1);
871 assert_eq!(1, subimg.rows().count());
872 }
873
874 let mut img = img;
875 let mut subimg = img.sub_image_mut(1, 1, 2, 1);
876 assert_eq!(1, subimg.rows().count());
877 assert_eq!(1, subimg.rows_mut().count());
878 assert_eq!(1, subimg.rows_mut().rev().count());
879 assert_eq!(1, subimg.rows_mut().fuse().rev().count());
880 assert_eq!(subimg.buf()[0], 6);
881 }
882
883 #[test]
884 fn rows() {
885 let img = ImgVec::new_stride(vec![0u8; 10000], 10, 15, 100);
886 assert_eq!(img.height(), img.rows().count());
887 assert_eq!(img.height(), img.rows().rev().count());
888 assert_eq!(img.height(), img.rows().fuse().rev().count());
889 }
890
891 #[test]
892 fn mut_pixels() {
893 for y in 1..15 {
894 for x in 1..10 {
895 let mut img = ImgVec::new_stride(vec![0u8; 10000], x, y, 100);
896 assert_eq!(x*y, img.pixels_mut().count());
897 assert_eq!(x*y, img.as_mut().pixels().count());
898 assert_eq!(x*y, img.as_mut().pixels_mut().count());
899 assert_eq!(x*y, img.as_mut().as_ref().pixels().count());
900 }
901 }
902 }
903
904 #[test]
905 fn into_contiguous_buf() {
906 for in_h in [1, 2, 3, 38, 39, 40, 41].iter().copied() {
907 for in_w in [1, 2, 3, 120, 121].iter().copied() {
908 for stride in [in_w, 121, 122, 166, 242, 243].iter().copied() {
909 let img = ImgVec::new_stride((0..10000).map(|x| x as u8).collect(), in_w, in_h, stride)
910 .map_buf(|x| x);
911 let pixels: Vec<_> = img.pixels().collect();
912 let (buf, w, h) = img.into_contiguous_buf();
913 assert_eq!(pixels, buf);
914 assert_eq!(in_w*in_h, buf.len());
915 assert_eq!(10000, buf.capacity());
916 assert_eq!(in_w, w);
917 assert_eq!(in_h, h);
918 }
919 }
920 }
921
922 let img = ImgVec::new((0..55*33).map(|x| x as u8).collect(), 55, 33);
923 let pixels: Vec<_> = img.pixels().collect();
924 let tmp = img.as_ref();
925 let (buf, ..) = tmp.to_contiguous_buf();
926 assert_eq!(&pixels[..], &buf[..]);
927 let (buf, ..) = img.into_contiguous_buf();
928 assert_eq!(pixels, buf);
929 }
930}