Coverage Report

Created: 2025-07-01 06:50

/rust/registry/src/index.crates.io-6f17d22bba15001f/v_frame-0.3.9/src/plane.rs
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2017-2021, The rav1e contributors. All rights reserved
2
//
3
// This source code is subject to the terms of the BSD 2 Clause License and
4
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
5
// was not distributed with this source code in the LICENSE file, you can
6
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
7
// Media Patent License 1.0 was not distributed with this source code in the
8
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.
9
10
use std::fmt::{Debug, Display, Formatter};
11
use std::iter::{self, FusedIterator};
12
use std::marker::PhantomData;
13
use std::mem::size_of;
14
use std::ops::{Index, IndexMut, Range};
15
16
use aligned_vec::{ABox, AVec, ConstAlign};
17
18
use crate::math::*;
19
use crate::pixel::*;
20
21
#[cfg(feature = "serialize")]
22
use serde::{Deserialize, Serialize};
23
24
/// Plane-specific configuration.
25
#[derive(Debug, Clone, PartialEq, Eq)]
26
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
27
pub struct PlaneConfig {
28
    /// Data stride.
29
    pub stride: usize,
30
    /// Allocated height in pixels.
31
    pub alloc_height: usize,
32
    /// Width in pixels.
33
    pub width: usize,
34
    /// Height in pixels.
35
    pub height: usize,
36
    /// Decimator along the X axis.
37
    ///
38
    /// For example, for chroma planes in a 4:2:0 configuration this would be 1.
39
    pub xdec: usize,
40
    /// Decimator along the Y axis.
41
    ///
42
    /// For example, for chroma planes in a 4:2:0 configuration this would be 1.
43
    pub ydec: usize,
44
    /// Number of padding pixels on the right.
45
    pub xpad: usize,
46
    /// Number of padding pixels on the bottom.
47
    pub ypad: usize,
48
    /// X where the data starts.
49
    pub xorigin: usize,
50
    /// Y where the data starts.
51
    pub yorigin: usize,
52
}
53
54
impl PlaneConfig {
55
    /// Stride alignment in bytes.
56
    const STRIDE_ALIGNMENT_LOG2: usize = 6;
57
58
    #[inline]
59
0
    pub fn new(
60
0
        width: usize,
61
0
        height: usize,
62
0
        xdec: usize,
63
0
        ydec: usize,
64
0
        xpad: usize,
65
0
        ypad: usize,
66
0
        type_size: usize,
67
0
    ) -> Self {
68
0
        let xorigin = xpad.align_power_of_two(Self::STRIDE_ALIGNMENT_LOG2 + 1 - type_size);
69
0
        let yorigin = ypad;
70
0
        let stride = (xorigin + width + xpad)
71
0
            .align_power_of_two(Self::STRIDE_ALIGNMENT_LOG2 + 1 - type_size);
72
0
        let alloc_height = yorigin + height + ypad;
73
0
74
0
        PlaneConfig {
75
0
            stride,
76
0
            alloc_height,
77
0
            width,
78
0
            height,
79
0
            xdec,
80
0
            ydec,
81
0
            xpad,
82
0
            ypad,
83
0
            xorigin,
84
0
            yorigin,
85
0
        }
86
0
    }
Unexecuted instantiation: <v_frame::plane::PlaneConfig>::new
Unexecuted instantiation: <v_frame::plane::PlaneConfig>::new
Unexecuted instantiation: <v_frame::plane::PlaneConfig>::new
87
}
88
89
/// Absolute offset in pixels inside a plane
90
#[derive(Clone, Copy, Debug, Default)]
91
pub struct PlaneOffset {
92
    pub x: isize,
93
    pub y: isize,
94
}
95
96
/// Backing buffer for the Plane data
97
///
98
/// The buffer is padded and aligned according to the architecture-specific
99
/// SIMD constraints.
100
#[derive(Debug, Clone, PartialEq, Eq)]
101
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
102
pub 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
109
unsafe impl<T: Pixel + Send> Send for PlaneData<T> {}
110
unsafe impl<T: Pixel + Sync> Sync for PlaneData<T> {}
111
112
impl<T: Pixel> std::ops::Deref for PlaneData<T> {
113
    type Target = [T];
114
115
0
    fn deref(&self) -> &[T] {
116
0
        self.data.as_ref()
117
0
    }
Unexecuted instantiation: <v_frame::plane::PlaneData<u16> as core::ops::deref::Deref>::deref
Unexecuted instantiation: <v_frame::plane::PlaneData<u8> as core::ops::deref::Deref>::deref
Unexecuted instantiation: <v_frame::plane::PlaneData<_> as core::ops::deref::Deref>::deref
118
}
119
120
impl<T: Pixel> std::ops::DerefMut for PlaneData<T> {
121
0
    fn deref_mut(&mut self) -> &mut [T] {
122
0
        self.data.as_mut()
123
0
    }
Unexecuted instantiation: <v_frame::plane::PlaneData<u8> as core::ops::deref::DerefMut>::deref_mut
Unexecuted instantiation: <v_frame::plane::PlaneData<u16> as core::ops::deref::DerefMut>::deref_mut
Unexecuted instantiation: <v_frame::plane::PlaneData<_> as core::ops::deref::DerefMut>::deref_mut
124
}
125
126
impl<T: Pixel> PlaneData<T> {
127
    #[cfg(target_arch = "wasm32")]
128
    // FIXME: wasm32 allocator fails for alignment larger than 3
129
    const DATA_ALIGNMENT: usize = 1 << 3;
130
    #[cfg(not(target_arch = "wasm32"))]
131
    const DATA_ALIGNMENT: usize = 1 << 6;
132
133
0
    pub fn new(len: usize) -> Self {
134
0
        Self {
135
0
            data: AVec::from_iter(
136
0
                Self::DATA_ALIGNMENT,
137
0
                iter::repeat(T::cast_from(128)).take(len),
138
0
            )
139
0
            .into_boxed_slice(),
140
0
        }
141
0
    }
Unexecuted instantiation: <v_frame::plane::PlaneData<u8>>::new
Unexecuted instantiation: <v_frame::plane::PlaneData<u16>>::new
Unexecuted instantiation: <v_frame::plane::PlaneData<_>>::new
142
143
0
    fn from_slice(data: &[T]) -> Self {
144
0
        Self {
145
0
            data: AVec::from_slice(Self::DATA_ALIGNMENT, data).into_boxed_slice(),
146
0
        }
147
0
    }
148
}
149
150
/// One data plane of a frame.
151
///
152
/// For example, a plane can be a Y luma plane or a U or V chroma plane.
153
#[derive(Clone, PartialEq, Eq)]
154
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
155
pub struct Plane<T: Pixel> {
156
    // TODO: it is used by encoder to copy by plane and by tiling, make it
157
    // private again once tiling is moved and a copy_plane fn is added.
158
    //
159
    pub data: PlaneData<T>,
160
    /// Plane configuration.
161
    pub cfg: PlaneConfig,
162
}
163
164
impl<T: Pixel> Debug for Plane<T>
165
where
166
    T: Display,
167
{
168
0
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
169
0
        write!(
170
0
            f,
171
0
            "Plane {{ data: [{}, ...], cfg: {:?} }}",
172
0
            self.data[0], self.cfg
173
0
        )
174
0
    }
Unexecuted instantiation: <v_frame::plane::Plane<u8> as core::fmt::Debug>::fmt
Unexecuted instantiation: <v_frame::plane::Plane<_> as core::fmt::Debug>::fmt
175
}
176
177
impl<T: Pixel> Plane<T> {
178
    /// Allocates and returns a new plane.
179
0
    pub fn new(
180
0
        width: usize,
181
0
        height: usize,
182
0
        xdec: usize,
183
0
        ydec: usize,
184
0
        xpad: usize,
185
0
        ypad: usize,
186
0
    ) -> Self {
187
0
        let cfg = PlaneConfig::new(width, height, xdec, ydec, xpad, ypad, size_of::<T>());
188
0
        let data = PlaneData::new(cfg.stride * cfg.alloc_height);
189
0
190
0
        Plane { data, cfg }
191
0
    }
Unexecuted instantiation: <v_frame::plane::Plane<u8>>::new
Unexecuted instantiation: <v_frame::plane::Plane<u16>>::new
Unexecuted instantiation: <v_frame::plane::Plane<_>>::new
192
193
    /// # Panics
194
    ///
195
    /// - If `len` is not a multiple of `stride`
196
0
    pub fn from_slice(data: &[T], stride: usize) -> Self {
197
0
        let len = data.len();
198
0
199
0
        assert!(len % stride == 0);
200
201
0
        Self {
202
0
            data: PlaneData::from_slice(data),
203
0
            cfg: PlaneConfig {
204
0
                stride,
205
0
                alloc_height: len / stride,
206
0
                width: stride,
207
0
                height: len / stride,
208
0
                xdec: 0,
209
0
                ydec: 0,
210
0
                xpad: 0,
211
0
                ypad: 0,
212
0
                xorigin: 0,
213
0
                yorigin: 0,
214
0
            },
215
0
        }
216
0
    }
217
218
0
    pub fn pad(&mut self, w: usize, h: usize) {
219
0
        let xorigin = self.cfg.xorigin;
220
0
        let yorigin = self.cfg.yorigin;
221
0
        let stride = self.cfg.stride;
222
0
        let alloc_height = self.cfg.alloc_height;
223
0
        let width = (w + self.cfg.xdec) >> self.cfg.xdec;
224
0
        let height = (h + self.cfg.ydec) >> self.cfg.ydec;
225
0
226
0
        if xorigin > 0 {
227
0
            for y in 0..height {
228
0
                let base = (yorigin + y) * stride;
229
0
                let fill_val = self.data[base + xorigin];
230
0
                for val in &mut self.data[base..base + xorigin] {
231
0
                    *val = fill_val;
232
0
                }
233
            }
234
0
        }
235
236
0
        if xorigin + width < stride {
237
0
            for y in 0..height {
238
0
                let base = (yorigin + y) * stride + xorigin + width;
239
0
                let fill_val = self.data[base - 1];
240
0
                for val in &mut self.data[base..base + stride - (xorigin + width)] {
241
0
                    *val = fill_val;
242
0
                }
243
            }
244
0
        }
245
246
0
        if yorigin > 0 {
247
0
            let (top, bottom) = self.data.split_at_mut(yorigin * stride);
248
0
            let src = &bottom[..stride];
249
0
            for y in 0..yorigin {
250
0
                let dst = &mut top[y * stride..(y + 1) * stride];
251
0
                dst.copy_from_slice(src);
252
0
            }
253
0
        }
254
255
0
        if yorigin + height < self.cfg.alloc_height {
256
0
            let (top, bottom) = self.data.split_at_mut((yorigin + height) * stride);
257
0
            let src = &top[(yorigin + height - 1) * stride..];
258
0
            for y in 0..alloc_height - (yorigin + height) {
259
0
                let dst = &mut bottom[y * stride..(y + 1) * stride];
260
0
                dst.copy_from_slice(src);
261
0
            }
262
0
        }
263
0
    }
Unexecuted instantiation: <v_frame::plane::Plane<u16>>::pad
Unexecuted instantiation: <v_frame::plane::Plane<u8>>::pad
Unexecuted instantiation: <v_frame::plane::Plane<_>>::pad
264
265
    /// Minimally test that the plane has been padded.
266
0
    pub fn probe_padding(&self, w: usize, h: usize) -> bool {
267
0
        let PlaneConfig {
268
0
            xorigin,
269
0
            yorigin,
270
0
            stride,
271
0
            alloc_height,
272
0
            xdec,
273
0
            ydec,
274
0
            ..
275
0
        } = self.cfg;
276
0
        let width = (w + xdec) >> xdec;
277
0
        let height = (h + ydec) >> ydec;
278
0
        let corner = (yorigin + height - 1) * stride + xorigin + width - 1;
279
0
        let corner_value = self.data[corner];
280
0
281
0
        self.data[(yorigin + height) * stride - 1] == corner_value
282
0
            && self.data[(alloc_height - 1) * stride + xorigin + width - 1] == corner_value
283
0
            && self.data[alloc_height * stride - 1] == corner_value
284
0
    }
Unexecuted instantiation: <v_frame::plane::Plane<u16>>::probe_padding
Unexecuted instantiation: <v_frame::plane::Plane<u8>>::probe_padding
Unexecuted instantiation: <v_frame::plane::Plane<_>>::probe_padding
285
286
0
    pub fn slice(&self, po: PlaneOffset) -> PlaneSlice<'_, T> {
287
0
        PlaneSlice {
288
0
            plane: self,
289
0
            x: po.x,
290
0
            y: po.y,
291
0
        }
292
0
    }
Unexecuted instantiation: <v_frame::plane::Plane<u16>>::slice
Unexecuted instantiation: <v_frame::plane::Plane<u8>>::slice
Unexecuted instantiation: <v_frame::plane::Plane<_>>::slice
293
294
0
    pub fn mut_slice(&mut self, po: PlaneOffset) -> PlaneMutSlice<'_, T> {
295
0
        PlaneMutSlice {
296
0
            plane: self,
297
0
            x: po.x,
298
0
            y: po.y,
299
0
        }
300
0
    }
Unexecuted instantiation: <v_frame::plane::Plane<u16>>::mut_slice
Unexecuted instantiation: <v_frame::plane::Plane<u8>>::mut_slice
Unexecuted instantiation: <v_frame::plane::Plane<_>>::mut_slice
301
302
    #[inline]
303
0
    fn index(&self, x: usize, y: usize) -> usize {
304
0
        (y + self.cfg.yorigin) * self.cfg.stride + (x + self.cfg.xorigin)
305
0
    }
Unexecuted instantiation: <v_frame::plane::Plane<u16>>::index
Unexecuted instantiation: <v_frame::plane::Plane<u8>>::index
Unexecuted instantiation: <v_frame::plane::Plane<_>>::index
306
307
    /// This version of the function crops off the padding on the right side of the image
308
    #[inline]
309
0
    pub fn row_range_cropped(&self, x: isize, y: isize) -> Range<usize> {
310
0
        debug_assert!(self.cfg.yorigin as isize + y >= 0);
311
0
        debug_assert!(self.cfg.xorigin as isize + x >= 0);
312
0
        let base_y = (self.cfg.yorigin as isize + y) as usize;
313
0
        let base_x = (self.cfg.xorigin as isize + x) as usize;
314
0
        let base = base_y * self.cfg.stride + base_x;
315
0
        let width = (self.cfg.width as isize - x) as usize;
316
0
        base..base + width
317
0
    }
Unexecuted instantiation: <v_frame::plane::Plane<u16>>::row_range_cropped
Unexecuted instantiation: <v_frame::plane::Plane<u8>>::row_range_cropped
Unexecuted instantiation: <v_frame::plane::Plane<_>>::row_range_cropped
318
319
    /// This version of the function includes the padding on the right side of the image
320
    #[inline]
321
0
    pub fn row_range(&self, x: isize, y: isize) -> Range<usize> {
322
0
        debug_assert!(self.cfg.yorigin as isize + y >= 0);
323
0
        debug_assert!(self.cfg.xorigin as isize + x >= 0);
324
0
        let base_y = (self.cfg.yorigin as isize + y) as usize;
325
0
        let base_x = (self.cfg.xorigin as isize + x) as usize;
326
0
        let base = base_y * self.cfg.stride + base_x;
327
0
        let width = self.cfg.stride - base_x;
328
0
        base..base + width
329
0
    }
Unexecuted instantiation: <v_frame::plane::Plane<u16>>::row_range
Unexecuted instantiation: <v_frame::plane::Plane<u8>>::row_range
Unexecuted instantiation: <v_frame::plane::Plane<_>>::row_range
330
331
    /// Returns the pixel at the given coordinates.
332
0
    pub fn p(&self, x: usize, y: usize) -> T {
333
0
        self.data[self.index(x, y)]
334
0
    }
335
336
    /// Returns plane data starting from the origin.
337
0
    pub fn data_origin(&self) -> &[T] {
338
0
        &self.data[self.index(0, 0)..]
339
0
    }
Unexecuted instantiation: <v_frame::plane::Plane<u16>>::data_origin
Unexecuted instantiation: <v_frame::plane::Plane<u8>>::data_origin
Unexecuted instantiation: <v_frame::plane::Plane<_>>::data_origin
340
341
    /// Returns mutable plane data starting from the origin.
342
0
    pub fn data_origin_mut(&mut self) -> &mut [T] {
343
0
        let i = self.index(0, 0);
344
0
        &mut self.data[i..]
345
0
    }
Unexecuted instantiation: <v_frame::plane::Plane<u8>>::data_origin_mut
Unexecuted instantiation: <v_frame::plane::Plane<_>>::data_origin_mut
346
347
    /// Copies data into the plane from a pixel array.
348
    ///
349
    /// # Panics
350
    ///
351
    /// - If `source_bytewidth` does not match the generic `T` of `Plane`
352
0
    pub fn copy_from_raw_u8(
353
0
        &mut self,
354
0
        source: &[u8],
355
0
        source_stride: usize,
356
0
        source_bytewidth: usize,
357
0
    ) {
358
0
        let stride = self.cfg.stride;
359
0
360
0
        assert!(stride != 0);
361
0
        assert!(source_stride != 0);
362
363
0
        for (self_row, source_row) in self
364
0
            .data_origin_mut()
365
0
            .chunks_exact_mut(stride)
366
0
            .zip(source.chunks_exact(source_stride))
367
        {
368
0
            match source_bytewidth {
369
                1 => {
370
0
                    for (self_pixel, source_pixel) in self_row.iter_mut().zip(source_row.iter()) {
371
0
                        *self_pixel = T::cast_from(*source_pixel);
372
0
                    }
373
                }
374
                2 => {
375
0
                    assert!(
376
0
                        size_of::<T>() == 2,
377
0
                        "source bytewidth ({}) cannot fit in Plane<u8>",
378
                        source_bytewidth
379
                    );
380
381
0
                    debug_assert!(T::type_enum() == PixelType::U16);
382
383
                    // SAFETY: because of the assert it is safe to assume that T == u16
384
0
                    let self_row: &mut [u16] = unsafe { std::mem::transmute(self_row) };
385
0
                    // SAFETY: we reinterpret the slice of bytes as a slice of elements of
386
0
                    // [u8; 2] to allow for more efficient codegen with from_le_bytes
387
0
                    let source_row: &[[u8; 2]] = unsafe {
388
0
                        std::slice::from_raw_parts(source_row.as_ptr().cast(), source_row.len() / 2)
389
                    };
390
391
0
                    for (self_pixel, bytes) in self_row.iter_mut().zip(source_row) {
392
0
                        *self_pixel = u16::from_le_bytes(*bytes);
393
0
                    }
394
                }
395
396
0
                _ => {}
397
            }
398
        }
399
0
    }
400
401
    /// Copies data from a plane into a pixel array.
402
    ///
403
    /// # Panics
404
    ///
405
    /// - If `dest_bytewidth` does not match the generic `T` of `Plane`
406
0
    pub fn copy_to_raw_u8(&self, dest: &mut [u8], dest_stride: usize, dest_bytewidth: usize) {
407
0
        let stride = self.cfg.stride;
408
0
        for (self_row, dest_row) in self
409
0
            .data_origin()
410
0
            .chunks_exact(stride)
411
0
            .zip(dest.chunks_exact_mut(dest_stride))
412
        {
413
0
            match dest_bytewidth {
414
                1 => {
415
0
                    for (self_pixel, dest_pixel) in
416
0
                        self_row[..self.cfg.width].iter().zip(dest_row.iter_mut())
417
0
                    {
418
0
                        *dest_pixel = u8::cast_from(*self_pixel);
419
0
                    }
420
                }
421
                2 => {
422
0
                    assert!(
423
0
                        size_of::<T>() >= 2,
424
0
                        "dest bytewidth ({}) cannot fit in Plane<u8>",
425
                        dest_bytewidth
426
                    );
427
428
                    // SAFETY: we reinterpret the slice of bytes as a slice
429
                    // of [u8; 2] with half the elements
430
0
                    let dest_row: &mut [[u8; 2]] = unsafe {
431
0
                        std::slice::from_raw_parts_mut(
432
0
                            dest_row.as_mut_ptr().cast(),
433
0
                            dest_row.len() / 2,
434
0
                        )
435
                    };
436
437
0
                    for (self_pixel, bytes) in self_row[..self.cfg.width].iter().zip(dest_row) {
438
0
                        *bytes = u16::cast_from(*self_pixel).to_le_bytes();
439
0
                    }
440
                }
441
442
0
                _ => {}
443
            }
444
        }
445
0
    }
446
447
    /// Returns plane with half the resolution for width and height.
448
    /// Downscaled with 2x2 box filter.
449
    /// Padded to dimensions with `frame_width` and `frame_height`.
450
    ///
451
    /// # Panics
452
    ///
453
    /// - If the requested width and height are > half the input width or height
454
0
    pub fn downsampled(&self, frame_width: usize, frame_height: usize) -> Plane<T> {
455
0
        let src = self;
456
0
        let mut new = Plane::new(
457
0
            (src.cfg.width + 1) / 2,
458
0
            (src.cfg.height + 1) / 2,
459
0
            src.cfg.xdec + 1,
460
0
            src.cfg.ydec + 1,
461
0
            src.cfg.xpad / 2,
462
0
            src.cfg.ypad / 2,
463
0
        );
464
0
465
0
        let width = new.cfg.width;
466
0
        let height = new.cfg.height;
467
0
468
0
        assert!(width * 2 <= src.cfg.stride - src.cfg.xorigin);
469
0
        assert!(height * 2 <= src.cfg.alloc_height - src.cfg.yorigin);
470
471
0
        let data_origin = src.data_origin();
472
0
        for (row_idx, dst_row) in new
473
0
            .mut_slice(PlaneOffset::default())
474
0
            .rows_iter_mut()
475
0
            .enumerate()
476
0
            .take(height)
477
        {
478
0
            let src_top_row = &data_origin[(src.cfg.stride * row_idx * 2)..][..(2 * width)];
479
0
            let src_bottom_row =
480
0
                &data_origin[(src.cfg.stride * (row_idx * 2 + 1))..][..(2 * width)];
481
482
0
            for ((dst, a), b) in dst_row
483
0
                .iter_mut()
484
0
                .zip(src_top_row.chunks_exact(2))
485
0
                .zip(src_bottom_row.chunks_exact(2))
486
0
            {
487
0
                let sum = u32::cast_from(a[0])
488
0
                    + u32::cast_from(a[1])
489
0
                    + u32::cast_from(b[0])
490
0
                    + u32::cast_from(b[1]);
491
0
                let avg = (sum + 2) >> 2;
492
0
                *dst = T::cast_from(avg);
493
0
            }
494
        }
495
496
0
        new.pad(frame_width, frame_height);
497
0
        new
498
0
    }
Unexecuted instantiation: <v_frame::plane::Plane<u16>>::downsampled
Unexecuted instantiation: <v_frame::plane::Plane<u8>>::downsampled
Unexecuted instantiation: <v_frame::plane::Plane<_>>::downsampled
499
500
    /// Returns a plane downscaled from the source plane by a factor of `scale` (not padded)
501
0
    pub fn downscale<const SCALE: usize>(&self) -> Plane<T> {
502
0
        let mut new_plane = Plane::new(self.cfg.width / SCALE, self.cfg.height / SCALE, 0, 0, 0, 0);
503
0
504
0
        self.downscale_in_place::<SCALE>(&mut new_plane);
505
0
506
0
        new_plane
507
0
    }
Unexecuted instantiation: <v_frame::plane::Plane<u8>>::downscale::<16>
Unexecuted instantiation: <v_frame::plane::Plane<u8>>::downscale::<32>
Unexecuted instantiation: <v_frame::plane::Plane<u8>>::downscale::<2>
Unexecuted instantiation: <v_frame::plane::Plane<u8>>::downscale::<4>
Unexecuted instantiation: <v_frame::plane::Plane<u8>>::downscale::<8>
Unexecuted instantiation: <v_frame::plane::Plane<u16>>::downscale::<16>
Unexecuted instantiation: <v_frame::plane::Plane<u16>>::downscale::<32>
Unexecuted instantiation: <v_frame::plane::Plane<u16>>::downscale::<2>
Unexecuted instantiation: <v_frame::plane::Plane<u16>>::downscale::<4>
Unexecuted instantiation: <v_frame::plane::Plane<u16>>::downscale::<8>
Unexecuted instantiation: <v_frame::plane::Plane<_>>::downscale::<_>
508
509
    /// Downscales the source plane by a factor of `scale`, writing the result to `in_plane` (not padded)
510
    ///
511
    /// # Panics
512
    ///
513
    /// - If the current plane's width and height are not at least `SCALE` times the `in_plane`'s
514
    #[cfg_attr(feature = "profiling", profiling::function(downscale_in_place))]
515
0
    pub fn downscale_in_place<const SCALE: usize>(&self, in_plane: &mut Plane<T>) {
516
0
        let stride = in_plane.cfg.stride;
517
0
        let width = in_plane.cfg.width;
518
0
        let height = in_plane.cfg.height;
519
0
520
0
        if stride == 0 || self.cfg.stride == 0 {
521
0
            panic!("stride cannot be 0");
522
0
        }
523
0
524
0
        assert!(width * SCALE <= self.cfg.stride - self.cfg.xorigin);
525
0
        assert!(height * SCALE <= self.cfg.alloc_height - self.cfg.yorigin);
526
527
        // SAFETY: Bounds checks have been removed for performance reasons
528
        unsafe {
529
0
            let src = self;
530
0
            let box_pixels = SCALE * SCALE;
531
0
            let half_box_pixels = box_pixels as u32 / 2; // Used for rounding int division
532
0
533
0
            let data_origin = src.data_origin();
534
0
            let plane_data_mut_slice = &mut *in_plane.data;
535
536
            // Iter dst rows
537
0
            for row_idx in 0..height {
538
0
                let dst_row = plane_data_mut_slice.get_unchecked_mut(row_idx * stride..);
539
                // Iter dst cols
540
0
                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
                            // Sum box of size scale * scale
545
546
                            // Iter src row
547
                            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
                                // Iter src col
553
                                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
                            // Box average
560
                            let avg = sum as usize / box_pixels;
561
                            *dst = T::cast_from(avg);
562
                        };
563
                    }
564
565
                    // Use 16 bit precision if overflow would not happen
566
0
                    if T::type_enum() == PixelType::U8
567
0
                        && SCALE as u128 * SCALE as u128 * (u8::MAX as u128)
568
0
                            + half_box_pixels as u128
569
0
                            <= u16::MAX as u128
570
                    {
571
0
                        generate_inner_loop!(u16);
572
                    } else {
573
0
                        generate_inner_loop!(u32);
574
                    }
575
                }
576
            }
577
        }
578
0
    }
Unexecuted instantiation: <v_frame::plane::Plane<u8>>::downscale_in_place::<16>
Unexecuted instantiation: <v_frame::plane::Plane<u8>>::downscale_in_place::<32>
Unexecuted instantiation: <v_frame::plane::Plane<u8>>::downscale_in_place::<2>
Unexecuted instantiation: <v_frame::plane::Plane<u8>>::downscale_in_place::<4>
Unexecuted instantiation: <v_frame::plane::Plane<u8>>::downscale_in_place::<8>
Unexecuted instantiation: <v_frame::plane::Plane<u16>>::downscale_in_place::<16>
Unexecuted instantiation: <v_frame::plane::Plane<u16>>::downscale_in_place::<32>
Unexecuted instantiation: <v_frame::plane::Plane<u16>>::downscale_in_place::<2>
Unexecuted instantiation: <v_frame::plane::Plane<u16>>::downscale_in_place::<4>
Unexecuted instantiation: <v_frame::plane::Plane<u16>>::downscale_in_place::<8>
Unexecuted instantiation: <v_frame::plane::Plane<_>>::downscale_in_place::<_>
579
580
    /// Iterates over the pixels in the plane, skipping the padding.
581
0
    pub fn iter(&self) -> PlaneIter<'_, T> {
582
0
        PlaneIter::new(self)
583
0
    }
584
585
    /// Iterates over the lines of the plane
586
0
    pub fn rows_iter(&self) -> RowsIter<'_, T> {
587
0
        RowsIter {
588
0
            plane: self,
589
0
            x: 0,
590
0
            y: 0,
591
0
        }
592
0
    }
Unexecuted instantiation: <v_frame::plane::Plane<u16>>::rows_iter
Unexecuted instantiation: <v_frame::plane::Plane<u8>>::rows_iter
Unexecuted instantiation: <v_frame::plane::Plane<_>>::rows_iter
593
594
0
    pub fn rows_iter_mut(&mut self) -> RowsIterMut<'_, T> {
595
0
        RowsIterMut {
596
0
            plane: self as *mut Plane<T>,
597
0
            x: 0,
598
0
            y: 0,
599
0
            phantom: PhantomData,
600
0
        }
601
0
    }
602
603
    /// Return a line
604
0
    pub fn row(&self, y: isize) -> &[T] {
605
0
        let range = self.row_range(0, y);
606
0
607
0
        &self.data[range]
608
0
    }
Unexecuted instantiation: <v_frame::plane::Plane<u16>>::row
Unexecuted instantiation: <v_frame::plane::Plane<u8>>::row
Unexecuted instantiation: <v_frame::plane::Plane<_>>::row
609
}
610
611
/// Iterator over plane pixels, skipping padding.
612
#[derive(Debug)]
613
pub struct PlaneIter<'a, T: Pixel> {
614
    plane: &'a Plane<T>,
615
    y: usize,
616
    x: usize,
617
}
618
619
impl<'a, T: Pixel> PlaneIter<'a, T> {
620
    /// Creates a new iterator.
621
0
    pub fn new(plane: &'a Plane<T>) -> Self {
622
0
        Self { plane, y: 0, x: 0 }
623
0
    }
624
625
0
    fn width(&self) -> usize {
626
0
        self.plane.cfg.width
627
0
    }
628
629
0
    fn height(&self) -> usize {
630
0
        self.plane.cfg.height
631
0
    }
632
}
633
634
impl<T: Pixel> Iterator for PlaneIter<'_, T> {
635
    type Item = T;
636
637
0
    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
638
0
        if self.y == self.height() {
639
0
            return None;
640
0
        }
641
0
        let pixel = self.plane.p(self.x, self.y);
642
0
        if self.x == self.width() - 1 {
643
0
            self.x = 0;
644
0
            self.y += 1;
645
0
        } else {
646
0
            self.x += 1;
647
0
        }
648
0
        Some(pixel)
649
0
    }
650
}
651
652
impl<T: Pixel> FusedIterator for PlaneIter<'_, T> {}
653
654
// A Plane, PlaneSlice, or PlaneRegion is assumed to include or be able to include
655
// padding on the edge of the frame
656
#[derive(Clone, Copy, Debug)]
657
pub struct PlaneSlice<'a, T: Pixel> {
658
    pub plane: &'a Plane<T>,
659
    pub x: isize,
660
    pub y: isize,
661
}
662
663
// A RowsIter or RowsIterMut is assumed to crop the padding from the frame edges
664
pub struct RowsIter<'a, T: Pixel> {
665
    plane: &'a Plane<T>,
666
    x: isize,
667
    y: isize,
668
}
669
670
impl<'a, T: Pixel> Iterator for RowsIter<'a, T> {
671
    type Item = &'a [T];
672
673
0
    fn next(&mut self) -> Option<Self::Item> {
674
0
        if self.plane.cfg.height as isize > self.y {
675
            // cannot directly return self.ps.row(row) due to lifetime issue
676
0
            let range = self.plane.row_range_cropped(self.x, self.y);
677
0
            self.y += 1;
678
0
            Some(&self.plane.data[range])
679
        } else {
680
0
            None
681
        }
682
0
    }
Unexecuted instantiation: <v_frame::plane::RowsIter<u16> as core::iter::traits::iterator::Iterator>::next
Unexecuted instantiation: <v_frame::plane::RowsIter<u8> as core::iter::traits::iterator::Iterator>::next
Unexecuted instantiation: <v_frame::plane::RowsIter<_> as core::iter::traits::iterator::Iterator>::next
683
684
0
    fn size_hint(&self) -> (usize, Option<usize>) {
685
0
        let remaining = self.plane.cfg.height as isize - self.y;
686
0
        debug_assert!(remaining >= 0);
687
0
        let remaining = remaining as usize;
688
0
689
0
        (remaining, Some(remaining))
690
0
    }
691
}
692
693
impl<T: Pixel> ExactSizeIterator for RowsIter<'_, T> {}
694
impl<T: Pixel> FusedIterator for RowsIter<'_, T> {}
695
696
impl<'a, T: Pixel> PlaneSlice<'a, T> {
697
    #[allow(unused)]
698
0
    pub fn as_ptr(&self) -> *const T {
699
0
        self[0].as_ptr()
700
0
    }
Unexecuted instantiation: <v_frame::plane::PlaneSlice<u16>>::as_ptr
Unexecuted instantiation: <v_frame::plane::PlaneSlice<u8>>::as_ptr
Unexecuted instantiation: <v_frame::plane::PlaneSlice<_>>::as_ptr
701
702
0
    pub fn rows_iter(&self) -> RowsIter<'_, T> {
703
0
        RowsIter {
704
0
            plane: self.plane,
705
0
            x: self.x,
706
0
            y: self.y,
707
0
        }
708
0
    }
709
710
0
    pub fn clamp(&self) -> PlaneSlice<'a, T> {
711
0
        PlaneSlice {
712
0
            plane: self.plane,
713
0
            x: self.x.clamp(
714
0
                -(self.plane.cfg.xorigin as isize),
715
0
                self.plane.cfg.width as isize,
716
0
            ),
717
0
            y: self.y.clamp(
718
0
                -(self.plane.cfg.yorigin as isize),
719
0
                self.plane.cfg.height as isize,
720
0
            ),
721
0
        }
722
0
    }
Unexecuted instantiation: <v_frame::plane::PlaneSlice<u16>>::clamp
Unexecuted instantiation: <v_frame::plane::PlaneSlice<u8>>::clamp
Unexecuted instantiation: <v_frame::plane::PlaneSlice<_>>::clamp
723
724
0
    pub fn subslice(&self, xo: usize, yo: usize) -> PlaneSlice<'a, T> {
725
0
        PlaneSlice {
726
0
            plane: self.plane,
727
0
            x: self.x + xo as isize,
728
0
            y: self.y + yo as isize,
729
0
        }
730
0
    }
Unexecuted instantiation: <v_frame::plane::PlaneSlice<u16>>::subslice
Unexecuted instantiation: <v_frame::plane::PlaneSlice<u8>>::subslice
Unexecuted instantiation: <v_frame::plane::PlaneSlice<_>>::subslice
731
732
0
    pub fn reslice(&self, xo: isize, yo: isize) -> PlaneSlice<'a, T> {
733
0
        PlaneSlice {
734
0
            plane: self.plane,
735
0
            x: self.x + xo,
736
0
            y: self.y + yo,
737
0
        }
738
0
    }
Unexecuted instantiation: <v_frame::plane::PlaneSlice<u16>>::reslice
Unexecuted instantiation: <v_frame::plane::PlaneSlice<u8>>::reslice
Unexecuted instantiation: <v_frame::plane::PlaneSlice<_>>::reslice
739
740
    /// A slice starting i pixels above the current one.
741
0
    pub fn go_up(&self, i: usize) -> PlaneSlice<'a, T> {
742
0
        PlaneSlice {
743
0
            plane: self.plane,
744
0
            x: self.x,
745
0
            y: self.y - i as isize,
746
0
        }
747
0
    }
Unexecuted instantiation: <v_frame::plane::PlaneSlice<u16>>::go_up
Unexecuted instantiation: <v_frame::plane::PlaneSlice<u8>>::go_up
Unexecuted instantiation: <v_frame::plane::PlaneSlice<_>>::go_up
748
749
    /// A slice starting i pixels to the left of the current one.
750
0
    pub fn go_left(&self, i: usize) -> PlaneSlice<'a, T> {
751
0
        PlaneSlice {
752
0
            plane: self.plane,
753
0
            x: self.x - i as isize,
754
0
            y: self.y,
755
0
        }
756
0
    }
Unexecuted instantiation: <v_frame::plane::PlaneSlice<u16>>::go_left
Unexecuted instantiation: <v_frame::plane::PlaneSlice<u8>>::go_left
Unexecuted instantiation: <v_frame::plane::PlaneSlice<_>>::go_left
757
758
0
    pub fn p(&self, add_x: usize, add_y: usize) -> T {
759
0
        let new_y = (self.y + add_y as isize + self.plane.cfg.yorigin as isize) as usize;
760
0
        let new_x = (self.x + add_x as isize + self.plane.cfg.xorigin as isize) as usize;
761
0
        self.plane.data[new_y * self.plane.cfg.stride + new_x]
762
0
    }
763
764
    /// Checks if `add_y` and `add_x` lies in the allocated bounds of the
765
    /// underlying plane.
766
0
    pub fn accessible(&self, add_x: usize, add_y: usize) -> bool {
767
0
        let y = (self.y + add_y as isize + self.plane.cfg.yorigin as isize) as usize;
768
0
        let x = (self.x + add_x as isize + self.plane.cfg.xorigin as isize) as usize;
769
0
        y < self.plane.cfg.alloc_height && x < self.plane.cfg.stride
770
0
    }
771
772
    /// Checks if -`sub_x` and -`sub_y` lies in the allocated bounds of the
773
    /// underlying plane.
774
0
    pub fn accessible_neg(&self, sub_x: usize, sub_y: usize) -> bool {
775
0
        let y = self.y - sub_y as isize + self.plane.cfg.yorigin as isize;
776
0
        let x = self.x - sub_x as isize + self.plane.cfg.xorigin as isize;
777
0
        y >= 0 && x >= 0
778
0
    }
779
780
    /// This version of the function crops off the padding on the right side of the image
781
0
    pub fn row_cropped(&self, y: usize) -> &[T] {
782
0
        let y = (self.y + y as isize + self.plane.cfg.yorigin as isize) as usize;
783
0
        let x = (self.x + self.plane.cfg.xorigin as isize) as usize;
784
0
        let start = y * self.plane.cfg.stride + x;
785
0
        let width = (self.plane.cfg.width as isize - self.x) as usize;
786
0
        &self.plane.data[start..start + width]
787
0
    }
788
789
    /// This version of the function includes the padding on the right side of the image
790
0
    pub fn row(&self, y: usize) -> &[T] {
791
0
        let y = (self.y + y as isize + self.plane.cfg.yorigin as isize) as usize;
792
0
        let x = (self.x + self.plane.cfg.xorigin as isize) as usize;
793
0
        let start = y * self.plane.cfg.stride + x;
794
0
        let width = self.plane.cfg.stride - x;
795
0
        &self.plane.data[start..start + width]
796
0
    }
Unexecuted instantiation: <v_frame::plane::PlaneSlice<u16>>::row
Unexecuted instantiation: <v_frame::plane::PlaneSlice<u8>>::row
Unexecuted instantiation: <v_frame::plane::PlaneSlice<_>>::row
797
}
798
799
impl<T: Pixel> Index<usize> for PlaneSlice<'_, T> {
800
    type Output = [T];
801
0
    fn index(&self, index: usize) -> &Self::Output {
802
0
        let range = self.plane.row_range(self.x, self.y + index as isize);
803
0
        &self.plane.data[range]
804
0
    }
Unexecuted instantiation: <v_frame::plane::PlaneSlice<u16> as core::ops::index::Index<usize>>::index
Unexecuted instantiation: <v_frame::plane::PlaneSlice<u8> as core::ops::index::Index<usize>>::index
Unexecuted instantiation: <v_frame::plane::PlaneSlice<_> as core::ops::index::Index<usize>>::index
805
}
806
807
pub struct PlaneMutSlice<'a, T: Pixel> {
808
    pub plane: &'a mut Plane<T>,
809
    pub x: isize,
810
    pub y: isize,
811
}
812
813
pub 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
820
impl<'a, T: Pixel> Iterator for RowsIterMut<'a, T> {
821
    type Item = &'a mut [T];
822
823
0
    fn next(&mut self) -> Option<Self::Item> {
824
0
        // SAFETY: there could not be a concurrent call using a mutable reference to the plane
825
0
        let plane = unsafe { &mut *self.plane };
826
0
        if plane.cfg.height as isize > self.y {
827
            // cannot directly return self.ps.row(row) due to lifetime issue
828
0
            let range = plane.row_range_cropped(self.x, self.y);
829
0
            self.y += 1;
830
0
            Some(&mut plane.data[range])
831
        } else {
832
0
            None
833
        }
834
0
    }
Unexecuted instantiation: <v_frame::plane::RowsIterMut<u16> as core::iter::traits::iterator::Iterator>::next
Unexecuted instantiation: <v_frame::plane::RowsIterMut<u8> as core::iter::traits::iterator::Iterator>::next
Unexecuted instantiation: <v_frame::plane::RowsIterMut<_> as core::iter::traits::iterator::Iterator>::next
835
836
0
    fn size_hint(&self) -> (usize, Option<usize>) {
837
0
        // SAFETY: there could not be a concurrent call using a mutable reference to the plane
838
0
        let plane = unsafe { &mut *self.plane };
839
0
        let remaining = plane.cfg.height as isize - self.y;
840
0
        debug_assert!(remaining >= 0);
841
0
        let remaining = remaining as usize;
842
0
843
0
        (remaining, Some(remaining))
844
0
    }
845
}
846
847
impl<T: Pixel> ExactSizeIterator for RowsIterMut<'_, T> {}
848
impl<T: Pixel> FusedIterator for RowsIterMut<'_, T> {}
849
850
impl<T: Pixel> PlaneMutSlice<'_, T> {
851
    #[allow(unused)]
852
0
    pub fn rows_iter(&self) -> RowsIter<'_, T> {
853
0
        RowsIter {
854
0
            plane: self.plane,
855
0
            x: self.x,
856
0
            y: self.y,
857
0
        }
858
0
    }
859
860
0
    pub fn rows_iter_mut(&mut self) -> RowsIterMut<'_, T> {
861
0
        RowsIterMut {
862
0
            plane: self.plane as *mut Plane<T>,
863
0
            x: self.x,
864
0
            y: self.y,
865
0
            phantom: PhantomData,
866
0
        }
867
0
    }
Unexecuted instantiation: <v_frame::plane::PlaneMutSlice<u16>>::rows_iter_mut
Unexecuted instantiation: <v_frame::plane::PlaneMutSlice<u8>>::rows_iter_mut
Unexecuted instantiation: <v_frame::plane::PlaneMutSlice<_>>::rows_iter_mut
868
869
    #[allow(unused)]
870
0
    pub fn subslice(&mut self, xo: usize, yo: usize) -> PlaneMutSlice<'_, T> {
871
0
        PlaneMutSlice {
872
0
            plane: self.plane,
873
0
            x: self.x + xo as isize,
874
0
            y: self.y + yo as isize,
875
0
        }
876
0
    }
877
}
878
879
impl<T: Pixel> Index<usize> for PlaneMutSlice<'_, T> {
880
    type Output = [T];
881
0
    fn index(&self, index: usize) -> &Self::Output {
882
0
        let range = self.plane.row_range(self.x, self.y + index as isize);
883
0
        &self.plane.data[range]
884
0
    }
885
}
886
887
impl<T: Pixel> IndexMut<usize> for PlaneMutSlice<'_, T> {
888
0
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
889
0
        let range = self.plane.row_range(self.x, self.y + index as isize);
890
0
        &mut self.plane.data[range]
891
0
    }
892
}
893
894
#[cfg(test)]
895
pub 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
}