Coverage Report

Created: 2026-06-10 07:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/image/src/images/flat.rs
Line
Count
Source
1
//! Image representations for ffi.
2
//!
3
//! # Usage
4
//!
5
//! Imagine you want to offer a very simple ffi interface: The caller provides an image buffer and
6
//! your program creates a thumbnail from it and dumps that image as `png`. This module is designed
7
//! to help you transition from raw memory data to Rust representation.
8
//!
9
//! ```no_run
10
//! use std::ptr;
11
//! use std::slice;
12
//! use image::Rgb;
13
//! use image::flat::{FlatSamples, SampleLayout};
14
//! use image::imageops::thumbnail;
15
//!
16
//! #[no_mangle]
17
//! pub extern "C" fn store_rgb8_compressed(
18
//!     data: *const u8, len: usize,
19
//!     layout: *const SampleLayout
20
//! )
21
//!     -> bool
22
//! {
23
//!     let samples = unsafe { slice::from_raw_parts(data, len) };
24
//!     let layout = unsafe { ptr::read(layout) };
25
//!
26
//!     let buffer = FlatSamples {
27
//!         samples,
28
//!         layout,
29
//!         color_hint: None,
30
//!     };
31
//!
32
//!     let view = match buffer.as_view::<Rgb<u8>>() {
33
//!         Err(_) => return false, // Invalid layout.
34
//!         Ok(view) => view,
35
//!     };
36
//!
37
//!     thumbnail(&view, 64, 64)
38
//!         .save("output.png")
39
//!         .map(|_| true)
40
//!         .unwrap_or_else(|_| false)
41
//! }
42
//! ```
43
//!
44
use std::marker::PhantomData;
45
use std::ops::{Deref, Index, IndexMut};
46
use std::{cmp, error, fmt};
47
48
use num_traits::Zero;
49
50
use crate::color::ColorType;
51
use crate::error::{
52
    DecodingError, ImageError, ImageFormatHint, ParameterError, ParameterErrorKind,
53
    UnsupportedError, UnsupportedErrorKind,
54
};
55
use crate::math::Rect;
56
use crate::traits::Pixel;
57
use crate::{GenericImage, GenericImageView, ImageBuffer};
58
59
/// A flat buffer over a (multi channel) image.
60
///
61
/// In contrast to `ImageBuffer`, this representation of a sample collection is much more lenient
62
/// in the layout thereof. It also allows grouping by color planes instead of by pixel as long as
63
/// the strides of each extent are constant. This struct itself has no invariants on the strides
64
/// but not every possible configuration can be interpreted as a [`GenericImageView`] or
65
/// [`GenericImage`]. The methods [`as_view`] and [`as_view_mut`] construct the actual implementors
66
/// of these traits and perform necessary checks. To manually perform this and other layout checks
67
/// use [`is_normal`] or [`has_aliased_samples`].
68
///
69
/// Instances can be constructed not only by hand. The buffer instances returned by library
70
/// functions such as [`ImageBuffer::as_flat_samples`] guarantee that the conversion to a generic
71
/// image or generic view succeeds. A very different constructor is [`with_monocolor`]. It uses a
72
/// single pixel as the backing storage for an arbitrarily sized read-only raster by mapping each
73
/// pixel to the same samples by setting some strides to `0`.
74
///
75
/// [`is_normal`]: Self::is_normal
76
/// [`has_aliased_samples`]: Self::has_aliased_samples
77
/// [`as_view`]: Self::as_view
78
/// [`as_view_mut`]: Self::as_view_mut
79
/// [`with_monocolor`]: Self::with_monocolor
80
#[derive(Clone, Debug)]
81
pub struct FlatSamples<Buffer> {
82
    /// Underlying linear container holding sample values.
83
    pub samples: Buffer,
84
85
    /// A `repr(C)` description of the layout of buffer samples.
86
    pub layout: SampleLayout,
87
88
    /// Supplementary color information.
89
    ///
90
    /// You may keep this as `None` in most cases. This is NOT checked in `View` or other
91
    /// converters. It is intended mainly as a way for types that convert to this buffer type to
92
    /// attach their otherwise static color information. A dynamic image representation could
93
    /// however use this to resolve representational ambiguities such as the order of RGB channels.
94
    pub color_hint: Option<ColorType>,
95
}
96
97
/// A ffi compatible description of a sample buffer.
98
#[repr(C)]
99
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
100
pub struct SampleLayout {
101
    /// The number of channels in the color representation of the image.
102
    pub channels: u8,
103
104
    /// Add this to an index to get to the sample in the next channel.
105
    pub channel_stride: usize,
106
107
    /// The width of the represented image.
108
    pub width: u32,
109
110
    /// Add this to an index to get to the next sample in x-direction.
111
    pub width_stride: usize,
112
113
    /// The height of the represented image.
114
    pub height: u32,
115
116
    /// Add this to an index to get to the next sample in y-direction.
117
    pub height_stride: usize,
118
}
119
120
/// Helper struct for an unnamed (stride, length) pair.
121
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
122
struct Dim(usize, usize);
123
124
impl SampleLayout {
125
    /// Describe a row-major image packed in all directions.
126
    ///
127
    /// The resulting will surely be `NormalForm::RowMajorPacked`. It can therefore be converted to
128
    /// safely to an `ImageBuffer` with a large enough underlying buffer.
129
    ///
130
    /// ```
131
    /// # use image::flat::{NormalForm, SampleLayout};
132
    /// let layout = SampleLayout::row_major_packed(3, 640, 480);
133
    /// assert!(layout.is_normal(NormalForm::RowMajorPacked));
134
    /// ```
135
    ///
136
    /// # Panics
137
    ///
138
    /// On platforms where `usize` has the same size as `u32` this panics when the resulting stride
139
    /// in the `height` direction would be larger than `usize::MAX`. On other platforms
140
    /// where it can surely accommodate `u8::MAX * u32::MAX`, this can never happen.
141
    #[must_use]
142
0
    pub fn row_major_packed(channels: u8, width: u32, height: u32) -> Self {
143
0
        let height_stride = (channels as usize).checked_mul(width as usize).expect(
144
0
            "Row major packed image can not be described because it does not fit into memory",
145
        );
146
0
        SampleLayout {
147
0
            channels,
148
0
            channel_stride: 1,
149
0
            width,
150
0
            width_stride: channels as usize,
151
0
            height,
152
0
            height_stride,
153
0
        }
154
0
    }
155
156
    /// Describe a column-major image packed in all directions.
157
    ///
158
    /// The resulting will surely be `NormalForm::ColumnMajorPacked`. This is not particularly
159
    /// useful for conversion but can be used to describe such a buffer without pitfalls.
160
    ///
161
    /// ```
162
    /// # use image::flat::{NormalForm, SampleLayout};
163
    /// let layout = SampleLayout::column_major_packed(3, 640, 480);
164
    /// assert!(layout.is_normal(NormalForm::ColumnMajorPacked));
165
    /// ```
166
    ///
167
    /// # Panics
168
    ///
169
    /// On platforms where `usize` has the same size as `u32` this panics when the resulting stride
170
    /// in the `width` direction would be larger than `usize::MAX`. On other platforms
171
    /// where it can surely accommodate `u8::MAX * u32::MAX`, this can never happen.
172
    #[must_use]
173
0
    pub fn column_major_packed(channels: u8, width: u32, height: u32) -> Self {
174
0
        let width_stride = (channels as usize).checked_mul(height as usize).expect(
175
0
            "Column major packed image can not be described because it does not fit into memory",
176
        );
177
0
        SampleLayout {
178
0
            channels,
179
0
            channel_stride: 1,
180
0
            height,
181
0
            height_stride: channels as usize,
182
0
            width,
183
0
            width_stride,
184
0
        }
185
0
    }
186
187
    /// Get the strides for indexing matrix-like `[(c, w, h)]`.
188
    ///
189
    /// For a row-major layout with grouped samples, this tuple is strictly
190
    /// increasing.
191
    #[must_use]
192
0
    pub fn strides_cwh(&self) -> (usize, usize, usize) {
193
0
        (self.channel_stride, self.width_stride, self.height_stride)
194
0
    }
195
196
    /// Get the dimensions `(channels, width, height)`.
197
    ///
198
    /// The interface is optimized for use with `strides_cwh` instead. The channel extent will be
199
    /// before width and height.
200
    #[must_use]
201
0
    pub fn extents(&self) -> (usize, usize, usize) {
202
0
        (
203
0
            self.channels as usize,
204
0
            self.width as usize,
205
0
            self.height as usize,
206
0
        )
207
0
    }
208
209
    /// Tuple of bounds in the order of coordinate inputs.
210
    ///
211
    /// This function should be used whenever working with image coordinates opposed to buffer
212
    /// coordinates. The only difference compared to `extents` is the output type.
213
    #[must_use]
214
0
    pub fn bounds(&self) -> (u8, u32, u32) {
215
0
        (self.channels, self.width, self.height)
216
0
    }
217
218
    /// Get the minimum length of a buffer such that all in-bounds samples have valid indices.
219
    ///
220
    /// This method will allow zero strides, allowing compact representations of monochrome images.
221
    /// To check that no aliasing occurs, try `check_alias_invariants`. For compact images (no
222
    /// aliasing and no unindexed samples) this is `width*height*channels`. But for both of the
223
    /// other cases, the reasoning is slightly more involved.
224
    ///
225
    /// # Explanation
226
    ///
227
    /// Note that there is a difference between `min_length` and the index of the sample
228
    /// 'one-past-the-end'. This is due to strides that may be larger than the dimension below.
229
    ///
230
    /// ## Example with holes
231
    ///
232
    /// Let's look at an example of a grayscale image with
233
    /// * `width_stride = 1`
234
    /// * `width = 2`
235
    /// * `height_stride = 3`
236
    /// * `height = 2`
237
    ///
238
    /// ```text
239
    /// | x x   | x x m | $
240
    ///  min_length m ^
241
    ///                   ^ one-past-the-end $
242
    /// ```
243
    ///
244
    /// The difference is also extreme for empty images with large strides. The one-past-the-end
245
    /// sample index is still as large as the largest of these strides while `min_length = 0`.
246
    ///
247
    /// ## Example with aliasing
248
    ///
249
    /// The concept gets even more important when you allow samples to alias each other. Here we
250
    /// have the buffer of a small grayscale image where this is the case, this time we will first
251
    /// show the buffer and then the individual rows below.
252
    ///
253
    /// * `width_stride = 1`
254
    /// * `width = 3`
255
    /// * `height_stride = 2`
256
    /// * `height = 2`
257
    ///
258
    /// ```text
259
    ///  1 2 3 4 5 m
260
    /// |1 2 3| row one
261
    ///     |3 4 5| row two
262
    ///            ^ m min_length
263
    ///          ^ ??? one-past-the-end
264
    /// ```
265
    ///
266
    /// This time 'one-past-the-end' is not even simply the largest stride times the extent of its
267
    /// dimension. That still points inside the image because `height*height_stride = 4` but also
268
    /// `index_of(1, 2) = 4`.
269
    #[must_use]
270
0
    pub fn min_length(&self) -> Option<usize> {
271
0
        if self.width == 0 || self.height == 0 || self.channels == 0 {
272
0
            return Some(0);
273
0
        }
274
275
0
        self.index(self.channels - 1, self.width - 1, self.height - 1)
276
0
            .and_then(|idx| idx.checked_add(1))
277
0
    }
278
279
    /// Check if a buffer of length `len` is large enough.
280
    #[must_use]
281
0
    pub fn fits(&self, len: usize) -> bool {
282
0
        self.min_length().is_some_and(|min| len >= min)
283
0
    }
284
285
    /// The extents of this array, in order of increasing strides.
286
0
    fn increasing_stride_dims(&self) -> [Dim; 3] {
287
        // Order extents by strides, then check that each is less equal than the next stride.
288
0
        let mut grouped: [Dim; 3] = [
289
0
            Dim(self.channel_stride, self.channels as usize),
290
0
            Dim(self.width_stride, self.width as usize),
291
0
            Dim(self.height_stride, self.height as usize),
292
0
        ];
293
294
0
        grouped.sort();
295
296
0
        let [min_dim, mid_dim, max_dim] = grouped;
297
0
        assert!(min_dim.stride() <= mid_dim.stride() && mid_dim.stride() <= max_dim.stride());
298
299
0
        grouped
300
0
    }
301
302
    /// If there are any samples aliasing each other.
303
    ///
304
    /// If this is not the case, it would always be safe to allow mutable access to two different
305
    /// samples at the same time. Otherwise, this operation would need additional checks. When one
306
    /// dimension overflows `usize` with its stride we also consider this aliasing.
307
    #[must_use]
308
0
    pub fn has_aliased_samples(&self) -> bool {
309
0
        let [min_dim, mid_dim, max_dim] = self.increasing_stride_dims();
310
311
0
        let min_size = match min_dim.checked_len() {
312
0
            None => return true,
313
0
            Some(size) => size,
314
        };
315
316
0
        let mid_size = match mid_dim.checked_len() {
317
0
            None => return true,
318
0
            Some(size) => size,
319
        };
320
321
0
        if max_dim.checked_len().is_none() {
322
0
            return true;
323
0
        }
324
325
        // Each higher dimension must walk over all of one lower dimension.
326
0
        min_size > mid_dim.stride() || mid_size > max_dim.stride()
327
0
    }
328
329
    /// Check if a buffer fulfills the requirements of a normal form.
330
    ///
331
    /// Certain conversions have preconditions on the structure of the sample buffer that are not
332
    /// captured (by design) by the type system. These are then checked before the conversion. Such
333
    /// checks can all be done in constant time and will not inspect the buffer content. You can
334
    /// perform these checks yourself when the conversion is not required at this moment but maybe
335
    /// still performed later.
336
    #[must_use]
337
0
    pub fn is_normal(&self, form: NormalForm) -> bool {
338
0
        if self.has_aliased_samples() {
339
0
            return false;
340
0
        }
341
342
0
        if form >= NormalForm::PixelPacked && self.channel_stride != 1 {
343
0
            return false;
344
0
        }
345
346
0
        if form >= NormalForm::ImagePacked {
347
            // has aliased already checked for overflows.
348
0
            let grouped = self.increasing_stride_dims();
349
0
            let (min_dim, mid_dim, max_dim) = (grouped[0], grouped[1], grouped[2]);
350
351
0
            if 1 != min_dim.stride() {
352
0
                return false;
353
0
            }
354
355
0
            if min_dim.len() != mid_dim.stride() {
356
0
                return false;
357
0
            }
358
359
0
            if mid_dim.len() != max_dim.stride() {
360
0
                return false;
361
0
            }
362
0
        }
363
364
0
        if form >= NormalForm::RowMajorPacked {
365
0
            if self.width_stride != self.channels as usize {
366
0
                return false;
367
0
            }
368
369
0
            if self.width as usize * self.width_stride != self.height_stride {
370
0
                return false;
371
0
            }
372
0
        }
373
374
0
        if form >= NormalForm::ColumnMajorPacked {
375
0
            if self.height_stride != self.channels as usize {
376
0
                return false;
377
0
            }
378
379
0
            if self.height as usize * self.height_stride != self.width_stride {
380
0
                return false;
381
0
            }
382
0
        }
383
384
0
        true
385
0
    }
386
387
    /// Check that the pixel and the channel index are in bounds.
388
    ///
389
    /// An in-bound coordinate does not yet guarantee that the corresponding calculation of a
390
    /// buffer index does not overflow. However, if such a buffer large enough to hold all samples
391
    /// actually exists in memory, this property of course follows.
392
    #[must_use]
393
0
    pub fn in_bounds(&self, channel: u8, x: u32, y: u32) -> bool {
394
0
        channel < self.channels && x < self.width && y < self.height
395
0
    }
396
397
    /// Resolve the index of a particular sample.
398
    ///
399
    /// `None` if the index is outside the bounds or does not fit into a `usize`.
400
    #[must_use]
401
0
    pub fn index(&self, channel: u8, x: u32, y: u32) -> Option<usize> {
402
0
        if !self.in_bounds(channel, x, y) {
403
0
            return None;
404
0
        }
405
406
0
        self.index_ignoring_bounds(channel as usize, x as usize, y as usize)
407
0
    }
408
409
    /// Get the theoretical position of sample (channel, x, y).
410
    ///
411
    /// The 'check' is for overflow during index calculation, not that it is contained in the
412
    /// image. Two samples may return the same index, even when one of them is out of bounds. This
413
    /// happens when all strides are `0`, i.e. the image is an arbitrarily large monochrome image.
414
    #[must_use]
415
0
    pub fn index_ignoring_bounds(&self, channel: usize, x: usize, y: usize) -> Option<usize> {
416
0
        let idx_c = channel.checked_mul(self.channel_stride);
417
0
        let idx_x = x.checked_mul(self.width_stride);
418
0
        let idx_y = y.checked_mul(self.height_stride);
419
420
0
        let (Some(idx_c), Some(idx_x), Some(idx_y)) = (idx_c, idx_x, idx_y) else {
421
0
            return None;
422
        };
423
424
0
        Some(0usize)
425
0
            .and_then(|b| b.checked_add(idx_c))
426
0
            .and_then(|b| b.checked_add(idx_x))
427
0
            .and_then(|b| b.checked_add(idx_y))
428
0
    }
429
430
    /// Get an index provided it is inbouds.
431
    ///
432
    /// Assumes that the image is backed by some sufficiently large buffer. Then computation can
433
    /// not overflow as we could represent the maximum coordinate. Since overflow is defined either
434
    /// way, this method can not be unsafe.
435
    ///
436
    /// Behavior is *unspecified* if the index is out of bounds or this sample layout would require
437
    /// a buffer larger than `isize::MAX` bytes.
438
    #[must_use]
439
0
    pub fn in_bounds_index(&self, c: u8, x: u32, y: u32) -> usize {
440
0
        let (c_stride, x_stride, y_stride) = self.strides_cwh();
441
0
        (y as usize * y_stride) + (x as usize * x_stride) + (c as usize * c_stride)
442
0
    }
443
444
    /// Shrink the image to the minimum of current and given extents.
445
    ///
446
    /// This does not modify the strides, so that the resulting sample buffer may have holes
447
    /// created by the shrinking operation. Shrinking could also lead to an non-aliasing image when
448
    /// samples had aliased each other before.
449
0
    pub fn shrink_to(&mut self, channels: u8, width: u32, height: u32) {
450
0
        self.channels = self.channels.min(channels);
451
0
        self.width = self.width.min(width);
452
0
        self.height = self.height.min(height);
453
0
    }
454
}
455
456
impl Dim {
457
0
    fn stride(self) -> usize {
458
0
        self.0
459
0
    }
460
461
    /// Length of this dimension in memory.
462
0
    fn checked_len(self) -> Option<usize> {
463
0
        self.0.checked_mul(self.1)
464
0
    }
465
466
0
    fn len(self) -> usize {
467
0
        self.0 * self.1
468
0
    }
469
}
470
471
impl<Buffer> FlatSamples<Buffer> {
472
    /// Get the strides for indexing matrix-like `[(c, w, h)]`.
473
    ///
474
    /// For a row-major layout with grouped samples, this tuple is strictly
475
    /// increasing.
476
0
    pub fn strides_cwh(&self) -> (usize, usize, usize) {
477
0
        self.layout.strides_cwh()
478
0
    }
479
480
    /// Get the dimensions `(channels, width, height)`.
481
    ///
482
    /// The interface is optimized for use with `strides_cwh` instead. The channel extent will be
483
    /// before width and height.
484
0
    pub fn extents(&self) -> (usize, usize, usize) {
485
0
        self.layout.extents()
486
0
    }
487
488
    /// Tuple of bounds in the order of coordinate inputs.
489
    ///
490
    /// This function should be used whenever working with image coordinates opposed to buffer
491
    /// coordinates. The only difference compared to `extents` is the output type.
492
0
    pub fn bounds(&self) -> (u8, u32, u32) {
493
0
        self.layout.bounds()
494
0
    }
495
496
    /// Get a reference based version.
497
0
    pub fn as_ref<T>(&self) -> FlatSamples<&[T]>
498
0
    where
499
0
        Buffer: AsRef<[T]>,
500
    {
501
0
        FlatSamples {
502
0
            samples: self.samples.as_ref(),
503
0
            layout: self.layout,
504
0
            color_hint: self.color_hint,
505
0
        }
506
0
    }
507
508
    /// Get a mutable reference based version.
509
0
    pub fn as_mut<T>(&mut self) -> FlatSamples<&mut [T]>
510
0
    where
511
0
        Buffer: AsMut<[T]>,
512
    {
513
0
        FlatSamples {
514
0
            samples: self.samples.as_mut(),
515
0
            layout: self.layout,
516
0
            color_hint: self.color_hint,
517
0
        }
518
0
    }
519
520
    /// Copy the data into an owned vector.
521
0
    pub fn to_vec<T>(&self) -> FlatSamples<Vec<T>>
522
0
    where
523
0
        T: Clone,
524
0
        Buffer: AsRef<[T]>,
525
    {
526
0
        FlatSamples {
527
0
            samples: self.samples.as_ref().to_vec(),
528
0
            layout: self.layout,
529
0
            color_hint: self.color_hint,
530
0
        }
531
0
    }
532
533
    /// Get a reference to a single sample.
534
    ///
535
    /// This more restrictive than the method based on `std::ops::Index` but guarantees to properly
536
    /// check all bounds and not panic as long as `Buffer::as_ref` does not do so.
537
    ///
538
    /// ```
539
    /// # use image::{RgbImage};
540
    /// let flat = RgbImage::new(480, 640).into_flat_samples();
541
    ///
542
    /// // Get the blue channel at (10, 10).
543
    /// assert!(flat.get_sample(1, 10, 10).is_some());
544
    ///
545
    /// // There is no alpha channel.
546
    /// assert!(flat.get_sample(3, 10, 10).is_none());
547
    /// ```
548
    ///
549
    /// For cases where a special buffer does not provide `AsRef<[T]>`, consider encapsulating
550
    /// bounds checks with `min_length` in a type similar to `View`. Then you may use
551
    /// `in_bounds_index` as a small speedup over the index calculation of this method which relies
552
    /// on `index_ignoring_bounds` since it can not have a-priori knowledge that the sample
553
    /// coordinate is in fact backed by any memory buffer.
554
0
    pub fn get_sample<T>(&self, channel: u8, x: u32, y: u32) -> Option<&T>
555
0
    where
556
0
        Buffer: AsRef<[T]>,
557
    {
558
0
        self.index(channel, x, y)
559
0
            .and_then(|idx| self.samples.as_ref().get(idx))
560
0
    }
561
562
    /// Get a mutable reference to a single sample.
563
    ///
564
    /// This more restrictive than the method based on `std::ops::IndexMut` but guarantees to
565
    /// properly check all bounds and not panic as long as `Buffer::as_ref` does not do so.
566
    /// Contrary to conversion to `ViewMut`, this does not require that samples are packed since it
567
    /// does not need to convert samples to a color representation.
568
    ///
569
    /// **WARNING**: Note that of course samples may alias, so that the mutable reference returned
570
    /// here can in fact modify more than the coordinate in the argument.
571
    ///
572
    /// ```
573
    /// # use image::{RgbImage};
574
    /// let mut flat = RgbImage::new(480, 640).into_flat_samples();
575
    ///
576
    /// // Assign some new color to the blue channel at (10, 10).
577
    /// *flat.get_mut_sample(1, 10, 10).unwrap() = 255;
578
    ///
579
    /// // There is no alpha channel.
580
    /// assert!(flat.get_mut_sample(3, 10, 10).is_none());
581
    /// ```
582
    ///
583
    /// For cases where a special buffer does not provide `AsRef<[T]>`, consider encapsulating
584
    /// bounds checks with `min_length` in a type similar to `View`. Then you may use
585
    /// `in_bounds_index` as a small speedup over the index calculation of this method which relies
586
    /// on `index_ignoring_bounds` since it can not have a-priori knowledge that the sample
587
    /// coordinate is in fact backed by any memory buffer.
588
0
    pub fn get_mut_sample<T>(&mut self, channel: u8, x: u32, y: u32) -> Option<&mut T>
589
0
    where
590
0
        Buffer: AsMut<[T]>,
591
    {
592
0
        match self.index(channel, x, y) {
593
0
            None => None,
594
0
            Some(idx) => self.samples.as_mut().get_mut(idx),
595
        }
596
0
    }
597
598
    /// View this buffer as an image over some type of pixel.
599
    ///
600
    /// This first ensures that all in-bounds coordinates refer to valid indices in the sample
601
    /// buffer. It also checks that the specified pixel format expects the same number of channels
602
    /// that are present in this buffer. Neither are larger nor a smaller number will be accepted.
603
    /// There is no automatic conversion.
604
0
    pub fn as_view<P>(&self) -> Result<View<&[P::Subpixel], P>, Error>
605
0
    where
606
0
        P: Pixel,
607
0
        Buffer: AsRef<[P::Subpixel]>,
608
    {
609
0
        FlatSamples {
610
0
            samples: self.samples.as_ref(),
611
0
            layout: self.layout,
612
0
            color_hint: self.color_hint,
613
0
        }
614
0
        .into_view()
615
0
    }
616
617
    /// Convert this descriptor into a readable image.
618
    ///
619
    /// An owned version of [`Self::as_view`] that uses the original buffer type.
620
    ///
621
    /// FIXME: before exposing this, consider if we want to have strong invariants related to
622
    /// `AsRef` of `Buffer` or not. If we provide a generic one then we can not rely on the trait to
623
    /// give us a stable address or anything but its pure interface. It may make it difficult to
624
    /// introduce efficient code for the relevant case of `Buffer = &[T]`. We could introduce it
625
    /// specifically for that buffer type.
626
0
    pub(crate) fn into_view<P>(self) -> Result<View<Buffer, P>, Error>
627
0
    where
628
0
        P: Pixel,
629
0
        Buffer: AsRef<[P::Subpixel]>,
630
    {
631
0
        if self.layout.channels != P::CHANNEL_COUNT {
632
0
            return Err(Error::ChannelCountMismatch(
633
0
                self.layout.channels,
634
0
                P::CHANNEL_COUNT,
635
0
            ));
636
0
        }
637
638
0
        if !self.layout.fits(self.samples.as_ref().len()) {
639
0
            return Err(Error::TooLarge);
640
0
        }
641
642
0
        Ok(View {
643
0
            inner: self,
644
0
            phantom: PhantomData,
645
0
        })
646
0
    }
Unexecuted instantiation: <image::images::flat::FlatSamples<&[f32]>>::into_view::<image::color::Rgb<f32>>
Unexecuted instantiation: <image::images::flat::FlatSamples<&[f32]>>::into_view::<image::color::Luma<f32>>
Unexecuted instantiation: <image::images::flat::FlatSamples<&[f32]>>::into_view::<image::color::Rgba<f32>>
Unexecuted instantiation: <image::images::flat::FlatSamples<&[f32]>>::into_view::<image::color::LumaA<f32>>
Unexecuted instantiation: <image::images::flat::FlatSamples<&[u8]>>::into_view::<image::color::Rgb<u8>>
Unexecuted instantiation: <image::images::flat::FlatSamples<&[u8]>>::into_view::<image::color::Luma<u8>>
Unexecuted instantiation: <image::images::flat::FlatSamples<&[u8]>>::into_view::<image::color::Rgba<u8>>
Unexecuted instantiation: <image::images::flat::FlatSamples<&[u8]>>::into_view::<image::color::LumaA<u8>>
Unexecuted instantiation: <image::images::flat::FlatSamples<&[u16]>>::into_view::<image::color::Rgb<u16>>
Unexecuted instantiation: <image::images::flat::FlatSamples<&[u16]>>::into_view::<image::color::Luma<u16>>
Unexecuted instantiation: <image::images::flat::FlatSamples<&[u16]>>::into_view::<image::color::Rgba<u16>>
Unexecuted instantiation: <image::images::flat::FlatSamples<&[u16]>>::into_view::<image::color::LumaA<u16>>
647
648
    /// View this buffer but keep mutability at a sample level.
649
    ///
650
    /// This is similar to `as_view` but subtly different from `as_view_mut`. The resulting type
651
    /// can be used as a `GenericImage` with the same prior invariants needed as for `as_view`.
652
    /// It can not be used as a mutable `GenericImage` but does not need channels to be packed in
653
    /// their pixel representation.
654
    ///
655
    /// This first ensures that all in-bounds coordinates refer to valid indices in the sample
656
    /// buffer. It also checks that the specified pixel format expects the same number of channels
657
    /// that are present in this buffer. Neither are larger nor a smaller number will be accepted.
658
    /// There is no automatic conversion.
659
    ///
660
    /// **WARNING**: Note that of course samples may alias, so that the mutable reference returned
661
    /// for one sample can in fact modify other samples as well. Sometimes exactly this is
662
    /// intended.
663
0
    pub fn as_view_with_mut_samples<P>(&mut self) -> Result<View<&mut [P::Subpixel], P>, Error>
664
0
    where
665
0
        P: Pixel,
666
0
        Buffer: AsMut<[P::Subpixel]>,
667
    {
668
0
        if self.layout.channels != P::CHANNEL_COUNT {
669
0
            return Err(Error::ChannelCountMismatch(
670
0
                self.layout.channels,
671
0
                P::CHANNEL_COUNT,
672
0
            ));
673
0
        }
674
675
0
        let as_mut = self.samples.as_mut();
676
0
        if !self.layout.fits(as_mut.len()) {
677
0
            return Err(Error::TooLarge);
678
0
        }
679
680
0
        Ok(View {
681
0
            inner: FlatSamples {
682
0
                samples: as_mut,
683
0
                layout: self.layout,
684
0
                color_hint: self.color_hint,
685
0
            },
686
0
            phantom: PhantomData,
687
0
        })
688
0
    }
689
690
    /// Interpret this buffer as a mutable image.
691
    ///
692
    /// To succeed, the pixels in this buffer may not alias each other and the samples of each
693
    /// pixel must be packed (i.e. `channel_stride` is `1`). The number of channels must be
694
    /// consistent with the channel count expected by the pixel format.
695
    ///
696
    /// This is similar to an `ImageBuffer` except it is a temporary view that is not normalized as
697
    /// strongly. To get an owning version, consider copying the data into an `ImageBuffer`. This
698
    /// provides many more operations, is possibly faster (if not you may want to open an issue) is
699
    /// generally polished. You can also try to convert this buffer inline, see
700
    /// `ImageBuffer::from_raw`.
701
0
    pub fn as_view_mut<P>(&mut self) -> Result<ViewMut<&mut [P::Subpixel], P>, Error>
702
0
    where
703
0
        P: Pixel,
704
0
        Buffer: AsMut<[P::Subpixel]>,
705
    {
706
0
        if !self.layout.is_normal(NormalForm::PixelPacked) {
707
0
            return Err(Error::NormalFormRequired(NormalForm::PixelPacked));
708
0
        }
709
710
0
        if self.layout.channels != P::CHANNEL_COUNT {
711
0
            return Err(Error::ChannelCountMismatch(
712
0
                self.layout.channels,
713
0
                P::CHANNEL_COUNT,
714
0
            ));
715
0
        }
716
717
0
        let as_mut = self.samples.as_mut();
718
0
        if !self.layout.fits(as_mut.len()) {
719
0
            return Err(Error::TooLarge);
720
0
        }
721
722
0
        Ok(ViewMut {
723
0
            inner: FlatSamples {
724
0
                samples: as_mut,
725
0
                layout: self.layout,
726
0
                color_hint: self.color_hint,
727
0
            },
728
0
            phantom: PhantomData,
729
0
        })
730
0
    }
731
732
    /// Turn this buffer into a mutable image.
733
    ///
734
    /// FIXME: before exposing this, consider if we want to have strong invariants related to
735
    /// `AsMut` of `Buffer` or not. If we provide a generic one then we can not rely on the trait to
736
    /// give us a stable address or anything but its pure interface. It may make it difficult to
737
    /// introduce efficient code for the relevant case of `Buffer = &mut [T]`. We could introduce it
738
    /// specifically for that buffer type.
739
0
    pub(crate) fn into_view_mut<P>(mut self) -> Result<ViewMut<Buffer, P>, Error>
740
0
    where
741
0
        P: Pixel,
742
0
        Buffer: AsMut<[P::Subpixel]>,
743
    {
744
0
        if !self.layout.is_normal(NormalForm::PixelPacked) {
745
0
            return Err(Error::NormalFormRequired(NormalForm::PixelPacked));
746
0
        }
747
748
0
        if self.layout.channels != P::CHANNEL_COUNT {
749
0
            return Err(Error::ChannelCountMismatch(
750
0
                self.layout.channels,
751
0
                P::CHANNEL_COUNT,
752
0
            ));
753
0
        }
754
755
0
        if !self.layout.fits(self.samples.as_mut().len()) {
756
0
            return Err(Error::TooLarge);
757
0
        }
758
759
0
        Ok(ViewMut {
760
0
            inner: FlatSamples {
761
0
                samples: self.samples,
762
0
                layout: self.layout,
763
0
                color_hint: self.color_hint,
764
0
            },
765
0
            phantom: PhantomData,
766
0
        })
767
0
    }
Unexecuted instantiation: <image::images::flat::FlatSamples<&mut [f32]>>::into_view_mut::<image::color::Rgb<f32>>
Unexecuted instantiation: <image::images::flat::FlatSamples<&mut [f32]>>::into_view_mut::<image::color::Luma<f32>>
Unexecuted instantiation: <image::images::flat::FlatSamples<&mut [f32]>>::into_view_mut::<image::color::Rgba<f32>>
Unexecuted instantiation: <image::images::flat::FlatSamples<&mut [f32]>>::into_view_mut::<image::color::LumaA<f32>>
Unexecuted instantiation: <image::images::flat::FlatSamples<&mut [u8]>>::into_view_mut::<image::color::Rgb<u8>>
Unexecuted instantiation: <image::images::flat::FlatSamples<&mut [u8]>>::into_view_mut::<image::color::Luma<u8>>
Unexecuted instantiation: <image::images::flat::FlatSamples<&mut [u8]>>::into_view_mut::<image::color::Rgba<u8>>
Unexecuted instantiation: <image::images::flat::FlatSamples<&mut [u8]>>::into_view_mut::<image::color::LumaA<u8>>
Unexecuted instantiation: <image::images::flat::FlatSamples<&mut [u16]>>::into_view_mut::<image::color::Rgb<u16>>
Unexecuted instantiation: <image::images::flat::FlatSamples<&mut [u16]>>::into_view_mut::<image::color::Luma<u16>>
Unexecuted instantiation: <image::images::flat::FlatSamples<&mut [u16]>>::into_view_mut::<image::color::Rgba<u16>>
Unexecuted instantiation: <image::images::flat::FlatSamples<&mut [u16]>>::into_view_mut::<image::color::LumaA<u16>>
768
769
    /// View the samples as a slice.
770
    ///
771
    /// The slice is not limited to the region of the image and not all sample indices are valid
772
    /// indices into this buffer. See `image_mut_slice` as an alternative.
773
0
    pub fn as_slice<T>(&self) -> &[T]
774
0
    where
775
0
        Buffer: AsRef<[T]>,
776
    {
777
0
        self.samples.as_ref()
778
0
    }
779
780
    /// View the samples as a slice.
781
    ///
782
    /// The slice is not limited to the region of the image and not all sample indices are valid
783
    /// indices into this buffer. See `image_mut_slice` as an alternative.
784
0
    pub fn as_mut_slice<T>(&mut self) -> &mut [T]
785
0
    where
786
0
        Buffer: AsMut<[T]>,
787
    {
788
0
        self.samples.as_mut()
789
0
    }
790
791
    /// Return the portion of the buffer that holds sample values.
792
    ///
793
    /// This may fail when the coordinates in this image are either out-of-bounds of the underlying
794
    /// buffer or can not be represented. Note that the slice may have holes that do not correspond
795
    /// to any sample in the image represented by it.
796
0
    pub fn image_slice<T>(&self) -> Option<&[T]>
797
0
    where
798
0
        Buffer: AsRef<[T]>,
799
    {
800
0
        let min_length = self.min_length()?;
801
802
0
        let slice = self.samples.as_ref();
803
0
        if slice.len() < min_length {
804
0
            return None;
805
0
        }
806
807
0
        Some(&slice[..min_length])
808
0
    }
809
810
    /// Mutable portion of the buffer that holds sample values.
811
0
    pub fn image_mut_slice<T>(&mut self) -> Option<&mut [T]>
812
0
    where
813
0
        Buffer: AsMut<[T]>,
814
    {
815
0
        let min_length = self.min_length()?;
816
817
0
        let slice = self.samples.as_mut();
818
0
        if slice.len() < min_length {
819
0
            return None;
820
0
        }
821
822
0
        Some(&mut slice[..min_length])
823
0
    }
824
825
    /// Move the data into an image buffer.
826
    ///
827
    /// This does **not** convert the sample layout. The buffer needs to be in packed row-major form
828
    /// before calling this function. In case of an error, returns the buffer again so that it does
829
    /// not release any allocation.
830
0
    pub fn try_into_buffer<P>(self) -> Result<ImageBuffer<P, Buffer>, (Error, Self)>
831
0
    where
832
0
        P: Pixel,
833
0
        Buffer: Deref<Target = [P::Subpixel]>,
834
    {
835
0
        if !self.is_normal(NormalForm::RowMajorPacked) {
836
0
            return Err((Error::NormalFormRequired(NormalForm::RowMajorPacked), self));
837
0
        }
838
839
0
        if self.layout.channels != P::CHANNEL_COUNT {
840
0
            return Err((
841
0
                Error::ChannelCountMismatch(self.layout.channels, P::CHANNEL_COUNT),
842
0
                self,
843
0
            ));
844
0
        }
845
846
0
        if !self.fits(self.samples.deref().len()) {
847
0
            return Err((Error::TooLarge, self));
848
0
        }
849
850
        Ok(
851
0
            ImageBuffer::from_raw(self.layout.width, self.layout.height, self.samples)
852
0
                .unwrap_or_else(|| {
853
0
                    panic!("Preconditions should have been ensured before conversion")
854
                }),
855
        )
856
0
    }
857
858
    /// Get the minimum length of a buffer such that all in-bounds samples have valid indices.
859
    ///
860
    /// This method will allow zero strides, allowing compact representations of monochrome images.
861
    /// To check that no aliasing occurs, try `check_alias_invariants`. For compact images (no
862
    /// aliasing and no unindexed samples) this is `width*height*channels`. But for both of the
863
    /// other cases, the reasoning is slightly more involved.
864
    ///
865
    /// # Explanation
866
    ///
867
    /// Note that there is a difference between `min_length` and the index of the sample
868
    /// 'one-past-the-end'. This is due to strides that may be larger than the dimension below.
869
    ///
870
    /// ## Example with holes
871
    ///
872
    /// Let's look at an example of a grayscale image with
873
    /// * `width_stride = 1`
874
    /// * `width = 2`
875
    /// * `height_stride = 3`
876
    /// * `height = 2`
877
    ///
878
    /// ```text
879
    /// | x x   | x x m | $
880
    ///  min_length m ^
881
    ///                   ^ one-past-the-end $
882
    /// ```
883
    ///
884
    /// The difference is also extreme for empty images with large strides. The one-past-the-end
885
    /// sample index is still as large as the largest of these strides while `min_length = 0`.
886
    ///
887
    /// ## Example with aliasing
888
    ///
889
    /// The concept gets even more important when you allow samples to alias each other. Here we
890
    /// have the buffer of a small grayscale image where this is the case, this time we will first
891
    /// show the buffer and then the individual rows below.
892
    ///
893
    /// * `width_stride = 1`
894
    /// * `width = 3`
895
    /// * `height_stride = 2`
896
    /// * `height = 2`
897
    ///
898
    /// ```text
899
    ///  1 2 3 4 5 m
900
    /// |1 2 3| row one
901
    ///     |3 4 5| row two
902
    ///            ^ m min_length
903
    ///          ^ ??? one-past-the-end
904
    /// ```
905
    ///
906
    /// This time 'one-past-the-end' is not even simply the largest stride times the extent of its
907
    /// dimension. That still points inside the image because `height*height_stride = 4` but also
908
    /// `index_of(1, 2) = 4`.
909
0
    pub fn min_length(&self) -> Option<usize> {
910
0
        self.layout.min_length()
911
0
    }
Unexecuted instantiation: <image::images::flat::FlatSamples<&mut [f32]>>::min_length
Unexecuted instantiation: <image::images::flat::FlatSamples<&mut [u8]>>::min_length
Unexecuted instantiation: <image::images::flat::FlatSamples<&mut [u16]>>::min_length
912
913
    /// Check if a buffer of length `len` is large enough.
914
0
    pub fn fits(&self, len: usize) -> bool {
915
0
        self.layout.fits(len)
916
0
    }
917
918
    /// If there are any samples aliasing each other.
919
    ///
920
    /// If this is not the case, it would always be safe to allow mutable access to two different
921
    /// samples at the same time. Otherwise, this operation would need additional checks. When one
922
    /// dimension overflows `usize` with its stride we also consider this aliasing.
923
0
    pub fn has_aliased_samples(&self) -> bool {
924
0
        self.layout.has_aliased_samples()
925
0
    }
926
927
    /// Check if a buffer fulfills the requirements of a normal form.
928
    ///
929
    /// Certain conversions have preconditions on the structure of the sample buffer that are not
930
    /// captured (by design) by the type system. These are then checked before the conversion. Such
931
    /// checks can all be done in constant time and will not inspect the buffer content. You can
932
    /// perform these checks yourself when the conversion is not required at this moment but maybe
933
    /// still performed later.
934
0
    pub fn is_normal(&self, form: NormalForm) -> bool {
935
0
        self.layout.is_normal(form)
936
0
    }
937
938
    /// Check that the pixel and the channel index are in bounds.
939
    ///
940
    /// An in-bound coordinate does not yet guarantee that the corresponding calculation of a
941
    /// buffer index does not overflow. However, if such a buffer large enough to hold all samples
942
    /// actually exists in memory, this property of course follows.
943
0
    pub fn in_bounds(&self, channel: u8, x: u32, y: u32) -> bool {
944
0
        self.layout.in_bounds(channel, x, y)
945
0
    }
946
947
    /// Resolve the index of a particular sample.
948
    ///
949
    /// `None` if the index is outside the bounds or does not fit into a `usize`.
950
0
    pub fn index(&self, channel: u8, x: u32, y: u32) -> Option<usize> {
951
0
        self.layout.index(channel, x, y)
952
0
    }
Unexecuted instantiation: <image::images::flat::FlatSamples<&[f32]>>::index
Unexecuted instantiation: <image::images::flat::FlatSamples<&[u8]>>::index
Unexecuted instantiation: <image::images::flat::FlatSamples<&[u16]>>::index
953
954
    /// Get the theoretical position of sample (x, y, channel).
955
    ///
956
    /// The 'check' is for overflow during index calculation, not that it is contained in the
957
    /// image. Two samples may return the same index, even when one of them is out of bounds. This
958
    /// happens when all strides are `0`, i.e. the image is an arbitrarily large monochrome image.
959
0
    pub fn index_ignoring_bounds(&self, channel: usize, x: usize, y: usize) -> Option<usize> {
960
0
        self.layout.index_ignoring_bounds(channel, x, y)
961
0
    }
962
963
    /// Get an index provided it is inbouds.
964
    ///
965
    /// Assumes that the image is backed by some sufficiently large buffer. Then computation can
966
    /// not overflow as we could represent the maximum coordinate. Since overflow is defined either
967
    /// way, this method can not be unsafe.
968
0
    pub fn in_bounds_index(&self, channel: u8, x: u32, y: u32) -> usize {
969
0
        self.layout.in_bounds_index(channel, x, y)
970
0
    }
971
972
    /// Shrink the image to the minimum of current and given extents.
973
    ///
974
    /// This does not modify the strides, so that the resulting sample buffer may have holes
975
    /// created by the shrinking operation. Shrinking could also lead to an non-aliasing image when
976
    /// samples had aliased each other before.
977
0
    pub fn shrink_to(&mut self, channels: u8, width: u32, height: u32) {
978
0
        self.layout.shrink_to(channels, width, height);
979
0
    }
980
}
981
982
impl<'buf, Subpixel> FlatSamples<&'buf [Subpixel]> {
983
    /// Create a monocolor image from a single pixel.
984
    ///
985
    /// This can be used as a very cheap source of a `GenericImageView` with an arbitrary number of
986
    /// pixels of a single color, without any dynamic allocation.
987
    ///
988
    /// See also [`View::with_monocolor`].
989
0
    pub fn with_monocolor<P>(pixel: &'buf P, width: u32, height: u32) -> Self
990
0
    where
991
0
        P: Pixel<Subpixel = Subpixel>,
992
0
        Subpixel: crate::Primitive,
993
    {
994
0
        FlatSamples {
995
0
            samples: pixel.channels(),
996
0
            layout: SampleLayout {
997
0
                channels: P::CHANNEL_COUNT,
998
0
                channel_stride: 1,
999
0
                width,
1000
0
                width_stride: 0,
1001
0
                height,
1002
0
                height_stride: 0,
1003
0
            },
1004
0
1005
0
            // TODO this value is never set. It should be set in all places where the Pixel type implements PixelWithColorType
1006
0
            color_hint: None,
1007
0
        }
1008
0
    }
1009
}
1010
1011
/// A flat buffer that can be used as an image view.
1012
///
1013
/// This is a nearly trivial wrapper around a buffer but at least sanitizes by checking the buffer
1014
/// length first and constraining the pixel type.
1015
///
1016
/// Note that this does not eliminate panics as the `AsRef<[T]>` implementation of `Buffer` may be
1017
/// unreliable, i.e. return different buffers at different times. This of course is a non-issue for
1018
/// all common collections where the bounds check once must be enough.
1019
///
1020
/// # Inner invariants
1021
///
1022
/// * For all indices inside bounds, the corresponding index is valid in the buffer
1023
/// * `P::channel_count()` agrees with `self.inner.layout.channels`
1024
#[derive(Clone, Debug)]
1025
pub struct View<Buffer, P: Pixel>
1026
where
1027
    Buffer: AsRef<[P::Subpixel]>,
1028
{
1029
    inner: FlatSamples<Buffer>,
1030
    phantom: PhantomData<P>,
1031
}
1032
1033
/// Type alias for a view based on a pixel's channels.
1034
pub type ViewOfPixel<'lt, P> = View<&'lt [<P as Pixel>::Subpixel], P>;
1035
1036
/// A mutable owning version of a flat buffer.
1037
///
1038
/// While this wraps a buffer similar to `ImageBuffer`, this is mostly intended as a utility. The
1039
/// library endorsed normalized representation is still `ImageBuffer`. Also, the implementation of
1040
/// `AsMut<[P::Subpixel]>` must always yield the same buffer. Therefore there is no public way to
1041
/// construct this with an owning buffer.
1042
///
1043
/// # Inner invariants
1044
///
1045
/// * For all indices inside bounds, the corresponding index is valid in the buffer
1046
/// * There is no aliasing of samples
1047
/// * The samples are packed, i.e. `self.inner.layout.sample_stride == 1`
1048
/// * `P::channel_count()` agrees with `self.inner.layout.channels`
1049
#[derive(Clone, Debug)]
1050
pub struct ViewMut<Buffer, P: Pixel>
1051
where
1052
    Buffer: AsMut<[P::Subpixel]>,
1053
{
1054
    inner: FlatSamples<Buffer>,
1055
    phantom: PhantomData<P>,
1056
}
1057
1058
/// Type alias for a mutable view based on a pixel's channels.
1059
pub type ViewMutOfPixel<'lt, P> = ViewMut<&'lt mut [<P as Pixel>::Subpixel], P>;
1060
1061
/// Denotes invalid flat sample buffers when trying to convert to stricter types.
1062
///
1063
/// The biggest use case being `ImageBuffer` which expects closely packed
1064
/// samples in a row major matrix representation. But this error type may be
1065
/// reused for other import functions. A more versatile user may also try to
1066
/// correct the underlying representation depending on the error variant.
1067
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1068
pub enum Error {
1069
    /// The represented image was too large.
1070
    ///
1071
    /// The optional value denotes a possibly accepted maximal bound.
1072
    TooLarge,
1073
1074
    /// The represented image can not use this representation.
1075
    ///
1076
    /// Has an additional value of the normalized form that would be accepted.
1077
    NormalFormRequired(NormalForm),
1078
1079
    /// The color format did not match the channel count.
1080
    ///
1081
    /// In some cases you might be able to fix this by lowering the reported pixel count of the
1082
    /// buffer without touching the strides.
1083
    ///
1084
    /// In very special circumstances you *may* do the opposite. This is **VERY** dangerous but not
1085
    /// directly memory unsafe although that will likely alias pixels. One scenario is when you
1086
    /// want to construct an `Rgba` image but have only 3 bytes per pixel and for some reason don't
1087
    /// care about the value of the alpha channel even though you need `Rgba`.
1088
    ChannelCountMismatch(u8, u8),
1089
1090
    /// Deprecated - `ChannelCountMismatch` is used instead
1091
    WrongColor(ColorType),
1092
}
1093
1094
/// Different normal forms of buffers.
1095
///
1096
/// A normal form is an unaliased buffer with some additional constraints.  The `ÃŒmageBuffer` uses
1097
/// row major form with packed samples.
1098
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1099
pub enum NormalForm {
1100
    /// No pixel aliases another.
1101
    ///
1102
    /// Unaliased also guarantees that all index calculations in the image bounds using
1103
    /// `dim_index*dim_stride` (such as `x*width_stride + y*height_stride`) do not overflow.
1104
    Unaliased,
1105
1106
    /// At least pixels are packed.
1107
    ///
1108
    /// Images of these types can wrap `[T]`-slices into the standard color types. This is a
1109
    /// precondition for `GenericImage` which requires by-reference access to pixels.
1110
    PixelPacked,
1111
1112
    /// All samples are packed.
1113
    ///
1114
    /// This is orthogonal to `PixelPacked`. It requires that there are no holes in the image but
1115
    /// it is not necessary that the pixel samples themselves are adjacent. An example of this
1116
    /// behaviour is a planar image layout.
1117
    ImagePacked,
1118
1119
    /// The samples are in row-major form and all samples are packed.
1120
    ///
1121
    /// In addition to `PixelPacked` and `ImagePacked` this also asserts that the pixel matrix is
1122
    /// in row-major form.
1123
    RowMajorPacked,
1124
1125
    /// The samples are in column-major form and all samples are packed.
1126
    ///
1127
    /// In addition to `PixelPacked` and `ImagePacked` this also asserts that the pixel matrix is
1128
    /// in column-major form.
1129
    ColumnMajorPacked,
1130
}
1131
1132
impl<Buffer, P: Pixel> View<Buffer, P>
1133
where
1134
    Buffer: AsRef<[P::Subpixel]>,
1135
{
1136
    /// Take out the sample buffer.
1137
    ///
1138
    /// Gives up the normalization invariants on the buffer format.
1139
0
    pub fn into_inner(self) -> FlatSamples<Buffer> {
1140
0
        self.inner
1141
0
    }
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Rgb<f32>>>::into_inner
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Luma<f32>>>::into_inner
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Rgba<f32>>>::into_inner
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::LumaA<f32>>>::into_inner
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Rgb<u8>>>::into_inner
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Luma<u8>>>::into_inner
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Rgba<u8>>>::into_inner
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::LumaA<u8>>>::into_inner
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Rgb<u16>>>::into_inner
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Luma<u16>>>::into_inner
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Rgba<u16>>>::into_inner
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::LumaA<u16>>>::into_inner
1142
1143
    /// Get a reference on the inner sample descriptor.
1144
    ///
1145
    /// There is no mutable counterpart as modifying the buffer format, including strides and
1146
    /// lengths, could invalidate the accessibility invariants of the `View`. It is not specified
1147
    /// if the inner buffer is the same as the buffer of the image from which this view was
1148
    /// created. It might have been truncated as an optimization.
1149
0
    pub fn flat(&self) -> &FlatSamples<Buffer> {
1150
0
        &self.inner
1151
0
    }
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Rgb<f32>>>::flat
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Luma<f32>>>::flat
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Rgba<f32>>>::flat
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::LumaA<f32>>>::flat
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Rgb<u8>>>::flat
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Luma<u8>>>::flat
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Rgba<u8>>>::flat
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::LumaA<u8>>>::flat
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Rgb<u16>>>::flat
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Luma<u16>>>::flat
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Rgba<u16>>>::flat
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::LumaA<u16>>>::flat
1152
1153
    /// Get a reference on the inner buffer.
1154
    ///
1155
    /// There is no mutable counter part since it is not intended to allow you to reassign the
1156
    /// buffer or otherwise change its size or properties.
1157
0
    pub fn samples(&self) -> &Buffer {
1158
0
        &self.inner.samples
1159
0
    }
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Rgb<f32>>>::samples
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Luma<f32>>>::samples
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Rgba<f32>>>::samples
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::LumaA<f32>>>::samples
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Rgb<u8>>>::samples
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Luma<u8>>>::samples
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Rgba<u8>>>::samples
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::LumaA<u8>>>::samples
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Rgb<u16>>>::samples
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Luma<u16>>>::samples
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Rgba<u16>>>::samples
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::LumaA<u16>>>::samples
1160
1161
    /// Get a reference to a selected subpixel if it is in-bounds.
1162
    ///
1163
    /// This method will return `None` when the sample is out-of-bounds. All errors that could
1164
    /// occur due to overflow have been eliminated while construction the `View`.
1165
0
    pub fn get_sample(&self, channel: u8, x: u32, y: u32) -> Option<&P::Subpixel> {
1166
0
        if !self.inner.in_bounds(channel, x, y) {
1167
0
            return None;
1168
0
        }
1169
1170
0
        let index = self.inner.in_bounds_index(channel, x, y);
1171
        // Should always be `Some(_)` but checking is more costly.
1172
0
        self.samples().as_ref().get(index)
1173
0
    }
1174
1175
    /// Get a mutable reference to a selected subpixel if it is in-bounds.
1176
    ///
1177
    /// This is relevant only when constructed with `FlatSamples::as_view_with_mut_samples`.  This
1178
    /// method will return `None` when the sample is out-of-bounds. All errors that could occur due
1179
    /// to overflow have been eliminated while construction the `View`.
1180
    ///
1181
    /// **WARNING**: Note that of course samples may alias, so that the mutable reference returned
1182
    /// here can in fact modify more than the coordinate in the argument.
1183
0
    pub fn get_mut_sample(&mut self, channel: u8, x: u32, y: u32) -> Option<&mut P::Subpixel>
1184
0
    where
1185
0
        Buffer: AsMut<[P::Subpixel]>,
1186
    {
1187
0
        if !self.inner.in_bounds(channel, x, y) {
1188
0
            return None;
1189
0
        }
1190
1191
0
        let index = self.inner.in_bounds_index(channel, x, y);
1192
        // Should always be `Some(_)` but checking is more costly.
1193
0
        self.inner.samples.as_mut().get_mut(index)
1194
0
    }
1195
1196
    /// Get the minimum length of a buffer such that all in-bounds samples have valid indices.
1197
    ///
1198
    /// See `FlatSamples::min_length`. This method will always succeed.
1199
0
    pub fn min_length(&self) -> usize {
1200
0
        self.inner.min_length().unwrap()
1201
0
    }
1202
1203
    /// Return the portion of the buffer that holds sample values.
1204
    ///
1205
    /// While this can not fail–the validity of all coordinates has been validated during the
1206
    /// conversion from `FlatSamples`–the resulting slice may still contain holes.
1207
0
    pub fn image_slice(&self) -> &[P::Subpixel] {
1208
0
        &self.samples().as_ref()[..self.min_length()]
1209
0
    }
1210
1211
0
    pub(crate) fn strides_wh(&self) -> (usize, usize) {
1212
        // Note `c` stride must be `1` for a valid `View` so we can ignore it here.
1213
0
        let (_, w, h) = self.inner.layout.strides_cwh();
1214
0
        (w, h)
1215
0
    }
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Rgb<f32>>>::strides_wh
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Luma<f32>>>::strides_wh
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Rgba<f32>>>::strides_wh
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::LumaA<f32>>>::strides_wh
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Rgb<u8>>>::strides_wh
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Luma<u8>>>::strides_wh
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Rgba<u8>>>::strides_wh
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::LumaA<u8>>>::strides_wh
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Rgb<u16>>>::strides_wh
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Luma<u16>>>::strides_wh
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Rgba<u16>>>::strides_wh
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::LumaA<u16>>>::strides_wh
1216
1217
    /// Return the mutable portion of the buffer that holds sample values.
1218
    ///
1219
    /// This is relevant only when constructed with `FlatSamples::as_view_with_mut_samples`. While
1220
    /// this can not fail–the validity of all coordinates has been validated during the conversion
1221
    /// from `FlatSamples`–the resulting slice may still contain holes.
1222
0
    pub fn image_mut_slice(&mut self) -> &mut [P::Subpixel]
1223
0
    where
1224
0
        Buffer: AsMut<[P::Subpixel]>,
1225
    {
1226
0
        let min_length = self.min_length();
1227
0
        &mut self.inner.samples.as_mut()[..min_length]
1228
0
    }
1229
1230
    /// Shrink the inner image.
1231
    ///
1232
    /// The new dimensions will be the minimum of the previous dimensions. Since the set of
1233
    /// in-bounds pixels afterwards is a subset of the current ones, this is allowed on a `View`.
1234
    /// Note that you can not change the number of channels as an intrinsic property of `P`.
1235
0
    pub fn shrink_to(&mut self, width: u32, height: u32) {
1236
0
        let channels = self.inner.layout.channels;
1237
0
        self.inner.shrink_to(channels, width, height);
1238
0
    }
1239
1240
    /// Try to convert this into an image with mutable pixels.
1241
    ///
1242
    /// The resulting image implements `GenericImage` in addition to `GenericImageView`. While this
1243
    /// has mutable samples, it does not enforce that pixel can not alias and that samples are
1244
    /// packed enough for a mutable pixel reference. This is slightly cheaper than the chain
1245
    /// `self.into_inner().as_view_mut()` and keeps the `View` alive on failure.
1246
    ///
1247
    /// ```
1248
    /// # use image::RgbImage;
1249
    /// # use image::Rgb;
1250
    /// let mut buffer = RgbImage::new(480, 640).into_flat_samples();
1251
    /// let view = buffer.as_view_with_mut_samples::<Rgb<u8>>().unwrap();
1252
    ///
1253
    /// // Inspect some pixels, …
1254
    ///
1255
    /// // Doesn't fail because it was originally an `RgbImage`.
1256
    /// let view_mut = view.try_upgrade().unwrap();
1257
    /// ```
1258
0
    pub fn try_upgrade(self) -> Result<ViewMut<Buffer, P>, (Error, Self)>
1259
0
    where
1260
0
        Buffer: AsMut<[P::Subpixel]>,
1261
    {
1262
0
        if !self.inner.is_normal(NormalForm::PixelPacked) {
1263
0
            return Err((Error::NormalFormRequired(NormalForm::PixelPacked), self));
1264
0
        }
1265
1266
        // No length check or channel count check required, all the same.
1267
0
        Ok(ViewMut {
1268
0
            inner: self.inner,
1269
0
            phantom: PhantomData,
1270
0
        })
1271
0
    }
1272
1273
    /// If the underlying samples are in row-major form and packed pixels, return
1274
    /// an iterator over the rows of the image.
1275
0
    pub(crate) fn iter_rows(&self) -> Option<impl Iterator<Item = &[P::Subpixel]> + '_> {
1276
0
        let layout = self.flat().layout;
1277
0
        let channels = P::CHANNEL_COUNT;
1278
0
        if layout.channel_stride != 1
1279
0
            || layout.channels != channels
1280
0
            || layout.width_stride != channels as usize
1281
        {
1282
0
            return None;
1283
0
        }
1284
1285
0
        let data = self.samples().as_ref();
1286
0
        let row_len = layout.width as usize * channels as usize;
1287
0
        let row_stride = layout.height_stride;
1288
1289
        // Note: We do **NOT** assume row_len <= row_stride. Rows may overlap
1290
        // (or even all be the same slice when row_stride == 0). So the usual
1291
        // iter().chunks() strategy does not work here.
1292
1293
0
        Some((0..layout.height as usize).map(move |y| {
1294
0
            let start = y * row_stride;
1295
0
            &data[start..start + row_len]
1296
0
        }))
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Rgb<f32>>>::iter_rows::{closure#0}
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Luma<f32>>>::iter_rows::{closure#0}
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Rgba<f32>>>::iter_rows::{closure#0}
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::LumaA<f32>>>::iter_rows::{closure#0}
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Rgb<u8>>>::iter_rows::{closure#0}
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Luma<u8>>>::iter_rows::{closure#0}
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Rgba<u8>>>::iter_rows::{closure#0}
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::LumaA<u8>>>::iter_rows::{closure#0}
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Rgb<u16>>>::iter_rows::{closure#0}
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Luma<u16>>>::iter_rows::{closure#0}
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Rgba<u16>>>::iter_rows::{closure#0}
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::LumaA<u16>>>::iter_rows::{closure#0}
1297
0
    }
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Rgb<f32>>>::iter_rows
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Luma<f32>>>::iter_rows
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Rgba<f32>>>::iter_rows
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::LumaA<f32>>>::iter_rows
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Rgb<u8>>>::iter_rows
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Luma<u8>>>::iter_rows
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Rgba<u8>>>::iter_rows
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::LumaA<u8>>>::iter_rows
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Rgb<u16>>>::iter_rows
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Luma<u16>>>::iter_rows
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Rgba<u16>>>::iter_rows
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::LumaA<u16>>>::iter_rows
1298
}
1299
1300
impl<'buf, P: Pixel> View<&'buf [P::Subpixel], P> {
1301
    /// Create a monocolor image from a single pixel.
1302
    ///
1303
    /// This can be used as a very cheap source of a `GenericImageView` with an arbitrary number of
1304
    /// pixels of a single color, without any dynamic allocation.
1305
    ///
1306
    /// ## Examples
1307
    ///
1308
    /// ```
1309
    /// # fn paint_something<T>(_: T) {}
1310
    /// use image::{flat::View, GenericImage, RgbImage, Rgb};
1311
    ///
1312
    /// let gray = Rgb([20, 20, 20]);
1313
    /// let background = View::with_monocolor(&gray, 200, 200);
1314
    ///
1315
    /// let mut image = RgbImage::from_pixel(200, 200, gray);
1316
    /// paint_something(&mut image);
1317
    ///
1318
    /// // Reset the canvas
1319
    /// image.copy_from(&background, 0, 0);
1320
    /// ```
1321
0
    pub fn with_monocolor(pixel: &'buf P, width: u32, height: u32) -> Self
1322
0
    where
1323
0
        P::Subpixel: crate::Primitive,
1324
    {
1325
        // Reuse the validation, in case of `P::channels()` funny business. (View internally prefers
1326
        // using the constant ``CHANNEL_COUNT` where appropriate afterwards to avoid re-executing a
1327
        // potential adversarial trait impl).
1328
0
        FlatSamples::with_monocolor(pixel, width, height)
1329
0
            .into_view()
1330
0
            .unwrap()
1331
0
    }
1332
}
1333
1334
impl<Buffer, P: Pixel> ViewMut<Buffer, P>
1335
where
1336
    Buffer: AsMut<[P::Subpixel]>,
1337
{
1338
    /// Take out the sample buffer.
1339
    ///
1340
    /// Gives up the normalization invariants on the buffer format.
1341
0
    pub fn into_inner(self) -> FlatSamples<Buffer> {
1342
0
        self.inner
1343
0
    }
1344
1345
    /// Get a reference on the sample buffer descriptor.
1346
    ///
1347
    /// There is no mutable counterpart as modifying the buffer format, including strides and
1348
    /// lengths, could invalidate the accessibility invariants of the `View`. It is not specified
1349
    /// if the inner buffer is the same as the buffer of the image from which this view was
1350
    /// created. It might have been truncated as an optimization.
1351
0
    pub fn flat(&self) -> &FlatSamples<Buffer> {
1352
0
        &self.inner
1353
0
    }
1354
1355
    /// Get a reference on the inner buffer.
1356
    ///
1357
    /// There is no mutable counter part since it is not intended to allow you to reassign the
1358
    /// buffer or otherwise change its size or properties. However, its contents can be accessed
1359
    /// mutable through a slice with `image_mut_slice`.
1360
0
    pub fn samples(&self) -> &Buffer {
1361
0
        &self.inner.samples
1362
0
    }
1363
1364
    /// Get the minimum length of a buffer such that all in-bounds samples have valid indices.
1365
    ///
1366
    /// See `FlatSamples::min_length`. This method will always succeed.
1367
0
    pub fn min_length(&self) -> usize {
1368
0
        self.inner.min_length().unwrap()
1369
0
    }
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [f32], image::color::Rgb<f32>>>::min_length
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [f32], image::color::Luma<f32>>>::min_length
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [f32], image::color::Rgba<f32>>>::min_length
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [f32], image::color::LumaA<f32>>>::min_length
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u8], image::color::Rgb<u8>>>::min_length
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u8], image::color::Luma<u8>>>::min_length
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u8], image::color::Rgba<u8>>>::min_length
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u8], image::color::LumaA<u8>>>::min_length
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u16], image::color::Rgb<u16>>>::min_length
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u16], image::color::Luma<u16>>>::min_length
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u16], image::color::Rgba<u16>>>::min_length
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u16], image::color::LumaA<u16>>>::min_length
1370
1371
    /// Get a reference to a selected subpixel.
1372
    ///
1373
    /// This method will return `None` when the sample is out-of-bounds. All errors that could
1374
    /// occur due to overflow have been eliminated while construction the `View`.
1375
0
    pub fn get_sample(&self, channel: u8, x: u32, y: u32) -> Option<&P::Subpixel>
1376
0
    where
1377
0
        Buffer: AsRef<[P::Subpixel]>,
1378
    {
1379
0
        if !self.inner.in_bounds(channel, x, y) {
1380
0
            return None;
1381
0
        }
1382
1383
0
        let index = self.inner.in_bounds_index(channel, x, y);
1384
        // Should always be `Some(_)` but checking is more costly.
1385
0
        self.samples().as_ref().get(index)
1386
0
    }
1387
1388
    /// Get a mutable reference to a selected sample.
1389
    ///
1390
    /// This method will return `None` when the sample is out-of-bounds. All errors that could
1391
    /// occur due to overflow have been eliminated while construction the `View`.
1392
0
    pub fn get_mut_sample(&mut self, channel: u8, x: u32, y: u32) -> Option<&mut P::Subpixel> {
1393
0
        if !self.inner.in_bounds(channel, x, y) {
1394
0
            return None;
1395
0
        }
1396
1397
0
        let index = self.inner.in_bounds_index(channel, x, y);
1398
        // Should always be `Some(_)` but checking is more costly.
1399
0
        self.inner.samples.as_mut().get_mut(index)
1400
0
    }
1401
1402
    /// Return the portion of the buffer that holds sample values.
1403
    ///
1404
    /// While this can not fail–the validity of all coordinates has been validated during the
1405
    /// conversion from `FlatSamples`–the resulting slice may still contain holes.
1406
0
    pub fn image_slice(&self) -> &[P::Subpixel]
1407
0
    where
1408
0
        Buffer: AsRef<[P::Subpixel]>,
1409
    {
1410
0
        &self.inner.samples.as_ref()[..self.min_length()]
1411
0
    }
1412
1413
    /// Return the mutable buffer that holds sample values.
1414
0
    pub fn image_mut_slice(&mut self) -> &mut [P::Subpixel] {
1415
0
        let length = self.min_length();
1416
0
        &mut self.inner.samples.as_mut()[..length]
1417
0
    }
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [f32], image::color::Rgb<f32>>>::image_mut_slice
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [f32], image::color::Luma<f32>>>::image_mut_slice
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [f32], image::color::Rgba<f32>>>::image_mut_slice
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [f32], image::color::LumaA<f32>>>::image_mut_slice
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u8], image::color::Rgb<u8>>>::image_mut_slice
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u8], image::color::Luma<u8>>>::image_mut_slice
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u8], image::color::Rgba<u8>>>::image_mut_slice
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u8], image::color::LumaA<u8>>>::image_mut_slice
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u16], image::color::Rgb<u16>>>::image_mut_slice
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u16], image::color::Luma<u16>>>::image_mut_slice
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u16], image::color::Rgba<u16>>>::image_mut_slice
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u16], image::color::LumaA<u16>>>::image_mut_slice
1418
1419
    /// Shrink the inner image.
1420
    ///
1421
    /// The new dimensions will be the minimum of the previous dimensions. Since the set of
1422
    /// in-bounds pixels afterwards is a subset of the current ones, this is allowed on a `View`.
1423
    /// Note that you can not change the number of channels as an intrinsic property of `P`.
1424
0
    pub fn shrink_to(&mut self, width: u32, height: u32) {
1425
0
        let channels = self.inner.layout.channels;
1426
0
        self.inner.shrink_to(channels, width, height);
1427
0
    }
1428
1429
    /// Copy from, assuming that the source is not a simple view layout.
1430
0
    pub(crate) fn inner_copy_from<O>(&mut self, other: &O, x: u32, y: u32) -> crate::ImageResult<()>
1431
0
    where
1432
0
        O: GenericImageView<Pixel = P>,
1433
0
        // Note: not necessary for the implementation per-se but this allows the use of
1434
0
        // `GenericImage`/`GenericImageView` methods and so `test_in_bounds_of`.
1435
0
        Buffer: AsRef<[P::Subpixel]>,
1436
    {
1437
        // Do bounds checking here so we can use the non-bounds-checking
1438
        // functions to copy pixels.
1439
0
        let target = Rect::from_image_at(other, x, y);
1440
0
        target.test_in_bounds_of(self)?;
1441
1442
0
        if self.image_mut_slice().is_empty() {
1443
            // Apparently this is an empty image but the other is inbounds so it is *also* an empty
1444
            // image. Well, without anything to do let's signal success.
1445
0
            return Ok(());
1446
0
        }
1447
1448
0
        let (c, w, h) = self.inner.layout.strides_cwh();
1449
        // This will be assumed to hold in the following.
1450
0
        debug_assert_eq!(
1451
            c, 1,
1452
0
            "Precondition for a `ViewMut`, each Pixel is a slice of channels"
1453
        );
1454
1455
0
        if w == usize::from(P::CHANNEL_COUNT) {
1456
0
            let layout = self.inner.layout;
1457
0
            let buffer = self.image_mut_slice();
1458
1459
            // Edge case: if we have a height of `1` then its height stride may be zero without
1460
            // violating the aliasing requirements. We will instead always use the whole slice in
1461
            // that case. Avoids the potential panic.
1462
0
            let row_len = if layout.height <= 1 { buffer.len() } else { h };
1463
0
            let rows = buffer.chunks_exact_mut(row_len);
1464
1465
            // `ViewMut` has an actual invariant on its buffer size (even though it is generic) that
1466
            // is enforced by construction.
1467
0
            assert!(
1468
                // Since we verified `test_in_bounds_of´ and the target rectangle is a trustworthy
1469
                // value, not a generic interface, the addition on the right hand does not overflow
1470
                // `u32` as it still fits into our own height.
1471
0
                rows.len() >= (target.y + target.height) as usize,
1472
0
                "ViewMut buffer inconsistent with its layout"
1473
            );
1474
1475
0
            for (k, row) in rows
1476
0
                .skip(target.y as usize)
1477
0
                .take(target.height as usize)
1478
0
                .enumerate()
1479
            {
1480
                // Adjust the row according to the target region.
1481
0
                let row = &mut row[target.x as usize * usize::from(P::CHANNEL_COUNT)..];
1482
0
                let row = &mut row[..target.width as usize * usize::from(P::CHANNEL_COUNT)];
1483
0
                let chunks = row.chunks_exact_mut(usize::from(P::CHANNEL_COUNT));
1484
1485
0
                for (i, out_pix) in (0..target.width).zip(chunks) {
1486
0
                    let p = other.get_pixel(i, k as u32);
1487
0
                    *P::from_slice_mut(out_pix) = p;
1488
0
                }
1489
            }
1490
1491
0
            return Ok(());
1492
0
        }
1493
1494
0
        let layout = self.inner.layout;
1495
0
        let samples = self.image_mut_slice();
1496
1497
0
        for k in 0..target.height {
1498
0
            for i in 0..target.width {
1499
0
                let p = other.get_pixel(i, k);
1500
0
                let idx = layout.in_bounds_index(0, i + x, k + y);
1501
0
                let channels = &mut samples[idx..][..usize::from(P::CHANNEL_COUNT)];
1502
0
                *P::from_slice_mut(channels) = p;
1503
0
            }
1504
        }
1505
1506
0
        Ok(())
1507
0
    }
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [f32], image::color::Rgb<f32>>>::inner_copy_from::<image::images::buffer::ImageBuffer<image::color::Rgb<f32>, alloc::vec::Vec<f32>>>
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [f32], image::color::Luma<f32>>>::inner_copy_from::<image::images::buffer::ImageBuffer<image::color::Luma<f32>, alloc::vec::Vec<f32>>>
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [f32], image::color::Rgba<f32>>>::inner_copy_from::<image::images::buffer::ImageBuffer<image::color::Rgba<f32>, alloc::vec::Vec<f32>>>
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [f32], image::color::LumaA<f32>>>::inner_copy_from::<image::images::buffer::ImageBuffer<image::color::LumaA<f32>, alloc::vec::Vec<f32>>>
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u8], image::color::Rgb<u8>>>::inner_copy_from::<image::images::buffer::ImageBuffer<image::color::Rgb<u8>, alloc::vec::Vec<u8>>>
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u8], image::color::Luma<u8>>>::inner_copy_from::<image::images::buffer::ImageBuffer<image::color::Luma<u8>, alloc::vec::Vec<u8>>>
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u8], image::color::Rgba<u8>>>::inner_copy_from::<image::images::buffer::ImageBuffer<image::color::Rgba<u8>, alloc::vec::Vec<u8>>>
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u8], image::color::LumaA<u8>>>::inner_copy_from::<image::images::buffer::ImageBuffer<image::color::LumaA<u8>, alloc::vec::Vec<u8>>>
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u16], image::color::Rgb<u16>>>::inner_copy_from::<image::images::buffer::ImageBuffer<image::color::Rgb<u16>, alloc::vec::Vec<u16>>>
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u16], image::color::Luma<u16>>>::inner_copy_from::<image::images::buffer::ImageBuffer<image::color::Luma<u16>, alloc::vec::Vec<u16>>>
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u16], image::color::Rgba<u16>>>::inner_copy_from::<image::images::buffer::ImageBuffer<image::color::Rgba<u16>, alloc::vec::Vec<u16>>>
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u16], image::color::LumaA<u16>>>::inner_copy_from::<image::images::buffer::ImageBuffer<image::color::LumaA<u16>, alloc::vec::Vec<u16>>>
1508
1509
0
    pub(crate) fn inner_copy_from_samples(
1510
0
        &mut self,
1511
0
        other: ViewOfPixel<'_, P>,
1512
0
        x: u32,
1513
0
        y: u32,
1514
0
    ) -> crate::ImageResult<()>
1515
0
    where
1516
0
        // Note: not necessary for the implementation per-se but this allows the use of
1517
0
        // `GenericImage`/`GenericImageView` methods and so `test_in_bounds_of`.
1518
0
        Buffer: AsRef<[P::Subpixel]>,
1519
    {
1520
0
        let target = Rect::from_image_at(&other, x, y);
1521
0
        target.test_in_bounds_of(self)?;
1522
1523
0
        let in_layout = other.inner.layout;
1524
0
        let in_samples = other.image_slice();
1525
1526
0
        let out_layout = self.inner.layout;
1527
0
        let out_samples = self.image_mut_slice();
1528
1529
        // Check if we can make use of batch copies, row-by-row.
1530
0
        if in_layout.width_stride == usize::from(P::CHANNEL_COUNT)
1531
0
            && out_layout.width_stride == usize::from(P::CHANNEL_COUNT)
1532
        {
1533
            // See `inner_copy_from` where we have the same trick (chunks_exact_mut with 0 stride is
1534
            // not allowed).
1535
0
            let rows = out_samples.chunks_exact_mut({
1536
0
                if out_layout.height <= 1 {
1537
0
                    out_samples.len()
1538
                } else {
1539
0
                    out_layout.height_stride
1540
                }
1541
            });
1542
1543
0
            let row_samples = target.width as usize * usize::from(P::CHANNEL_COUNT);
1544
0
            for (k, orow) in rows
1545
0
                .skip(target.y as usize)
1546
0
                .take(target.height as usize)
1547
0
                .enumerate()
1548
0
            {
1549
0
                let orow = &mut orow[target.x as usize * usize::from(P::CHANNEL_COUNT)..];
1550
0
                let irow = &in_samples[k * in_layout.height_stride..];
1551
0
                orow[..row_samples].copy_from_slice(&irow[..row_samples]);
1552
0
            }
1553
1554
0
            return Ok(());
1555
0
        }
1556
1557
0
        for k in 0..target.height {
1558
0
            for i in 0..target.width {
1559
0
                let iidx = in_layout.in_bounds_index(0, i, k);
1560
0
                let oidx = out_layout.in_bounds_index(0, i + x, k + y);
1561
0
                out_samples[oidx..][..usize::from(P::CHANNEL_COUNT)]
1562
0
                    .copy_from_slice(&in_samples[iidx..][..usize::from(P::CHANNEL_COUNT)]);
1563
0
            }
1564
        }
1565
1566
0
        Ok(())
1567
0
    }
1568
}
1569
1570
// The out-of-bounds panic for single sample access similar to `slice::index`.
1571
#[inline(never)]
1572
#[cold]
1573
0
fn panic_cwh_out_of_bounds(
1574
0
    (c, x, y): (u8, u32, u32),
1575
0
    bounds: (u8, u32, u32),
1576
0
    strides: (usize, usize, usize),
1577
0
) -> ! {
1578
0
    panic!(
1579
0
        "Sample coordinates {:?} out of sample matrix bounds {:?} with strides {:?}",
1580
0
        (c, x, y),
1581
        bounds,
1582
        strides
1583
    )
1584
}
1585
1586
// The out-of-bounds panic for pixel access similar to `slice::index`.
1587
#[inline(never)]
1588
#[cold]
1589
0
fn panic_pixel_out_of_bounds((x, y): (u32, u32), bounds: (u32, u32)) -> ! {
1590
0
    panic!("Image index {:?} out of bounds {:?}", (x, y), bounds)
1591
}
1592
1593
impl<Buffer> Index<(u8, u32, u32)> for FlatSamples<Buffer>
1594
where
1595
    Buffer: Index<usize>,
1596
{
1597
    type Output = Buffer::Output;
1598
1599
    /// Return a reference to a single sample at specified coordinates.
1600
    ///
1601
    /// # Panics
1602
    ///
1603
    /// When the coordinates are out of bounds or the index calculation fails.
1604
0
    fn index(&self, (c, x, y): (u8, u32, u32)) -> &Self::Output {
1605
0
        let bounds = self.bounds();
1606
0
        let strides = self.strides_cwh();
1607
0
        let index = self
1608
0
            .index(c, x, y)
1609
0
            .unwrap_or_else(|| panic_cwh_out_of_bounds((c, x, y), bounds, strides));
1610
0
        &self.samples[index]
1611
0
    }
1612
}
1613
1614
impl<Buffer> IndexMut<(u8, u32, u32)> for FlatSamples<Buffer>
1615
where
1616
    Buffer: IndexMut<usize>,
1617
{
1618
    /// Return a mutable reference to a single sample at specified coordinates.
1619
    ///
1620
    /// # Panics
1621
    ///
1622
    /// When the coordinates are out of bounds or the index calculation fails.
1623
0
    fn index_mut(&mut self, (c, x, y): (u8, u32, u32)) -> &mut Self::Output {
1624
0
        let bounds = self.bounds();
1625
0
        let strides = self.strides_cwh();
1626
0
        let index = self
1627
0
            .index(c, x, y)
1628
0
            .unwrap_or_else(|| panic_cwh_out_of_bounds((c, x, y), bounds, strides));
1629
0
        &mut self.samples[index]
1630
0
    }
1631
}
1632
1633
impl<Buffer, P: Pixel> GenericImageView for View<Buffer, P>
1634
where
1635
    Buffer: AsRef<[P::Subpixel]>,
1636
{
1637
    type Pixel = P;
1638
1639
0
    fn dimensions(&self) -> (u32, u32) {
1640
0
        (self.inner.layout.width, self.inner.layout.height)
1641
0
    }
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Rgb<f32>> as image::images::generic_image::GenericImageView>::dimensions
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Luma<f32>> as image::images::generic_image::GenericImageView>::dimensions
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Rgba<f32>> as image::images::generic_image::GenericImageView>::dimensions
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::LumaA<f32>> as image::images::generic_image::GenericImageView>::dimensions
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Rgb<u8>> as image::images::generic_image::GenericImageView>::dimensions
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Luma<u8>> as image::images::generic_image::GenericImageView>::dimensions
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Rgba<u8>> as image::images::generic_image::GenericImageView>::dimensions
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::LumaA<u8>> as image::images::generic_image::GenericImageView>::dimensions
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Rgb<u16>> as image::images::generic_image::GenericImageView>::dimensions
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Luma<u16>> as image::images::generic_image::GenericImageView>::dimensions
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Rgba<u16>> as image::images::generic_image::GenericImageView>::dimensions
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::LumaA<u16>> as image::images::generic_image::GenericImageView>::dimensions
1642
1643
0
    fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
1644
0
        if !self.inner.in_bounds(0, x, y) {
1645
0
            panic_pixel_out_of_bounds((x, y), self.dimensions())
1646
0
        }
1647
1648
0
        let image = self.inner.samples.as_ref();
1649
0
        let base_index = self.inner.in_bounds_index(0, x, y);
1650
0
        let channels = P::CHANNEL_COUNT as usize;
1651
1652
0
        let mut buffer = [Zero::zero(); 256];
1653
0
        buffer
1654
0
            .iter_mut()
1655
0
            .enumerate()
1656
0
            .take(channels)
1657
0
            .for_each(|(c, to)| {
1658
0
                let index = base_index + c * self.inner.layout.channel_stride;
1659
0
                *to = image[index];
1660
0
            });
1661
1662
0
        *P::from_slice(&buffer[..channels])
1663
0
    }
1664
1665
0
    fn to_pixel_view(&self) -> Option<ViewOfPixel<'_, Self::Pixel>> {
1666
0
        Some(View {
1667
0
            inner: FlatSamples {
1668
0
                samples: self.inner.samples.as_ref(),
1669
0
                layout: self.inner.layout,
1670
0
                color_hint: None,
1671
0
            },
1672
0
            phantom: PhantomData,
1673
0
        })
1674
0
    }
1675
}
1676
1677
impl<Buffer, P: Pixel> GenericImageView for ViewMut<Buffer, P>
1678
where
1679
    Buffer: AsMut<[P::Subpixel]> + AsRef<[P::Subpixel]>,
1680
{
1681
    type Pixel = P;
1682
1683
0
    fn dimensions(&self) -> (u32, u32) {
1684
0
        (self.inner.layout.width, self.inner.layout.height)
1685
0
    }
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [f32], image::color::Rgb<f32>> as image::images::generic_image::GenericImageView>::dimensions
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [f32], image::color::Luma<f32>> as image::images::generic_image::GenericImageView>::dimensions
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [f32], image::color::Rgba<f32>> as image::images::generic_image::GenericImageView>::dimensions
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [f32], image::color::LumaA<f32>> as image::images::generic_image::GenericImageView>::dimensions
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u8], image::color::Rgb<u8>> as image::images::generic_image::GenericImageView>::dimensions
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u8], image::color::Luma<u8>> as image::images::generic_image::GenericImageView>::dimensions
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u8], image::color::Rgba<u8>> as image::images::generic_image::GenericImageView>::dimensions
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u8], image::color::LumaA<u8>> as image::images::generic_image::GenericImageView>::dimensions
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u16], image::color::Rgb<u16>> as image::images::generic_image::GenericImageView>::dimensions
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u16], image::color::Luma<u16>> as image::images::generic_image::GenericImageView>::dimensions
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u16], image::color::Rgba<u16>> as image::images::generic_image::GenericImageView>::dimensions
Unexecuted instantiation: <image::images::flat::ViewMut<&mut [u16], image::color::LumaA<u16>> as image::images::generic_image::GenericImageView>::dimensions
1686
1687
0
    fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
1688
0
        if !self.inner.in_bounds(0, x, y) {
1689
0
            panic_pixel_out_of_bounds((x, y), self.dimensions())
1690
0
        }
1691
1692
0
        let image = self.inner.samples.as_ref();
1693
0
        let base_index = self.inner.in_bounds_index(0, x, y);
1694
0
        let channels = P::CHANNEL_COUNT as usize;
1695
1696
0
        let mut buffer = [Zero::zero(); 256];
1697
0
        buffer
1698
0
            .iter_mut()
1699
0
            .enumerate()
1700
0
            .take(channels)
1701
0
            .for_each(|(c, to)| {
1702
0
                let index = base_index + c * self.inner.layout.channel_stride;
1703
0
                *to = image[index];
1704
0
            });
1705
1706
0
        *P::from_slice(&buffer[..channels])
1707
0
    }
1708
1709
0
    fn to_pixel_view(&self) -> Option<ViewOfPixel<'_, Self::Pixel>> {
1710
0
        Some(View {
1711
0
            inner: FlatSamples {
1712
0
                samples: self.inner.samples.as_ref(),
1713
0
                layout: self.inner.layout,
1714
0
                color_hint: None,
1715
0
            },
1716
0
            phantom: PhantomData,
1717
0
        })
1718
0
    }
1719
}
1720
1721
impl<Buffer, P: Pixel> GenericImage for ViewMut<Buffer, P>
1722
where
1723
    Buffer: AsMut<[P::Subpixel]> + AsRef<[P::Subpixel]>,
1724
{
1725
0
    fn put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
1726
0
        if !self.inner.in_bounds(0, x, y) {
1727
0
            panic_pixel_out_of_bounds((x, y), self.dimensions())
1728
0
        }
1729
1730
0
        let base_index = self.inner.in_bounds_index(0, x, y);
1731
0
        let channel_count = <P as Pixel>::CHANNEL_COUNT as usize;
1732
0
        let pixel_range = base_index..base_index + channel_count;
1733
0
        *P::from_slice_mut(&mut self.inner.samples.as_mut()[pixel_range]) = pixel;
1734
0
    }
1735
1736
0
    fn copy_from<O>(&mut self, other: &O, x: u32, y: u32) -> crate::ImageResult<()>
1737
0
    where
1738
0
        O: GenericImageView<Pixel = Self::Pixel>,
1739
    {
1740
0
        if let Some(flat) = other.to_pixel_view() {
1741
0
            return self.inner_copy_from_samples(flat, x, y);
1742
0
        }
1743
1744
0
        self.inner_copy_from(other, x, y)
1745
0
    }
1746
}
1747
1748
impl From<Error> for ImageError {
1749
0
    fn from(error: Error) -> ImageError {
1750
        #[derive(Debug)]
1751
        struct NormalFormRequiredError(NormalForm);
1752
        impl fmt::Display for NormalFormRequiredError {
1753
0
            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1754
0
                write!(f, "Required sample buffer in normal form {:?}", self.0)
1755
0
            }
1756
        }
1757
        impl error::Error for NormalFormRequiredError {}
1758
1759
0
        match error {
1760
0
            Error::TooLarge => ImageError::Parameter(ParameterError::from_kind(
1761
0
                ParameterErrorKind::DimensionMismatch,
1762
0
            )),
1763
0
            Error::NormalFormRequired(form) => ImageError::Decoding(DecodingError::new(
1764
0
                ImageFormatHint::Unknown,
1765
0
                NormalFormRequiredError(form),
1766
0
            )),
1767
0
            Error::ChannelCountMismatch(_lc, _pc) => ImageError::Parameter(
1768
0
                ParameterError::from_kind(ParameterErrorKind::DimensionMismatch),
1769
0
            ),
1770
0
            Error::WrongColor(color) => {
1771
0
                ImageError::Unsupported(UnsupportedError::from_format_and_kind(
1772
0
                    ImageFormatHint::Unknown,
1773
0
                    UnsupportedErrorKind::Color(color.into()),
1774
0
                ))
1775
            }
1776
        }
1777
0
    }
1778
}
1779
1780
impl fmt::Display for Error {
1781
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1782
0
        match self {
1783
0
            Error::TooLarge => write!(f, "The layout is too large"),
1784
0
            Error::NormalFormRequired(form) => write!(
1785
0
                f,
1786
0
                "The layout needs to {}",
1787
0
                match form {
1788
0
                    NormalForm::ColumnMajorPacked => "be packed and in column major form",
1789
0
                    NormalForm::ImagePacked => "be fully packed",
1790
0
                    NormalForm::PixelPacked => "have packed pixels",
1791
0
                    NormalForm::RowMajorPacked => "be packed and in row major form",
1792
0
                    NormalForm::Unaliased => "not have any aliasing channels",
1793
                }
1794
            ),
1795
0
            Error::ChannelCountMismatch(layout_channels, pixel_channels) => {
1796
0
                write!(f, "The channel count of the chosen pixel (={pixel_channels}) does not agree with the layout (={layout_channels})")
1797
            }
1798
0
            Error::WrongColor(color) => {
1799
0
                write!(f, "The chosen color type does not match the hint {color:?}")
1800
            }
1801
        }
1802
0
    }
1803
}
1804
1805
impl error::Error for Error {}
1806
1807
impl PartialOrd for NormalForm {
1808
    /// Compares the logical preconditions.
1809
    ///
1810
    /// `a < b` if the normal form `a` has less preconditions than `b`.
1811
0
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
1812
0
        match (*self, *other) {
1813
0
            (NormalForm::Unaliased, NormalForm::Unaliased) => Some(cmp::Ordering::Equal),
1814
0
            (NormalForm::PixelPacked, NormalForm::PixelPacked) => Some(cmp::Ordering::Equal),
1815
0
            (NormalForm::ImagePacked, NormalForm::ImagePacked) => Some(cmp::Ordering::Equal),
1816
0
            (NormalForm::RowMajorPacked, NormalForm::RowMajorPacked) => Some(cmp::Ordering::Equal),
1817
            (NormalForm::ColumnMajorPacked, NormalForm::ColumnMajorPacked) => {
1818
0
                Some(cmp::Ordering::Equal)
1819
            }
1820
1821
0
            (NormalForm::Unaliased, _) => Some(cmp::Ordering::Less),
1822
0
            (_, NormalForm::Unaliased) => Some(cmp::Ordering::Greater),
1823
1824
0
            (NormalForm::PixelPacked, NormalForm::ColumnMajorPacked) => Some(cmp::Ordering::Less),
1825
0
            (NormalForm::PixelPacked, NormalForm::RowMajorPacked) => Some(cmp::Ordering::Less),
1826
0
            (NormalForm::RowMajorPacked, NormalForm::PixelPacked) => Some(cmp::Ordering::Greater),
1827
            (NormalForm::ColumnMajorPacked, NormalForm::PixelPacked) => {
1828
0
                Some(cmp::Ordering::Greater)
1829
            }
1830
1831
0
            (NormalForm::ImagePacked, NormalForm::ColumnMajorPacked) => Some(cmp::Ordering::Less),
1832
0
            (NormalForm::ImagePacked, NormalForm::RowMajorPacked) => Some(cmp::Ordering::Less),
1833
0
            (NormalForm::RowMajorPacked, NormalForm::ImagePacked) => Some(cmp::Ordering::Greater),
1834
            (NormalForm::ColumnMajorPacked, NormalForm::ImagePacked) => {
1835
0
                Some(cmp::Ordering::Greater)
1836
            }
1837
1838
0
            (NormalForm::ImagePacked, NormalForm::PixelPacked) => None,
1839
0
            (NormalForm::PixelPacked, NormalForm::ImagePacked) => None,
1840
0
            (NormalForm::RowMajorPacked, NormalForm::ColumnMajorPacked) => None,
1841
0
            (NormalForm::ColumnMajorPacked, NormalForm::RowMajorPacked) => None,
1842
        }
1843
0
    }
1844
}
1845
1846
#[cfg(test)]
1847
mod tests {
1848
    use super::*;
1849
    use crate::color::{LumaA, Rgb};
1850
    use crate::images::buffer::GrayAlphaImage;
1851
1852
    #[test]
1853
    fn aliasing_view() {
1854
        let buffer = FlatSamples {
1855
            samples: &[42],
1856
            layout: SampleLayout {
1857
                channels: 3,
1858
                channel_stride: 0,
1859
                width: 100,
1860
                width_stride: 0,
1861
                height: 100,
1862
                height_stride: 0,
1863
            },
1864
            color_hint: None,
1865
        };
1866
1867
        let view = buffer.as_view::<Rgb<u8>>().expect("This is a valid view");
1868
        let pixel_count = view
1869
            .pixels()
1870
            .inspect(|pixel| assert!(pixel.2 == Rgb([42, 42, 42])))
1871
            .count();
1872
        assert_eq!(pixel_count, 100 * 100);
1873
    }
1874
1875
    #[test]
1876
    fn mutable_view() {
1877
        let mut buffer = FlatSamples {
1878
            samples: [0; 18],
1879
            layout: SampleLayout {
1880
                channels: 2,
1881
                channel_stride: 1,
1882
                width: 3,
1883
                width_stride: 2,
1884
                height: 3,
1885
                height_stride: 6,
1886
            },
1887
            color_hint: None,
1888
        };
1889
1890
        {
1891
            let mut view = buffer
1892
                .as_view_mut::<LumaA<u16>>()
1893
                .expect("This should be a valid mutable buffer");
1894
            assert_eq!(view.dimensions(), (3, 3));
1895
            for i in 0..9 {
1896
                view.put_pixel(i % 3, i / 3, LumaA([2 * i as u16, 2 * i as u16 + 1]));
1897
            }
1898
        }
1899
1900
        buffer
1901
            .samples
1902
            .iter()
1903
            .enumerate()
1904
            .for_each(|(idx, sample)| assert_eq!(idx, *sample as usize));
1905
    }
1906
1907
    #[test]
1908
    fn normal_forms() {
1909
        assert!(FlatSamples {
1910
            samples: [0u8; 0],
1911
            layout: SampleLayout {
1912
                channels: 2,
1913
                channel_stride: 1,
1914
                width: 3,
1915
                width_stride: 9,
1916
                height: 3,
1917
                height_stride: 28,
1918
            },
1919
            color_hint: None,
1920
        }
1921
        .is_normal(NormalForm::PixelPacked));
1922
1923
        assert!(FlatSamples {
1924
            samples: [0u8; 0],
1925
            layout: SampleLayout {
1926
                channels: 2,
1927
                channel_stride: 8,
1928
                width: 4,
1929
                width_stride: 1,
1930
                height: 2,
1931
                height_stride: 4,
1932
            },
1933
            color_hint: None,
1934
        }
1935
        .is_normal(NormalForm::ImagePacked));
1936
1937
        assert!(FlatSamples {
1938
            samples: [0u8; 0],
1939
            layout: SampleLayout {
1940
                channels: 2,
1941
                channel_stride: 1,
1942
                width: 4,
1943
                width_stride: 2,
1944
                height: 2,
1945
                height_stride: 8,
1946
            },
1947
            color_hint: None,
1948
        }
1949
        .is_normal(NormalForm::RowMajorPacked));
1950
1951
        assert!(FlatSamples {
1952
            samples: [0u8; 0],
1953
            layout: SampleLayout {
1954
                channels: 2,
1955
                channel_stride: 1,
1956
                width: 4,
1957
                width_stride: 4,
1958
                height: 2,
1959
                height_stride: 2,
1960
            },
1961
            color_hint: None,
1962
        }
1963
        .is_normal(NormalForm::ColumnMajorPacked));
1964
    }
1965
1966
    #[test]
1967
    fn image_buffer_conversion() {
1968
        let expected_layout = SampleLayout {
1969
            channels: 2,
1970
            channel_stride: 1,
1971
            width: 4,
1972
            width_stride: 2,
1973
            height: 2,
1974
            height_stride: 8,
1975
        };
1976
1977
        let initial = GrayAlphaImage::new(expected_layout.width, expected_layout.height);
1978
        let buffer = initial.into_flat_samples();
1979
1980
        assert_eq!(buffer.layout, expected_layout);
1981
1982
        let _: GrayAlphaImage = buffer
1983
            .try_into_buffer()
1984
            .unwrap_or_else(|(error, _)| panic!("Expected buffer to be convertible but {error:?}"));
1985
    }
1986
1987
    #[test]
1988
    fn copy_buffer_like_view() {
1989
        let src = View::with_monocolor(&LumaA([0xffu8, 0xfe]), 2, 3);
1990
1991
        let mut buffer = FlatSamples {
1992
            samples: [0; 12],
1993
            layout: SampleLayout {
1994
                channels: 2,
1995
                channel_stride: 1,
1996
                width: 2,
1997
                width_stride: 2,
1998
                height: 3,
1999
                height_stride: 4,
2000
            },
2001
            color_hint: None,
2002
        };
2003
2004
        let mut view = buffer
2005
            .as_view_mut::<LumaA<u8>>()
2006
            .expect("This should be a valid mutable buffer");
2007
2008
        view.copy_from(&src, 0, 0)
2009
            .expect("image fits into the target");
2010
2011
        assert_eq!(buffer.samples.as_chunks::<2>().0, [[0xff, 0xfe]; 6],);
2012
    }
2013
2014
    #[test]
2015
    fn copy_heightstride_view() {
2016
        let src = View::with_monocolor(&LumaA([0xffu8, 0xfe]), 2, 3);
2017
2018
        // Each row has capacity for 5 channels, of which 4 are used.
2019
        let mut buffer = FlatSamples {
2020
            samples: [0; 15],
2021
            layout: SampleLayout {
2022
                channels: 2,
2023
                channel_stride: 1,
2024
                width: 2,
2025
                width_stride: 2,
2026
                height: 3,
2027
                height_stride: 5,
2028
            },
2029
            color_hint: None,
2030
        };
2031
2032
        let mut view = buffer
2033
            .as_view_mut::<LumaA<u8>>()
2034
            .expect("This should be a valid mutable buffer");
2035
2036
        view.copy_from(&src, 0, 0)
2037
            .expect("image fits into the target");
2038
2039
        assert_eq!(
2040
            buffer.samples.as_chunks::<5>().0,
2041
            [[0xff, 0xfe, 0xff, 0xfe, 0]; 3],
2042
        );
2043
    }
2044
2045
    #[test]
2046
    fn copy_widthstride_view() {
2047
        let src = View::with_monocolor(&LumaA([0xffu8, 0xfe]), 2, 3);
2048
2049
        // Each row has capacity for 5 channels, of which 4 are used.
2050
        let mut buffer = FlatSamples {
2051
            samples: [0; 18],
2052
            layout: SampleLayout {
2053
                channels: 2,
2054
                channel_stride: 1,
2055
                width: 2,
2056
                width_stride: 3,
2057
                height: 3,
2058
                height_stride: 6,
2059
            },
2060
            color_hint: None,
2061
        };
2062
2063
        let mut view = buffer
2064
            .as_view_mut::<LumaA<u8>>()
2065
            .expect("This should be a valid mutable buffer");
2066
2067
        view.copy_from(&src, 0, 0)
2068
            .expect("image fits into the target");
2069
2070
        assert_eq!(
2071
            buffer.samples.as_chunks::<6>().0,
2072
            [[0xff, 0xfe, 0, 0xff, 0xfe, 0]; 3],
2073
        );
2074
    }
2075
2076
    #[test]
2077
    fn copy_column_major_view() {
2078
        let src = View::with_monocolor(&LumaA([0xffu8, 0xfe]), 1, 3);
2079
2080
        // Each row has capacity for 5 channels, of which 4 are used.
2081
        let mut buffer = FlatSamples {
2082
            samples: [0; 14],
2083
            layout: SampleLayout {
2084
                channels: 2,
2085
                channel_stride: 1,
2086
                width: 2,
2087
                width_stride: 8,
2088
                height: 3,
2089
                height_stride: 2,
2090
            },
2091
            color_hint: None,
2092
        };
2093
2094
        let mut view = buffer
2095
            .as_view_mut::<LumaA<u8>>()
2096
            .expect("This should be a valid mutable buffer");
2097
2098
        view.copy_from(&src, 0, 0)
2099
            .expect("image fits into the target");
2100
2101
        // First column, i.e. first 3 pixels, affected.
2102
        assert_eq!(
2103
            view.image_slice()[0..6].as_chunks::<2>().0,
2104
            [[0xff, 0xfe]; 3],
2105
        );
2106
        // Everything else unchanged.
2107
        assert_eq!(view.image_slice()[6..], [0; 8]);
2108
2109
        view.copy_from(&src, 1, 0)
2110
            .expect("image fits into the target");
2111
2112
        assert_eq!(view.image_slice()[6..8], [0, 0]);
2113
        assert_eq!(
2114
            view.image_slice()[8..].as_chunks::<2>().0,
2115
            [[0xff, 0xfe]; 3],
2116
        );
2117
    }
2118
}