1use std::fmt::{Debug, Display, Formatter};
11use std::iter::{self, FusedIterator};
12use std::marker::PhantomData;
13use std::mem::size_of;
14use std::ops::{Index, IndexMut, Range};
15
16use aligned_vec::{ABox, AVec, ConstAlign};
17
18use crate::math::*;
19use crate::pixel::*;
20
21#[cfg(feature = "serialize")]
22use serde::{Deserialize, Serialize};
23
24#[derive(Debug, Clone, PartialEq, Eq)]
26#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
27pub struct PlaneConfig {
28 pub stride: usize,
30 pub alloc_height: usize,
32 pub width: usize,
34 pub height: usize,
36 pub xdec: usize,
40 pub ydec: usize,
44 pub xpad: usize,
46 pub ypad: usize,
48 pub xorigin: usize,
50 pub yorigin: usize,
52}
53
54impl PlaneConfig {
55 const STRIDE_ALIGNMENT_LOG2: usize = 6;
57
58 #[inline]
59 pub fn new(
60 width: usize,
61 height: usize,
62 xdec: usize,
63 ydec: usize,
64 xpad: usize,
65 ypad: usize,
66 type_size: usize,
67 ) -> Self {
68 let xorigin = xpad.align_power_of_two(Self::STRIDE_ALIGNMENT_LOG2 + 1 - type_size);
69 let yorigin = ypad;
70 let stride = (xorigin + width + xpad)
71 .align_power_of_two(Self::STRIDE_ALIGNMENT_LOG2 + 1 - type_size);
72 let alloc_height = yorigin + height + ypad;
73
74 PlaneConfig {
75 stride,
76 alloc_height,
77 width,
78 height,
79 xdec,
80 ydec,
81 xpad,
82 ypad,
83 xorigin,
84 yorigin,
85 }
86 }
87}
88
89#[derive(Clone, Copy, Debug, Default)]
91pub struct PlaneOffset {
92 pub x: isize,
93 pub y: isize,
94}
95
96#[derive(Debug, Clone, PartialEq, Eq)]
101#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
102pub struct PlaneData<T: Pixel> {
103 #[cfg(not(target_arch = "wasm32"))]
104 data: ABox<[T], ConstAlign<{ 1 << 6 }>>,
105 #[cfg(target_arch = "wasm32")]
106 data: ABox<[T], ConstAlign<{ 1 << 3 }>>,
107}
108
109unsafe impl<T: Pixel + Send> Send for PlaneData<T> {}
110unsafe impl<T: Pixel + Sync> Sync for PlaneData<T> {}
111
112impl<T: Pixel> std::ops::Deref for PlaneData<T> {
113 type Target = [T];
114
115 fn deref(&self) -> &[T] {
116 self.data.as_ref()
117 }
118}
119
120impl<T: Pixel> std::ops::DerefMut for PlaneData<T> {
121 fn deref_mut(&mut self) -> &mut [T] {
122 self.data.as_mut()
123 }
124}
125
126impl<T: Pixel> PlaneData<T> {
127 #[cfg(target_arch = "wasm32")]
128 const DATA_ALIGNMENT: usize = 1 << 3;
130 #[cfg(not(target_arch = "wasm32"))]
131 const DATA_ALIGNMENT: usize = 1 << 6;
132
133 pub fn new(len: usize) -> Self {
134 Self {
135 data: AVec::from_iter(
136 Self::DATA_ALIGNMENT,
137 iter::repeat(T::cast_from(128)).take(len),
138 )
139 .into_boxed_slice(),
140 }
141 }
142
143 fn from_slice(data: &[T]) -> Self {
144 Self {
145 data: AVec::from_slice(Self::DATA_ALIGNMENT, data).into_boxed_slice(),
146 }
147 }
148}
149
150#[derive(Clone, PartialEq, Eq)]
154#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
155pub struct Plane<T: Pixel> {
156 pub data: PlaneData<T>,
160 pub cfg: PlaneConfig,
162}
163
164impl<T: Pixel> Debug for Plane<T>
165where
166 T: Display,
167{
168 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
169 write!(
170 f,
171 "Plane {{ data: [{}, ...], cfg: {:?} }}",
172 self.data[0], self.cfg
173 )
174 }
175}
176
177impl<T: Pixel> Plane<T> {
178 pub fn new(
180 width: usize,
181 height: usize,
182 xdec: usize,
183 ydec: usize,
184 xpad: usize,
185 ypad: usize,
186 ) -> Self {
187 let cfg = PlaneConfig::new(width, height, xdec, ydec, xpad, ypad, size_of::<T>());
188 let data = PlaneData::new(cfg.stride * cfg.alloc_height);
189
190 Plane { data, cfg }
191 }
192
193 pub fn from_slice(data: &[T], stride: usize) -> Self {
197 let len = data.len();
198
199 assert!(len % stride == 0);
200
201 Self {
202 data: PlaneData::from_slice(data),
203 cfg: PlaneConfig {
204 stride,
205 alloc_height: len / stride,
206 width: stride,
207 height: len / stride,
208 xdec: 0,
209 ydec: 0,
210 xpad: 0,
211 ypad: 0,
212 xorigin: 0,
213 yorigin: 0,
214 },
215 }
216 }
217
218 pub fn pad(&mut self, w: usize, h: usize) {
219 let xorigin = self.cfg.xorigin;
220 let yorigin = self.cfg.yorigin;
221 let stride = self.cfg.stride;
222 let alloc_height = self.cfg.alloc_height;
223 let width = (w + self.cfg.xdec) >> self.cfg.xdec;
224 let height = (h + self.cfg.ydec) >> self.cfg.ydec;
225
226 if xorigin > 0 {
227 for y in 0..height {
228 let base = (yorigin + y) * stride;
229 let fill_val = self.data[base + xorigin];
230 for val in &mut self.data[base..base + xorigin] {
231 *val = fill_val;
232 }
233 }
234 }
235
236 if xorigin + width < stride {
237 for y in 0..height {
238 let base = (yorigin + y) * stride + xorigin + width;
239 let fill_val = self.data[base - 1];
240 for val in &mut self.data[base..base + stride - (xorigin + width)] {
241 *val = fill_val;
242 }
243 }
244 }
245
246 if yorigin > 0 {
247 let (top, bottom) = self.data.split_at_mut(yorigin * stride);
248 let src = &bottom[..stride];
249 for y in 0..yorigin {
250 let dst = &mut top[y * stride..(y + 1) * stride];
251 dst.copy_from_slice(src);
252 }
253 }
254
255 if yorigin + height < self.cfg.alloc_height {
256 let (top, bottom) = self.data.split_at_mut((yorigin + height) * stride);
257 let src = &top[(yorigin + height - 1) * stride..];
258 for y in 0..alloc_height - (yorigin + height) {
259 let dst = &mut bottom[y * stride..(y + 1) * stride];
260 dst.copy_from_slice(src);
261 }
262 }
263 }
264
265 pub fn probe_padding(&self, w: usize, h: usize) -> bool {
267 let PlaneConfig {
268 xorigin,
269 yorigin,
270 stride,
271 alloc_height,
272 xdec,
273 ydec,
274 ..
275 } = self.cfg;
276 let width = (w + xdec) >> xdec;
277 let height = (h + ydec) >> ydec;
278 let corner = (yorigin + height - 1) * stride + xorigin + width - 1;
279 let corner_value = self.data[corner];
280
281 self.data[(yorigin + height) * stride - 1] == corner_value
282 && self.data[(alloc_height - 1) * stride + xorigin + width - 1] == corner_value
283 && self.data[alloc_height * stride - 1] == corner_value
284 }
285
286 pub fn slice(&self, po: PlaneOffset) -> PlaneSlice<'_, T> {
287 PlaneSlice {
288 plane: self,
289 x: po.x,
290 y: po.y,
291 }
292 }
293
294 pub fn mut_slice(&mut self, po: PlaneOffset) -> PlaneMutSlice<'_, T> {
295 PlaneMutSlice {
296 plane: self,
297 x: po.x,
298 y: po.y,
299 }
300 }
301
302 #[inline]
303 fn index(&self, x: usize, y: usize) -> usize {
304 (y + self.cfg.yorigin) * self.cfg.stride + (x + self.cfg.xorigin)
305 }
306
307 #[inline]
309 pub fn row_range_cropped(&self, x: isize, y: isize) -> Range<usize> {
310 debug_assert!(self.cfg.yorigin as isize + y >= 0);
311 debug_assert!(self.cfg.xorigin as isize + x >= 0);
312 let base_y = (self.cfg.yorigin as isize + y) as usize;
313 let base_x = (self.cfg.xorigin as isize + x) as usize;
314 let base = base_y * self.cfg.stride + base_x;
315 let width = (self.cfg.width as isize - x) as usize;
316 base..base + width
317 }
318
319 #[inline]
321 pub fn row_range(&self, x: isize, y: isize) -> Range<usize> {
322 debug_assert!(self.cfg.yorigin as isize + y >= 0);
323 debug_assert!(self.cfg.xorigin as isize + x >= 0);
324 let base_y = (self.cfg.yorigin as isize + y) as usize;
325 let base_x = (self.cfg.xorigin as isize + x) as usize;
326 let base = base_y * self.cfg.stride + base_x;
327 let width = self.cfg.stride - base_x;
328 base..base + width
329 }
330
331 pub fn p(&self, x: usize, y: usize) -> T {
333 self.data[self.index(x, y)]
334 }
335
336 pub fn data_origin(&self) -> &[T] {
338 &self.data[self.index(0, 0)..]
339 }
340
341 pub fn data_origin_mut(&mut self) -> &mut [T] {
343 let i = self.index(0, 0);
344 &mut self.data[i..]
345 }
346
347 pub fn copy_from_raw_u8(
353 &mut self,
354 source: &[u8],
355 source_stride: usize,
356 source_bytewidth: usize,
357 ) {
358 let stride = self.cfg.stride;
359
360 assert!(stride != 0);
361 assert!(source_stride != 0);
362
363 for (self_row, source_row) in self
364 .data_origin_mut()
365 .chunks_exact_mut(stride)
366 .zip(source.chunks_exact(source_stride))
367 {
368 match source_bytewidth {
369 1 => {
370 for (self_pixel, source_pixel) in self_row.iter_mut().zip(source_row.iter()) {
371 *self_pixel = T::cast_from(*source_pixel);
372 }
373 }
374 2 => {
375 assert!(
376 size_of::<T>() == 2,
377 "source bytewidth ({}) cannot fit in Plane<u8>",
378 source_bytewidth
379 );
380
381 debug_assert!(T::type_enum() == PixelType::U16);
382
383 let self_row: &mut [u16] = unsafe { std::mem::transmute(self_row) };
385 let source_row: &[[u8; 2]] = unsafe {
388 std::slice::from_raw_parts(source_row.as_ptr().cast(), source_row.len() / 2)
389 };
390
391 for (self_pixel, bytes) in self_row.iter_mut().zip(source_row) {
392 *self_pixel = u16::from_le_bytes(*bytes);
393 }
394 }
395
396 _ => {}
397 }
398 }
399 }
400
401 pub fn copy_to_raw_u8(&self, dest: &mut [u8], dest_stride: usize, dest_bytewidth: usize) {
407 let stride = self.cfg.stride;
408 for (self_row, dest_row) in self
409 .data_origin()
410 .chunks_exact(stride)
411 .zip(dest.chunks_exact_mut(dest_stride))
412 {
413 match dest_bytewidth {
414 1 => {
415 for (self_pixel, dest_pixel) in
416 self_row[..self.cfg.width].iter().zip(dest_row.iter_mut())
417 {
418 *dest_pixel = u8::cast_from(*self_pixel);
419 }
420 }
421 2 => {
422 assert!(
423 size_of::<T>() >= 2,
424 "dest bytewidth ({}) cannot fit in Plane<u8>",
425 dest_bytewidth
426 );
427
428 let dest_row: &mut [[u8; 2]] = unsafe {
431 std::slice::from_raw_parts_mut(
432 dest_row.as_mut_ptr().cast(),
433 dest_row.len() / 2,
434 )
435 };
436
437 for (self_pixel, bytes) in self_row[..self.cfg.width].iter().zip(dest_row) {
438 *bytes = u16::cast_from(*self_pixel).to_le_bytes();
439 }
440 }
441
442 _ => {}
443 }
444 }
445 }
446
447 pub fn downsampled(&self, frame_width: usize, frame_height: usize) -> Plane<T> {
455 let src = self;
456 let mut new = Plane::new(
457 (src.cfg.width + 1) / 2,
458 (src.cfg.height + 1) / 2,
459 src.cfg.xdec + 1,
460 src.cfg.ydec + 1,
461 src.cfg.xpad / 2,
462 src.cfg.ypad / 2,
463 );
464
465 let width = new.cfg.width;
466 let height = new.cfg.height;
467
468 assert!(width * 2 <= src.cfg.stride - src.cfg.xorigin);
469 assert!(height * 2 <= src.cfg.alloc_height - src.cfg.yorigin);
470
471 let data_origin = src.data_origin();
472 for (row_idx, dst_row) in new
473 .mut_slice(PlaneOffset::default())
474 .rows_iter_mut()
475 .enumerate()
476 .take(height)
477 {
478 let src_top_row = &data_origin[(src.cfg.stride * row_idx * 2)..][..(2 * width)];
479 let src_bottom_row =
480 &data_origin[(src.cfg.stride * (row_idx * 2 + 1))..][..(2 * width)];
481
482 for ((dst, a), b) in dst_row
483 .iter_mut()
484 .zip(src_top_row.chunks_exact(2))
485 .zip(src_bottom_row.chunks_exact(2))
486 {
487 let sum = u32::cast_from(a[0])
488 + u32::cast_from(a[1])
489 + u32::cast_from(b[0])
490 + u32::cast_from(b[1]);
491 let avg = (sum + 2) >> 2;
492 *dst = T::cast_from(avg);
493 }
494 }
495
496 new.pad(frame_width, frame_height);
497 new
498 }
499
500 pub fn downscale<const SCALE: usize>(&self) -> Plane<T> {
502 let mut new_plane = Plane::new(self.cfg.width / SCALE, self.cfg.height / SCALE, 0, 0, 0, 0);
503
504 self.downscale_in_place::<SCALE>(&mut new_plane);
505
506 new_plane
507 }
508
509 #[cfg_attr(feature = "profiling", profiling::function(downscale_in_place))]
515 pub fn downscale_in_place<const SCALE: usize>(&self, in_plane: &mut Plane<T>) {
516 let stride = in_plane.cfg.stride;
517 let width = in_plane.cfg.width;
518 let height = in_plane.cfg.height;
519
520 if stride == 0 || self.cfg.stride == 0 {
521 panic!("stride cannot be 0");
522 }
523
524 assert!(width * SCALE <= self.cfg.stride - self.cfg.xorigin);
525 assert!(height * SCALE <= self.cfg.alloc_height - self.cfg.yorigin);
526
527 unsafe {
529 let src = self;
530 let box_pixels = SCALE * SCALE;
531 let half_box_pixels = box_pixels as u32 / 2; let data_origin = src.data_origin();
534 let plane_data_mut_slice = &mut *in_plane.data;
535
536 for row_idx in 0..height {
538 let dst_row = plane_data_mut_slice.get_unchecked_mut(row_idx * stride..);
539 for (col_idx, dst) in dst_row.get_unchecked_mut(..width).iter_mut().enumerate() {
541 macro_rules! generate_inner_loop {
542 ($x:ty) => {
543 let mut sum = half_box_pixels as $x;
544 for y in 0..SCALE {
548 let src_row_idx = row_idx * SCALE + y;
549 let src_row =
550 data_origin.get_unchecked((src_row_idx * src.cfg.stride)..);
551
552 for x in 0..SCALE {
554 let src_col_idx = col_idx * SCALE + x;
555 sum += <$x>::cast_from(*src_row.get_unchecked(src_col_idx));
556 }
557 }
558
559 let avg = sum as usize / box_pixels;
561 *dst = T::cast_from(avg);
562 };
563 }
564
565 if T::type_enum() == PixelType::U8
567 && SCALE as u128 * SCALE as u128 * (u8::MAX as u128)
568 + half_box_pixels as u128
569 <= u16::MAX as u128
570 {
571 generate_inner_loop!(u16);
572 } else {
573 generate_inner_loop!(u32);
574 }
575 }
576 }
577 }
578 }
579
580 pub fn iter(&self) -> PlaneIter<'_, T> {
582 PlaneIter::new(self)
583 }
584
585 pub fn rows_iter(&self) -> RowsIter<'_, T> {
587 RowsIter {
588 plane: self,
589 x: 0,
590 y: 0,
591 }
592 }
593
594 pub fn rows_iter_mut(&mut self) -> RowsIterMut<'_, T> {
595 RowsIterMut {
596 plane: self as *mut Plane<T>,
597 x: 0,
598 y: 0,
599 phantom: PhantomData,
600 }
601 }
602
603 pub fn row(&self, y: isize) -> &[T] {
605 let range = self.row_range(0, y);
606
607 &self.data[range]
608 }
609}
610
611#[derive(Debug)]
613pub struct PlaneIter<'a, T: Pixel> {
614 plane: &'a Plane<T>,
615 y: usize,
616 x: usize,
617}
618
619impl<'a, T: Pixel> PlaneIter<'a, T> {
620 pub fn new(plane: &'a Plane<T>) -> Self {
622 Self { plane, y: 0, x: 0 }
623 }
624
625 fn width(&self) -> usize {
626 self.plane.cfg.width
627 }
628
629 fn height(&self) -> usize {
630 self.plane.cfg.height
631 }
632}
633
634impl<T: Pixel> Iterator for PlaneIter<'_, T> {
635 type Item = T;
636
637 fn next(&mut self) -> Option<<Self as Iterator>::Item> {
638 if self.y == self.height() {
639 return None;
640 }
641 let pixel = self.plane.p(self.x, self.y);
642 if self.x == self.width() - 1 {
643 self.x = 0;
644 self.y += 1;
645 } else {
646 self.x += 1;
647 }
648 Some(pixel)
649 }
650}
651
652impl<T: Pixel> FusedIterator for PlaneIter<'_, T> {}
653
654#[derive(Clone, Copy, Debug)]
657pub struct PlaneSlice<'a, T: Pixel> {
658 pub plane: &'a Plane<T>,
659 pub x: isize,
660 pub y: isize,
661}
662
663pub struct RowsIter<'a, T: Pixel> {
665 plane: &'a Plane<T>,
666 x: isize,
667 y: isize,
668}
669
670impl<'a, T: Pixel> Iterator for RowsIter<'a, T> {
671 type Item = &'a [T];
672
673 fn next(&mut self) -> Option<Self::Item> {
674 if self.plane.cfg.height as isize > self.y {
675 let range = self.plane.row_range_cropped(self.x, self.y);
677 self.y += 1;
678 Some(&self.plane.data[range])
679 } else {
680 None
681 }
682 }
683
684 fn size_hint(&self) -> (usize, Option<usize>) {
685 let remaining = self.plane.cfg.height as isize - self.y;
686 debug_assert!(remaining >= 0);
687 let remaining = remaining as usize;
688
689 (remaining, Some(remaining))
690 }
691}
692
693impl<T: Pixel> ExactSizeIterator for RowsIter<'_, T> {}
694impl<T: Pixel> FusedIterator for RowsIter<'_, T> {}
695
696impl<'a, T: Pixel> PlaneSlice<'a, T> {
697 #[allow(unused)]
698 pub fn as_ptr(&self) -> *const T {
699 self[0].as_ptr()
700 }
701
702 pub fn rows_iter(&self) -> RowsIter<'_, T> {
703 RowsIter {
704 plane: self.plane,
705 x: self.x,
706 y: self.y,
707 }
708 }
709
710 pub fn clamp(&self) -> PlaneSlice<'a, T> {
711 PlaneSlice {
712 plane: self.plane,
713 x: self.x.clamp(
714 -(self.plane.cfg.xorigin as isize),
715 self.plane.cfg.width as isize,
716 ),
717 y: self.y.clamp(
718 -(self.plane.cfg.yorigin as isize),
719 self.plane.cfg.height as isize,
720 ),
721 }
722 }
723
724 pub fn subslice(&self, xo: usize, yo: usize) -> PlaneSlice<'a, T> {
725 PlaneSlice {
726 plane: self.plane,
727 x: self.x + xo as isize,
728 y: self.y + yo as isize,
729 }
730 }
731
732 pub fn reslice(&self, xo: isize, yo: isize) -> PlaneSlice<'a, T> {
733 PlaneSlice {
734 plane: self.plane,
735 x: self.x + xo,
736 y: self.y + yo,
737 }
738 }
739
740 pub fn go_up(&self, i: usize) -> PlaneSlice<'a, T> {
742 PlaneSlice {
743 plane: self.plane,
744 x: self.x,
745 y: self.y - i as isize,
746 }
747 }
748
749 pub fn go_left(&self, i: usize) -> PlaneSlice<'a, T> {
751 PlaneSlice {
752 plane: self.plane,
753 x: self.x - i as isize,
754 y: self.y,
755 }
756 }
757
758 pub fn p(&self, add_x: usize, add_y: usize) -> T {
759 let new_y = (self.y + add_y as isize + self.plane.cfg.yorigin as isize) as usize;
760 let new_x = (self.x + add_x as isize + self.plane.cfg.xorigin as isize) as usize;
761 self.plane.data[new_y * self.plane.cfg.stride + new_x]
762 }
763
764 pub fn accessible(&self, add_x: usize, add_y: usize) -> bool {
767 let y = (self.y + add_y as isize + self.plane.cfg.yorigin as isize) as usize;
768 let x = (self.x + add_x as isize + self.plane.cfg.xorigin as isize) as usize;
769 y < self.plane.cfg.alloc_height && x < self.plane.cfg.stride
770 }
771
772 pub fn accessible_neg(&self, sub_x: usize, sub_y: usize) -> bool {
775 let y = self.y - sub_y as isize + self.plane.cfg.yorigin as isize;
776 let x = self.x - sub_x as isize + self.plane.cfg.xorigin as isize;
777 y >= 0 && x >= 0
778 }
779
780 pub fn row_cropped(&self, y: usize) -> &[T] {
782 let y = (self.y + y as isize + self.plane.cfg.yorigin as isize) as usize;
783 let x = (self.x + self.plane.cfg.xorigin as isize) as usize;
784 let start = y * self.plane.cfg.stride + x;
785 let width = (self.plane.cfg.width as isize - self.x) as usize;
786 &self.plane.data[start..start + width]
787 }
788
789 pub fn row(&self, y: usize) -> &[T] {
791 let y = (self.y + y as isize + self.plane.cfg.yorigin as isize) as usize;
792 let x = (self.x + self.plane.cfg.xorigin as isize) as usize;
793 let start = y * self.plane.cfg.stride + x;
794 let width = self.plane.cfg.stride - x;
795 &self.plane.data[start..start + width]
796 }
797}
798
799impl<T: Pixel> Index<usize> for PlaneSlice<'_, T> {
800 type Output = [T];
801 fn index(&self, index: usize) -> &Self::Output {
802 let range = self.plane.row_range(self.x, self.y + index as isize);
803 &self.plane.data[range]
804 }
805}
806
807pub struct PlaneMutSlice<'a, T: Pixel> {
808 pub plane: &'a mut Plane<T>,
809 pub x: isize,
810 pub y: isize,
811}
812
813pub struct RowsIterMut<'a, T: Pixel> {
814 plane: *mut Plane<T>,
815 x: isize,
816 y: isize,
817 phantom: PhantomData<&'a mut Plane<T>>,
818}
819
820impl<'a, T: Pixel> Iterator for RowsIterMut<'a, T> {
821 type Item = &'a mut [T];
822
823 fn next(&mut self) -> Option<Self::Item> {
824 let plane = unsafe { &mut *self.plane };
826 if plane.cfg.height as isize > self.y {
827 let range = plane.row_range_cropped(self.x, self.y);
829 self.y += 1;
830 Some(&mut plane.data[range])
831 } else {
832 None
833 }
834 }
835
836 fn size_hint(&self) -> (usize, Option<usize>) {
837 let plane = unsafe { &mut *self.plane };
839 let remaining = plane.cfg.height as isize - self.y;
840 debug_assert!(remaining >= 0);
841 let remaining = remaining as usize;
842
843 (remaining, Some(remaining))
844 }
845}
846
847impl<T: Pixel> ExactSizeIterator for RowsIterMut<'_, T> {}
848impl<T: Pixel> FusedIterator for RowsIterMut<'_, T> {}
849
850impl<T: Pixel> PlaneMutSlice<'_, T> {
851 #[allow(unused)]
852 pub fn rows_iter(&self) -> RowsIter<'_, T> {
853 RowsIter {
854 plane: self.plane,
855 x: self.x,
856 y: self.y,
857 }
858 }
859
860 pub fn rows_iter_mut(&mut self) -> RowsIterMut<'_, T> {
861 RowsIterMut {
862 plane: self.plane as *mut Plane<T>,
863 x: self.x,
864 y: self.y,
865 phantom: PhantomData,
866 }
867 }
868
869 #[allow(unused)]
870 pub fn subslice(&mut self, xo: usize, yo: usize) -> PlaneMutSlice<'_, T> {
871 PlaneMutSlice {
872 plane: self.plane,
873 x: self.x + xo as isize,
874 y: self.y + yo as isize,
875 }
876 }
877}
878
879impl<T: Pixel> Index<usize> for PlaneMutSlice<'_, T> {
880 type Output = [T];
881 fn index(&self, index: usize) -> &Self::Output {
882 let range = self.plane.row_range(self.x, self.y + index as isize);
883 &self.plane.data[range]
884 }
885}
886
887impl<T: Pixel> IndexMut<usize> for PlaneMutSlice<'_, T> {
888 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
889 let range = self.plane.row_range(self.x, self.y + index as isize);
890 &mut self.plane.data[range]
891 }
892}
893
894#[cfg(test)]
895pub mod test {
896 use super::*;
897
898 #[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
899 use wasm_bindgen_test::*;
900
901 #[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
902 wasm_bindgen_test_configure!(run_in_browser);
903
904 #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), wasm_bindgen_test)]
905 #[test]
906 fn copy_from_raw_u8() {
907 #[rustfmt::skip]
908 let mut plane = Plane::from_slice(&[
909 0, 0, 0, 0, 0, 0, 0, 0,
910 0, 0, 0, 0, 0, 0, 0, 0,
911 0, 0, 0, 0, 0, 0, 0, 0,
912 0, 0, 1, 2, 3, 4, 0, 0,
913 0, 0, 8, 7, 6, 5, 0, 0,
914 0, 0, 9, 8, 7, 6, 0, 0,
915 0, 0, 2, 3, 4, 5, 0, 0,
916 0, 0, 0, 0, 0, 0, 0, 0,
917 0, 0, 0, 0, 0, 0, 0, 0,
918 ], 8);
919
920 let input = vec![42u8; 64];
921
922 plane.copy_from_raw_u8(&input, 8, 1);
923
924 println!("{:?}", &plane.data[..10]);
925
926 assert_eq!(&input[..64], &plane.data[..64]);
927 }
928
929 #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), wasm_bindgen_test)]
930 #[test]
931 fn copy_to_raw_u8() {
932 #[rustfmt::skip]
933 let plane = Plane::from_slice(&[
934 0, 0, 0, 0, 0, 0, 0, 0,
935 0, 0, 0, 0, 0, 0, 0, 0,
936 0, 0, 0, 0, 0, 0, 0, 0,
937 0, 0, 1, 2, 3, 4, 0, 0,
938 0, 0, 8, 7, 6, 5, 0, 0,
939 0, 0, 9, 8, 7, 6, 0, 0,
940 0, 0, 2, 3, 4, 5, 0, 0,
941 0, 0, 0, 0, 0, 0, 0, 0,
942 0, 0, 0, 0, 0, 0, 0, 0,
943 ], 8);
944
945 let mut output = vec![42u8; 64];
946
947 plane.copy_to_raw_u8(&mut output, 8, 1);
948
949 println!("{:?}", &plane.data[..10]);
950
951 assert_eq!(&output[..64], &plane.data[..64]);
952 }
953
954 #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), wasm_bindgen_test)]
955 #[test]
956 fn test_plane_downsample() {
957 #[rustfmt::skip]
958 let plane = Plane::<u8> {
959 data: PlaneData::from_slice(&[
960 0, 0, 0, 0, 0, 0, 0, 0,
961 0, 0, 0, 0, 0, 0, 0, 0,
962 0, 0, 0, 0, 0, 0, 0, 0,
963 0, 0, 1, 2, 3, 4, 0, 0,
964 0, 0, 8, 7, 6, 5, 0, 0,
965 0, 0, 9, 8, 7, 6, 0, 0,
966 0, 0, 2, 3, 4, 5, 0, 0,
967 0, 0, 0, 0, 0, 0, 0, 0,
968 0, 0, 0, 0, 0, 0, 0, 0,
969 ]),
970 cfg: PlaneConfig {
971 stride: 8,
972 alloc_height: 9,
973 width: 4,
974 height: 4,
975 xdec: 0,
976 ydec: 0,
977 xpad: 0,
978 ypad: 0,
979 xorigin: 2,
980 yorigin: 3,
981 },
982 };
983 let downsampled = plane.downsampled(4, 4);
984
985 #[rustfmt::skip]
986 let expected = &[
987 5, 5,
988 6, 6,
989 ];
990
991 let v: Vec<_> = downsampled.iter().collect();
992
993 assert_eq!(&expected[..], &v[..]);
994 }
995
996 #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), wasm_bindgen_test)]
997 #[test]
998 fn test_plane_downsample_odd() {
999 #[rustfmt::skip]
1000 let plane = Plane::<u8> {
1001 data: PlaneData::from_slice(&[
1002 0, 0, 0, 0, 0, 0, 0, 0,
1003 0, 0, 0, 0, 0, 0, 0, 0,
1004 0, 0, 0, 0, 0, 0, 0, 0,
1005 0, 0, 1, 2, 3, 4, 0, 0,
1006 0, 0, 8, 7, 6, 5, 0, 0,
1007 0, 0, 9, 8, 7, 6, 0, 0,
1008 0, 0, 2, 3, 4, 5, 0, 0,
1009 0, 0, 0, 0, 0, 0, 0, 0,
1010 0, 0, 0, 0, 0, 0, 0, 0,
1011 ]),
1012 cfg: PlaneConfig {
1013 stride: 8,
1014 alloc_height: 9,
1015 width: 3,
1016 height: 3,
1017 xdec: 0,
1018 ydec: 0,
1019 xpad: 0,
1020 ypad: 0,
1021 xorigin: 2,
1022 yorigin: 3,
1023 },
1024 };
1025 let downsampled = plane.downsampled(3, 3);
1026
1027 #[rustfmt::skip]
1028 let expected = &[
1029 5, 5,
1030 6, 6,
1031 ];
1032
1033 let v: Vec<_> = downsampled.iter().collect();
1034 assert_eq!(&expected[..], &v[..]);
1035 }
1036
1037 #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), wasm_bindgen_test)]
1038 #[test]
1039 fn test_plane_downscale() {
1040 #[rustfmt::skip]
1041 let plane = Plane::<u8> {
1042 data: PlaneData::from_slice(&[
1043 0, 0, 0, 0, 0, 0, 0, 0,
1044 0, 0, 0, 0, 0, 0, 0, 0,
1045 0, 0, 0, 0, 0, 0, 0, 0,
1046 0, 0, 0, 1, 4, 5, 0, 0,
1047 0, 0, 2, 3, 6, 7, 0, 0,
1048 0, 0, 8, 9, 7, 5, 0, 0,
1049 0, 0, 9, 8, 3, 1, 0, 0,
1050 0, 0, 0, 0, 0, 0, 0, 0,
1051 0, 0, 0, 0, 0, 0, 0, 0,
1052 ]),
1053 cfg: PlaneConfig {
1054 stride: 8,
1055 alloc_height: 9,
1056 width: 4,
1057 height: 4,
1058 xdec: 0,
1059 ydec: 0,
1060 xpad: 0,
1061 ypad: 0,
1062 xorigin: 2,
1063 yorigin: 3,
1064 },
1065 };
1066 let downscaled = plane.downscale::<2>();
1067
1068 #[rustfmt::skip]
1069 let expected = &[
1070 2, 6,
1071 9, 4
1072 ];
1073
1074 let v: Vec<_> = downscaled.iter().collect();
1075 assert_eq!(&expected[..], &v[..]);
1076 }
1077
1078 #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), wasm_bindgen_test)]
1079 #[test]
1080 fn test_plane_downscale_odd() {
1081 #[rustfmt::skip]
1082 let plane = Plane::<u8> {
1083 data: PlaneData::from_slice(&[
1084 1, 2, 3, 4, 1, 2, 3, 4,
1085 0, 0, 8, 7, 6, 5, 8, 7,
1086 6, 5, 8, 7, 6, 5, 8, 7,
1087 6, 5, 8, 7, 0, 0, 2, 3,
1088 4, 5, 0, 0, 9, 8, 7, 6,
1089 0, 0, 0, 0, 2, 3, 4, 5,
1090 0, 0, 0, 0, 2, 3, 4, 5,
1091 ]),
1092 cfg: PlaneConfig {
1093 stride: 8,
1094 alloc_height: 7,
1095 width: 8,
1096 height: 7,
1097 xdec: 0,
1098 ydec: 0,
1099 xpad: 0,
1100 ypad: 0,
1101 xorigin: 0,
1102 yorigin: 0,
1103 },
1104 };
1105
1106 let downscaled = plane.downscale::<3>();
1107
1108 #[rustfmt::skip]
1109 let expected = &[
1110 4, 5,
1111 3, 3
1112 ];
1113
1114 let v: Vec<_> = downscaled.iter().collect();
1115 assert_eq!(&expected[..], &v[..]);
1116 }
1117
1118 #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), wasm_bindgen_test)]
1119 #[test]
1120 fn test_plane_downscale_odd_2() {
1121 #[rustfmt::skip]
1122 let plane = Plane::<u8> {
1123 data: PlaneData::from_slice(&[
1124 9, 8, 3, 1, 0, 1, 4, 5, 0, 0,
1125 0, 1, 4, 5, 0, 0, 0, 0, 0, 0,
1126 0, 0, 0, 0, 0, 0, 0, 0, 9, 0,
1127 0, 2, 3, 6, 7, 0, 0, 0, 0, 0,
1128 0, 0, 8, 9, 7, 5, 0, 0, 0, 0,
1129 9, 8, 3, 1, 0, 1, 4, 5, 0, 0,
1130 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1131 0, 0, 0, 0, 0, 2, 3, 6, 7, 0,
1132 0, 0, 0, 0, 0, 0, 8, 9, 7, 5,
1133 0, 0, 0, 0, 9, 8, 3, 1, 0, 0
1134 ]),
1135 cfg: PlaneConfig {
1136 stride: 10,
1137 alloc_height: 10,
1138 width: 10,
1139 height: 10,
1140 xdec: 0,
1141 ydec: 0,
1142 xpad: 0,
1143 ypad: 0,
1144 xorigin: 0,
1145 yorigin: 0,
1146 },
1147 };
1148 let downscaled = plane.downscale::<3>();
1149
1150 #[rustfmt::skip]
1151 let expected = &[
1152 3, 1, 2,
1153 4, 4, 1,
1154 0, 0, 4,
1155 ];
1156
1157 let v: Vec<_> = downscaled.iter().collect();
1158 assert_eq!(&expected[..], &v[..]);
1159 }
1160
1161 #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), wasm_bindgen_test)]
1162 #[test]
1163 fn test_plane_pad() {
1164 #[rustfmt::skip]
1165 let mut plane = Plane::<u8> {
1166 data: PlaneData::from_slice(&[
1167 0, 0, 0, 0, 0, 0, 0, 0,
1168 0, 0, 0, 0, 0, 0, 0, 0,
1169 0, 0, 0, 0, 0, 0, 0, 0,
1170 0, 0, 1, 2, 3, 4, 0, 0,
1171 0, 0, 8, 7, 6, 5, 0, 0,
1172 0, 0, 9, 8, 7, 6, 0, 0,
1173 0, 0, 2, 3, 4, 5, 0, 0,
1174 0, 0, 0, 0, 0, 0, 0, 0,
1175 0, 0, 0, 0, 0, 0, 0, 0,
1176 ]),
1177 cfg: PlaneConfig {
1178 stride: 8,
1179 alloc_height: 9,
1180 width: 4,
1181 height: 4,
1182 xdec: 0,
1183 ydec: 0,
1184 xpad: 0,
1185 ypad: 0,
1186 xorigin: 2,
1187 yorigin: 3,
1188 },
1189 };
1190 plane.pad(4, 4);
1191
1192 #[rustfmt::skip]
1193 assert_eq!(&[
1194 1, 1, 1, 2, 3, 4, 4, 4,
1195 1, 1, 1, 2, 3, 4, 4, 4,
1196 1, 1, 1, 2, 3, 4, 4, 4,
1197 1, 1, 1, 2, 3, 4, 4, 4,
1198 8, 8, 8, 7, 6, 5, 5, 5,
1199 9, 9, 9, 8, 7, 6, 6, 6,
1200 2, 2, 2, 3, 4, 5, 5, 5,
1201 2, 2, 2, 3, 4, 5, 5, 5,
1202 2, 2, 2, 3, 4, 5, 5, 5,
1203 ], &plane.data[..]);
1204 }
1205
1206 #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), wasm_bindgen_test)]
1207 #[test]
1208 fn test_pixel_iterator() {
1209 #[rustfmt::skip]
1210 let plane = Plane::<u8> {
1211 data: PlaneData::from_slice(&[
1212 0, 0, 0, 0, 0, 0, 0, 0,
1213 0, 0, 0, 0, 0, 0, 0, 0,
1214 0, 0, 0, 0, 0, 0, 0, 0,
1215 0, 0, 1, 2, 3, 4, 0, 0,
1216 0, 0, 8, 7, 6, 5, 0, 0,
1217 0, 0, 9, 8, 7, 6, 0, 0,
1218 0, 0, 2, 3, 4, 5, 0, 0,
1219 0, 0, 0, 0, 0, 0, 0, 0,
1220 0, 0, 0, 0, 0, 0, 0, 0,
1221 ]),
1222 cfg: PlaneConfig {
1223 stride: 8,
1224 alloc_height: 9,
1225 width: 4,
1226 height: 4,
1227 xdec: 0,
1228 ydec: 0,
1229 xpad: 0,
1230 ypad: 0,
1231 xorigin: 2,
1232 yorigin: 3,
1233 },
1234 };
1235
1236 let pixels: Vec<u8> = plane.iter().collect();
1237
1238 assert_eq!(
1239 &[1, 2, 3, 4, 8, 7, 6, 5, 9, 8, 7, 6, 2, 3, 4, 5,][..],
1240 &pixels[..]
1241 );
1242 }
1243}