image/
flat.rs

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//!
44use std::marker::PhantomData;
45use std::ops::{Deref, Index, IndexMut};
46use std::{cmp, error, fmt};
47
48use num_traits::Zero;
49
50use crate::color::ColorType;
51use crate::error::{
52    DecodingError, ImageError, ImageFormatHint, ParameterError, ParameterErrorKind,
53    UnsupportedError, UnsupportedErrorKind,
54};
55use crate::image::{GenericImage, GenericImageView};
56use crate::traits::Pixel;
57use crate::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/// [`GenericImage`]: ../trait.GenericImage.html
76/// [`GenericImageView`]: ../trait.GenericImageView.html
77/// [`ImageBuffer::as_flat_samples`]: ../struct.ImageBuffer.html#method.as_flat_samples
78/// [`is_normal`]: #method.is_normal
79/// [`has_aliased_samples`]: #method.has_aliased_samples
80/// [`as_view`]: #method.as_view
81/// [`as_view_mut`]: #method.as_view_mut
82/// [`with_monocolor`]: #method.with_monocolor
83#[derive(Clone, Debug)]
84pub struct FlatSamples<Buffer> {
85    /// Underlying linear container holding sample values.
86    pub samples: Buffer,
87
88    /// A `repr(C)` description of the layout of buffer samples.
89    pub layout: SampleLayout,
90
91    /// Supplementary color information.
92    ///
93    /// You may keep this as `None` in most cases. This is NOT checked in `View` or other
94    /// converters. It is intended mainly as a way for types that convert to this buffer type to
95    /// attach their otherwise static color information. A dynamic image representation could
96    /// however use this to resolve representational ambiguities such as the order of RGB channels.
97    pub color_hint: Option<ColorType>,
98}
99
100/// A ffi compatible description of a sample buffer.
101#[repr(C)]
102#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
103pub struct SampleLayout {
104    /// The number of channels in the color representation of the image.
105    pub channels: u8,
106
107    /// Add this to an index to get to the sample in the next channel.
108    pub channel_stride: usize,
109
110    /// The width of the represented image.
111    pub width: u32,
112
113    /// Add this to an index to get to the next sample in x-direction.
114    pub width_stride: usize,
115
116    /// The height of the represented image.
117    pub height: u32,
118
119    /// Add this to an index to get to the next sample in y-direction.
120    pub height_stride: usize,
121}
122
123/// Helper struct for an unnamed (stride, length) pair.
124#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
125struct Dim(usize, usize);
126
127impl SampleLayout {
128    /// Describe a row-major image packed in all directions.
129    ///
130    /// The resulting will surely be `NormalForm::RowMajorPacked`. It can therefore be converted to
131    /// safely to an `ImageBuffer` with a large enough underlying buffer.
132    ///
133    /// ```
134    /// # use image::flat::{NormalForm, SampleLayout};
135    /// let layout = SampleLayout::row_major_packed(3, 640, 480);
136    /// assert!(layout.is_normal(NormalForm::RowMajorPacked));
137    /// ```
138    ///
139    /// # Panics
140    ///
141    /// On platforms where `usize` has the same size as `u32` this panics when the resulting stride
142    /// in the `height` direction would be larger than `usize::MAX`. On other platforms
143    /// where it can surely accommodate `u8::MAX * u32::MAX`, this can never happen.
144    #[must_use]
145    pub fn row_major_packed(channels: u8, width: u32, height: u32) -> Self {
146        let height_stride = (channels as usize).checked_mul(width as usize).expect(
147            "Row major packed image can not be described because it does not fit into memory",
148        );
149        SampleLayout {
150            channels,
151            channel_stride: 1,
152            width,
153            width_stride: channels as usize,
154            height,
155            height_stride,
156        }
157    }
158
159    /// Describe a column-major image packed in all directions.
160    ///
161    /// The resulting will surely be `NormalForm::ColumnMajorPacked`. This is not particularly
162    /// useful for conversion but can be used to describe such a buffer without pitfalls.
163    ///
164    /// ```
165    /// # use image::flat::{NormalForm, SampleLayout};
166    /// let layout = SampleLayout::column_major_packed(3, 640, 480);
167    /// assert!(layout.is_normal(NormalForm::ColumnMajorPacked));
168    /// ```
169    ///
170    /// # Panics
171    ///
172    /// On platforms where `usize` has the same size as `u32` this panics when the resulting stride
173    /// in the `width` direction would be larger than `usize::MAX`. On other platforms
174    /// where it can surely accommodate `u8::MAX * u32::MAX`, this can never happen.
175    #[must_use]
176    pub fn column_major_packed(channels: u8, width: u32, height: u32) -> Self {
177        let width_stride = (channels as usize).checked_mul(height as usize).expect(
178            "Column major packed image can not be described because it does not fit into memory",
179        );
180        SampleLayout {
181            channels,
182            channel_stride: 1,
183            height,
184            height_stride: channels as usize,
185            width,
186            width_stride,
187        }
188    }
189
190    /// Get the strides for indexing matrix-like `[(c, w, h)]`.
191    ///
192    /// For a row-major layout with grouped samples, this tuple is strictly
193    /// increasing.
194    #[must_use]
195    pub fn strides_cwh(&self) -> (usize, usize, usize) {
196        (self.channel_stride, self.width_stride, self.height_stride)
197    }
198
199    /// Get the dimensions `(channels, width, height)`.
200    ///
201    /// The interface is optimized for use with `strides_cwh` instead. The channel extent will be
202    /// before width and height.
203    #[must_use]
204    pub fn extents(&self) -> (usize, usize, usize) {
205        (
206            self.channels as usize,
207            self.width as usize,
208            self.height as usize,
209        )
210    }
211
212    /// Tuple of bounds in the order of coordinate inputs.
213    ///
214    /// This function should be used whenever working with image coordinates opposed to buffer
215    /// coordinates. The only difference compared to `extents` is the output type.
216    #[must_use]
217    pub fn bounds(&self) -> (u8, u32, u32) {
218        (self.channels, self.width, self.height)
219    }
220
221    /// Get the minimum length of a buffer such that all in-bounds samples have valid indices.
222    ///
223    /// This method will allow zero strides, allowing compact representations of monochrome images.
224    /// To check that no aliasing occurs, try `check_alias_invariants`. For compact images (no
225    /// aliasing and no unindexed samples) this is `width*height*channels`. But for both of the
226    /// other cases, the reasoning is slightly more involved.
227    ///
228    /// # Explanation
229    ///
230    /// Note that there is a difference between `min_length` and the index of the sample
231    /// 'one-past-the-end'. This is due to strides that may be larger than the dimension below.
232    ///
233    /// ## Example with holes
234    ///
235    /// Let's look at an example of a grayscale image with
236    /// * `width_stride = 1`
237    /// * `width = 2`
238    /// * `height_stride = 3`
239    /// * `height = 2`
240    ///
241    /// ```text
242    /// | x x   | x x m | $
243    ///  min_length m ^
244    ///                   ^ one-past-the-end $
245    /// ```
246    ///
247    /// The difference is also extreme for empty images with large strides. The one-past-the-end
248    /// sample index is still as large as the largest of these strides while `min_length = 0`.
249    ///
250    /// ## Example with aliasing
251    ///
252    /// The concept gets even more important when you allow samples to alias each other. Here we
253    /// have the buffer of a small grayscale image where this is the case, this time we will first
254    /// show the buffer and then the individual rows below.
255    ///
256    /// * `width_stride = 1`
257    /// * `width = 3`
258    /// * `height_stride = 2`
259    /// * `height = 2`
260    ///
261    /// ```text
262    ///  1 2 3 4 5 m
263    /// |1 2 3| row one
264    ///     |3 4 5| row two
265    ///            ^ m min_length
266    ///          ^ ??? one-past-the-end
267    /// ```
268    ///
269    /// This time 'one-past-the-end' is not even simply the largest stride times the extent of its
270    /// dimension. That still points inside the image because `height*height_stride = 4` but also
271    /// `index_of(1, 2) = 4`.
272    #[must_use]
273    pub fn min_length(&self) -> Option<usize> {
274        if self.width == 0 || self.height == 0 || self.channels == 0 {
275            return Some(0);
276        }
277
278        self.index(self.channels - 1, self.width - 1, self.height - 1)
279            .and_then(|idx| idx.checked_add(1))
280    }
281
282    /// Check if a buffer of length `len` is large enough.
283    #[must_use]
284    pub fn fits(&self, len: usize) -> bool {
285        self.min_length().is_some_and(|min| len >= min)
286    }
287
288    /// The extents of this array, in order of increasing strides.
289    fn increasing_stride_dims(&self) -> [Dim; 3] {
290        // Order extents by strides, then check that each is less equal than the next stride.
291        let mut grouped: [Dim; 3] = [
292            Dim(self.channel_stride, self.channels as usize),
293            Dim(self.width_stride, self.width as usize),
294            Dim(self.height_stride, self.height as usize),
295        ];
296
297        grouped.sort();
298
299        let (min_dim, mid_dim, max_dim) = (grouped[0], grouped[1], grouped[2]);
300        assert!(min_dim.stride() <= mid_dim.stride() && mid_dim.stride() <= max_dim.stride());
301
302        grouped
303    }
304
305    /// If there are any samples aliasing each other.
306    ///
307    /// If this is not the case, it would always be safe to allow mutable access to two different
308    /// samples at the same time. Otherwise, this operation would need additional checks. When one
309    /// dimension overflows `usize` with its stride we also consider this aliasing.
310    #[must_use]
311    pub fn has_aliased_samples(&self) -> bool {
312        let grouped = self.increasing_stride_dims();
313        let (min_dim, mid_dim, max_dim) = (grouped[0], grouped[1], grouped[2]);
314
315        let min_size = match min_dim.checked_len() {
316            None => return true,
317            Some(size) => size,
318        };
319
320        let mid_size = match mid_dim.checked_len() {
321            None => return true,
322            Some(size) => size,
323        };
324
325        if max_dim.checked_len().is_none() {
326            return true;
327        };
328
329        // Each higher dimension must walk over all of one lower dimension.
330        min_size > mid_dim.stride() || mid_size > max_dim.stride()
331    }
332
333    /// Check if a buffer fulfills the requirements of a normal form.
334    ///
335    /// Certain conversions have preconditions on the structure of the sample buffer that are not
336    /// captured (by design) by the type system. These are then checked before the conversion. Such
337    /// checks can all be done in constant time and will not inspect the buffer content. You can
338    /// perform these checks yourself when the conversion is not required at this moment but maybe
339    /// still performed later.
340    #[must_use]
341    pub fn is_normal(&self, form: NormalForm) -> bool {
342        if self.has_aliased_samples() {
343            return false;
344        }
345
346        if form >= NormalForm::PixelPacked && self.channel_stride != 1 {
347            return false;
348        }
349
350        if form >= NormalForm::ImagePacked {
351            // has aliased already checked for overflows.
352            let grouped = self.increasing_stride_dims();
353            let (min_dim, mid_dim, max_dim) = (grouped[0], grouped[1], grouped[2]);
354
355            if 1 != min_dim.stride() {
356                return false;
357            }
358
359            if min_dim.len() != mid_dim.stride() {
360                return false;
361            }
362
363            if mid_dim.len() != max_dim.stride() {
364                return false;
365            }
366        }
367
368        if form >= NormalForm::RowMajorPacked {
369            if self.width_stride != self.channels as usize {
370                return false;
371            }
372
373            if self.width as usize * self.width_stride != self.height_stride {
374                return false;
375            }
376        }
377
378        if form >= NormalForm::ColumnMajorPacked {
379            if self.height_stride != self.channels as usize {
380                return false;
381            }
382
383            if self.height as usize * self.height_stride != self.width_stride {
384                return false;
385            }
386        }
387
388        true
389    }
390
391    /// Check that the pixel and the channel index are in bounds.
392    ///
393    /// An in-bound coordinate does not yet guarantee that the corresponding calculation of a
394    /// buffer index does not overflow. However, if such a buffer large enough to hold all samples
395    /// actually exists in memory, this property of course follows.
396    #[must_use]
397    pub fn in_bounds(&self, channel: u8, x: u32, y: u32) -> bool {
398        channel < self.channels && x < self.width && y < self.height
399    }
400
401    /// Resolve the index of a particular sample.
402    ///
403    /// `None` if the index is outside the bounds or does not fit into a `usize`.
404    #[must_use]
405    pub fn index(&self, channel: u8, x: u32, y: u32) -> Option<usize> {
406        if !self.in_bounds(channel, x, y) {
407            return None;
408        }
409
410        self.index_ignoring_bounds(channel as usize, x as usize, y as usize)
411    }
412
413    /// Get the theoretical position of sample (channel, x, y).
414    ///
415    /// The 'check' is for overflow during index calculation, not that it is contained in the
416    /// image. Two samples may return the same index, even when one of them is out of bounds. This
417    /// happens when all strides are `0`, i.e. the image is an arbitrarily large monochrome image.
418    #[must_use]
419    pub fn index_ignoring_bounds(&self, channel: usize, x: usize, y: usize) -> Option<usize> {
420        let idx_c = channel.checked_mul(self.channel_stride);
421        let idx_x = x.checked_mul(self.width_stride);
422        let idx_y = y.checked_mul(self.height_stride);
423
424        let (Some(idx_c), Some(idx_x), Some(idx_y)) = (idx_c, idx_x, idx_y) else {
425            return None;
426        };
427
428        Some(0usize)
429            .and_then(|b| b.checked_add(idx_c))
430            .and_then(|b| b.checked_add(idx_x))
431            .and_then(|b| b.checked_add(idx_y))
432    }
433
434    /// Get an index provided it is inbouds.
435    ///
436    /// Assumes that the image is backed by some sufficiently large buffer. Then computation can
437    /// not overflow as we could represent the maximum coordinate. Since overflow is defined either
438    /// way, this method can not be unsafe.
439    ///
440    /// Behavior is *unspecified* if the index is out of bounds or this sample layout would require
441    /// a buffer larger than `isize::MAX` bytes.
442    #[must_use]
443    pub fn in_bounds_index(&self, c: u8, x: u32, y: u32) -> usize {
444        let (c_stride, x_stride, y_stride) = self.strides_cwh();
445        (y as usize * y_stride) + (x as usize * x_stride) + (c as usize * c_stride)
446    }
447
448    /// Shrink the image to the minimum of current and given extents.
449    ///
450    /// This does not modify the strides, so that the resulting sample buffer may have holes
451    /// created by the shrinking operation. Shrinking could also lead to an non-aliasing image when
452    /// samples had aliased each other before.
453    pub fn shrink_to(&mut self, channels: u8, width: u32, height: u32) {
454        self.channels = self.channels.min(channels);
455        self.width = self.width.min(width);
456        self.height = self.height.min(height);
457    }
458}
459
460impl Dim {
461    fn stride(self) -> usize {
462        self.0
463    }
464
465    /// Length of this dimension in memory.
466    fn checked_len(self) -> Option<usize> {
467        self.0.checked_mul(self.1)
468    }
469
470    fn len(self) -> usize {
471        self.0 * self.1
472    }
473}
474
475impl<Buffer> FlatSamples<Buffer> {
476    /// Get the strides for indexing matrix-like `[(c, w, h)]`.
477    ///
478    /// For a row-major layout with grouped samples, this tuple is strictly
479    /// increasing.
480    pub fn strides_cwh(&self) -> (usize, usize, usize) {
481        self.layout.strides_cwh()
482    }
483
484    /// Get the dimensions `(channels, width, height)`.
485    ///
486    /// The interface is optimized for use with `strides_cwh` instead. The channel extent will be
487    /// before width and height.
488    pub fn extents(&self) -> (usize, usize, usize) {
489        self.layout.extents()
490    }
491
492    /// Tuple of bounds in the order of coordinate inputs.
493    ///
494    /// This function should be used whenever working with image coordinates opposed to buffer
495    /// coordinates. The only difference compared to `extents` is the output type.
496    pub fn bounds(&self) -> (u8, u32, u32) {
497        self.layout.bounds()
498    }
499
500    /// Get a reference based version.
501    pub fn as_ref<T>(&self) -> FlatSamples<&[T]>
502    where
503        Buffer: AsRef<[T]>,
504    {
505        FlatSamples {
506            samples: self.samples.as_ref(),
507            layout: self.layout,
508            color_hint: self.color_hint,
509        }
510    }
511
512    /// Get a mutable reference based version.
513    pub fn as_mut<T>(&mut self) -> FlatSamples<&mut [T]>
514    where
515        Buffer: AsMut<[T]>,
516    {
517        FlatSamples {
518            samples: self.samples.as_mut(),
519            layout: self.layout,
520            color_hint: self.color_hint,
521        }
522    }
523
524    /// Copy the data into an owned vector.
525    pub fn to_vec<T>(&self) -> FlatSamples<Vec<T>>
526    where
527        T: Clone,
528        Buffer: AsRef<[T]>,
529    {
530        FlatSamples {
531            samples: self.samples.as_ref().to_vec(),
532            layout: self.layout,
533            color_hint: self.color_hint,
534        }
535    }
536
537    /// Get a reference to a single sample.
538    ///
539    /// This more restrictive than the method based on `std::ops::Index` but guarantees to properly
540    /// check all bounds and not panic as long as `Buffer::as_ref` does not do so.
541    ///
542    /// ```
543    /// # use image::{RgbImage};
544    /// let flat = RgbImage::new(480, 640).into_flat_samples();
545    ///
546    /// // Get the blue channel at (10, 10).
547    /// assert!(flat.get_sample(1, 10, 10).is_some());
548    ///
549    /// // There is no alpha channel.
550    /// assert!(flat.get_sample(3, 10, 10).is_none());
551    /// ```
552    ///
553    /// For cases where a special buffer does not provide `AsRef<[T]>`, consider encapsulating
554    /// bounds checks with `min_length` in a type similar to `View`. Then you may use
555    /// `in_bounds_index` as a small speedup over the index calculation of this method which relies
556    /// on `index_ignoring_bounds` since it can not have a-priori knowledge that the sample
557    /// coordinate is in fact backed by any memory buffer.
558    pub fn get_sample<T>(&self, channel: u8, x: u32, y: u32) -> Option<&T>
559    where
560        Buffer: AsRef<[T]>,
561    {
562        self.index(channel, x, y)
563            .and_then(|idx| self.samples.as_ref().get(idx))
564    }
565
566    /// Get a mutable reference to a single sample.
567    ///
568    /// This more restrictive than the method based on `std::ops::IndexMut` but guarantees to
569    /// properly check all bounds and not panic as long as `Buffer::as_ref` does not do so.
570    /// Contrary to conversion to `ViewMut`, this does not require that samples are packed since it
571    /// does not need to convert samples to a color representation.
572    ///
573    /// **WARNING**: Note that of course samples may alias, so that the mutable reference returned
574    /// here can in fact modify more than the coordinate in the argument.
575    ///
576    /// ```
577    /// # use image::{RgbImage};
578    /// let mut flat = RgbImage::new(480, 640).into_flat_samples();
579    ///
580    /// // Assign some new color to the blue channel at (10, 10).
581    /// *flat.get_mut_sample(1, 10, 10).unwrap() = 255;
582    ///
583    /// // There is no alpha channel.
584    /// assert!(flat.get_mut_sample(3, 10, 10).is_none());
585    /// ```
586    ///
587    /// For cases where a special buffer does not provide `AsRef<[T]>`, consider encapsulating
588    /// bounds checks with `min_length` in a type similar to `View`. Then you may use
589    /// `in_bounds_index` as a small speedup over the index calculation of this method which relies
590    /// on `index_ignoring_bounds` since it can not have a-priori knowledge that the sample
591    /// coordinate is in fact backed by any memory buffer.
592    pub fn get_mut_sample<T>(&mut self, channel: u8, x: u32, y: u32) -> Option<&mut T>
593    where
594        Buffer: AsMut<[T]>,
595    {
596        match self.index(channel, x, y) {
597            None => None,
598            Some(idx) => self.samples.as_mut().get_mut(idx),
599        }
600    }
601
602    /// View this buffer as an image over some type of pixel.
603    ///
604    /// This first ensures that all in-bounds coordinates refer to valid indices in the sample
605    /// buffer. It also checks that the specified pixel format expects the same number of channels
606    /// that are present in this buffer. Neither are larger nor a smaller number will be accepted.
607    /// There is no automatic conversion.
608    pub fn as_view<P>(&self) -> Result<View<&[P::Subpixel], P>, Error>
609    where
610        P: Pixel,
611        Buffer: AsRef<[P::Subpixel]>,
612    {
613        if self.layout.channels != P::CHANNEL_COUNT {
614            return Err(Error::ChannelCountMismatch(
615                self.layout.channels,
616                P::CHANNEL_COUNT,
617            ));
618        }
619
620        let as_ref = self.samples.as_ref();
621        if !self.layout.fits(as_ref.len()) {
622            return Err(Error::TooLarge);
623        }
624
625        Ok(View {
626            inner: FlatSamples {
627                samples: as_ref,
628                layout: self.layout,
629                color_hint: self.color_hint,
630            },
631            phantom: PhantomData,
632        })
633    }
634
635    /// View this buffer but keep mutability at a sample level.
636    ///
637    /// This is similar to `as_view` but subtly different from `as_view_mut`. The resulting type
638    /// can be used as a `GenericImage` with the same prior invariants needed as for `as_view`.
639    /// It can not be used as a mutable `GenericImage` but does not need channels to be packed in
640    /// their pixel representation.
641    ///
642    /// This first ensures that all in-bounds coordinates refer to valid indices in the sample
643    /// buffer. It also checks that the specified pixel format expects the same number of channels
644    /// that are present in this buffer. Neither are larger nor a smaller number will be accepted.
645    /// There is no automatic conversion.
646    ///
647    /// **WARNING**: Note that of course samples may alias, so that the mutable reference returned
648    /// for one sample can in fact modify other samples as well. Sometimes exactly this is
649    /// intended.
650    pub fn as_view_with_mut_samples<P>(&mut self) -> Result<View<&mut [P::Subpixel], P>, Error>
651    where
652        P: Pixel,
653        Buffer: AsMut<[P::Subpixel]>,
654    {
655        if self.layout.channels != P::CHANNEL_COUNT {
656            return Err(Error::ChannelCountMismatch(
657                self.layout.channels,
658                P::CHANNEL_COUNT,
659            ));
660        }
661
662        let as_mut = self.samples.as_mut();
663        if !self.layout.fits(as_mut.len()) {
664            return Err(Error::TooLarge);
665        }
666
667        Ok(View {
668            inner: FlatSamples {
669                samples: as_mut,
670                layout: self.layout,
671                color_hint: self.color_hint,
672            },
673            phantom: PhantomData,
674        })
675    }
676
677    /// Interpret this buffer as a mutable image.
678    ///
679    /// To succeed, the pixels in this buffer may not alias each other and the samples of each
680    /// pixel must be packed (i.e. `channel_stride` is `1`). The number of channels must be
681    /// consistent with the channel count expected by the pixel format.
682    ///
683    /// This is similar to an `ImageBuffer` except it is a temporary view that is not normalized as
684    /// strongly. To get an owning version, consider copying the data into an `ImageBuffer`. This
685    /// provides many more operations, is possibly faster (if not you may want to open an issue) is
686    /// generally polished. You can also try to convert this buffer inline, see
687    /// `ImageBuffer::from_raw`.
688    pub fn as_view_mut<P>(&mut self) -> Result<ViewMut<&mut [P::Subpixel], P>, Error>
689    where
690        P: Pixel,
691        Buffer: AsMut<[P::Subpixel]>,
692    {
693        if !self.layout.is_normal(NormalForm::PixelPacked) {
694            return Err(Error::NormalFormRequired(NormalForm::PixelPacked));
695        }
696
697        if self.layout.channels != P::CHANNEL_COUNT {
698            return Err(Error::ChannelCountMismatch(
699                self.layout.channels,
700                P::CHANNEL_COUNT,
701            ));
702        }
703
704        let as_mut = self.samples.as_mut();
705        if !self.layout.fits(as_mut.len()) {
706            return Err(Error::TooLarge);
707        }
708
709        Ok(ViewMut {
710            inner: FlatSamples {
711                samples: as_mut,
712                layout: self.layout,
713                color_hint: self.color_hint,
714            },
715            phantom: PhantomData,
716        })
717    }
718
719    /// View the samples as a slice.
720    ///
721    /// The slice is not limited to the region of the image and not all sample indices are valid
722    /// indices into this buffer. See `image_mut_slice` as an alternative.
723    pub fn as_slice<T>(&self) -> &[T]
724    where
725        Buffer: AsRef<[T]>,
726    {
727        self.samples.as_ref()
728    }
729
730    /// View the samples as a slice.
731    ///
732    /// The slice is not limited to the region of the image and not all sample indices are valid
733    /// indices into this buffer. See `image_mut_slice` as an alternative.
734    pub fn as_mut_slice<T>(&mut self) -> &mut [T]
735    where
736        Buffer: AsMut<[T]>,
737    {
738        self.samples.as_mut()
739    }
740
741    /// Return the portion of the buffer that holds sample values.
742    ///
743    /// This may fail when the coordinates in this image are either out-of-bounds of the underlying
744    /// buffer or can not be represented. Note that the slice may have holes that do not correspond
745    /// to any sample in the image represented by it.
746    pub fn image_slice<T>(&self) -> Option<&[T]>
747    where
748        Buffer: AsRef<[T]>,
749    {
750        let min_length = self.min_length()?;
751
752        let slice = self.samples.as_ref();
753        if slice.len() < min_length {
754            return None;
755        }
756
757        Some(&slice[..min_length])
758    }
759
760    /// Mutable portion of the buffer that holds sample values.
761    pub fn image_mut_slice<T>(&mut self) -> Option<&mut [T]>
762    where
763        Buffer: AsMut<[T]>,
764    {
765        let min_length = self.min_length()?;
766
767        let slice = self.samples.as_mut();
768        if slice.len() < min_length {
769            return None;
770        }
771
772        Some(&mut slice[..min_length])
773    }
774
775    /// Move the data into an image buffer.
776    ///
777    /// This does **not** convert the sample layout. The buffer needs to be in packed row-major form
778    /// before calling this function. In case of an error, returns the buffer again so that it does
779    /// not release any allocation.
780    pub fn try_into_buffer<P>(self) -> Result<ImageBuffer<P, Buffer>, (Error, Self)>
781    where
782        P: Pixel + 'static,
783        P::Subpixel: 'static,
784        Buffer: Deref<Target = [P::Subpixel]>,
785    {
786        if !self.is_normal(NormalForm::RowMajorPacked) {
787            return Err((Error::NormalFormRequired(NormalForm::RowMajorPacked), self));
788        }
789
790        if self.layout.channels != P::CHANNEL_COUNT {
791            return Err((
792                Error::ChannelCountMismatch(self.layout.channels, P::CHANNEL_COUNT),
793                self,
794            ));
795        }
796
797        if !self.fits(self.samples.deref().len()) {
798            return Err((Error::TooLarge, self));
799        }
800
801        Ok(
802            ImageBuffer::from_raw(self.layout.width, self.layout.height, self.samples)
803                .unwrap_or_else(|| {
804                    panic!("Preconditions should have been ensured before conversion")
805                }),
806        )
807    }
808
809    /// Get the minimum length of a buffer such that all in-bounds samples have valid indices.
810    ///
811    /// This method will allow zero strides, allowing compact representations of monochrome images.
812    /// To check that no aliasing occurs, try `check_alias_invariants`. For compact images (no
813    /// aliasing and no unindexed samples) this is `width*height*channels`. But for both of the
814    /// other cases, the reasoning is slightly more involved.
815    ///
816    /// # Explanation
817    ///
818    /// Note that there is a difference between `min_length` and the index of the sample
819    /// 'one-past-the-end'. This is due to strides that may be larger than the dimension below.
820    ///
821    /// ## Example with holes
822    ///
823    /// Let's look at an example of a grayscale image with
824    /// * `width_stride = 1`
825    /// * `width = 2`
826    /// * `height_stride = 3`
827    /// * `height = 2`
828    ///
829    /// ```text
830    /// | x x   | x x m | $
831    ///  min_length m ^
832    ///                   ^ one-past-the-end $
833    /// ```
834    ///
835    /// The difference is also extreme for empty images with large strides. The one-past-the-end
836    /// sample index is still as large as the largest of these strides while `min_length = 0`.
837    ///
838    /// ## Example with aliasing
839    ///
840    /// The concept gets even more important when you allow samples to alias each other. Here we
841    /// have the buffer of a small grayscale image where this is the case, this time we will first
842    /// show the buffer and then the individual rows below.
843    ///
844    /// * `width_stride = 1`
845    /// * `width = 3`
846    /// * `height_stride = 2`
847    /// * `height = 2`
848    ///
849    /// ```text
850    ///  1 2 3 4 5 m
851    /// |1 2 3| row one
852    ///     |3 4 5| row two
853    ///            ^ m min_length
854    ///          ^ ??? one-past-the-end
855    /// ```
856    ///
857    /// This time 'one-past-the-end' is not even simply the largest stride times the extent of its
858    /// dimension. That still points inside the image because `height*height_stride = 4` but also
859    /// `index_of(1, 2) = 4`.
860    pub fn min_length(&self) -> Option<usize> {
861        self.layout.min_length()
862    }
863
864    /// Check if a buffer of length `len` is large enough.
865    pub fn fits(&self, len: usize) -> bool {
866        self.layout.fits(len)
867    }
868
869    /// If there are any samples aliasing each other.
870    ///
871    /// If this is not the case, it would always be safe to allow mutable access to two different
872    /// samples at the same time. Otherwise, this operation would need additional checks. When one
873    /// dimension overflows `usize` with its stride we also consider this aliasing.
874    pub fn has_aliased_samples(&self) -> bool {
875        self.layout.has_aliased_samples()
876    }
877
878    /// Check if a buffer fulfills the requirements of a normal form.
879    ///
880    /// Certain conversions have preconditions on the structure of the sample buffer that are not
881    /// captured (by design) by the type system. These are then checked before the conversion. Such
882    /// checks can all be done in constant time and will not inspect the buffer content. You can
883    /// perform these checks yourself when the conversion is not required at this moment but maybe
884    /// still performed later.
885    pub fn is_normal(&self, form: NormalForm) -> bool {
886        self.layout.is_normal(form)
887    }
888
889    /// Check that the pixel and the channel index are in bounds.
890    ///
891    /// An in-bound coordinate does not yet guarantee that the corresponding calculation of a
892    /// buffer index does not overflow. However, if such a buffer large enough to hold all samples
893    /// actually exists in memory, this property of course follows.
894    pub fn in_bounds(&self, channel: u8, x: u32, y: u32) -> bool {
895        self.layout.in_bounds(channel, x, y)
896    }
897
898    /// Resolve the index of a particular sample.
899    ///
900    /// `None` if the index is outside the bounds or does not fit into a `usize`.
901    pub fn index(&self, channel: u8, x: u32, y: u32) -> Option<usize> {
902        self.layout.index(channel, x, y)
903    }
904
905    /// Get the theoretical position of sample (x, y, channel).
906    ///
907    /// The 'check' is for overflow during index calculation, not that it is contained in the
908    /// image. Two samples may return the same index, even when one of them is out of bounds. This
909    /// happens when all strides are `0`, i.e. the image is an arbitrarily large monochrome image.
910    pub fn index_ignoring_bounds(&self, channel: usize, x: usize, y: usize) -> Option<usize> {
911        self.layout.index_ignoring_bounds(channel, x, y)
912    }
913
914    /// Get an index provided it is inbouds.
915    ///
916    /// Assumes that the image is backed by some sufficiently large buffer. Then computation can
917    /// not overflow as we could represent the maximum coordinate. Since overflow is defined either
918    /// way, this method can not be unsafe.
919    pub fn in_bounds_index(&self, channel: u8, x: u32, y: u32) -> usize {
920        self.layout.in_bounds_index(channel, x, y)
921    }
922
923    /// Shrink the image to the minimum of current and given extents.
924    ///
925    /// This does not modify the strides, so that the resulting sample buffer may have holes
926    /// created by the shrinking operation. Shrinking could also lead to an non-aliasing image when
927    /// samples had aliased each other before.
928    pub fn shrink_to(&mut self, channels: u8, width: u32, height: u32) {
929        self.layout.shrink_to(channels, width, height);
930    }
931}
932
933impl<'buf, Subpixel> FlatSamples<&'buf [Subpixel]> {
934    /// Create a monocolor image from a single pixel.
935    ///
936    /// This can be used as a very cheap source of a `GenericImageView` with an arbitrary number of
937    /// pixels of a single color, without any dynamic allocation.
938    ///
939    /// ## Examples
940    ///
941    /// ```
942    /// # fn paint_something<T>(_: T) {}
943    /// use image::{flat::FlatSamples, GenericImage, RgbImage, Rgb};
944    ///
945    /// let background = Rgb([20, 20, 20]);
946    /// let bg = FlatSamples::with_monocolor(&background, 200, 200);
947    ///
948    /// let mut image = RgbImage::new(200, 200);
949    /// paint_something(&mut image);
950    ///
951    /// // Reset the canvas
952    /// image.copy_from(&bg.as_view().unwrap(), 0, 0);
953    /// ```
954    pub fn with_monocolor<P>(pixel: &'buf P, width: u32, height: u32) -> Self
955    where
956        P: Pixel<Subpixel = Subpixel>,
957        Subpixel: crate::Primitive,
958    {
959        FlatSamples {
960            samples: pixel.channels(),
961            layout: SampleLayout {
962                channels: P::CHANNEL_COUNT,
963                channel_stride: 1,
964                width,
965                width_stride: 0,
966                height,
967                height_stride: 0,
968            },
969
970            // TODO this value is never set. It should be set in all places where the Pixel type implements PixelWithColorType
971            color_hint: None,
972        }
973    }
974}
975
976/// A flat buffer that can be used as an image view.
977///
978/// This is a nearly trivial wrapper around a buffer but at least sanitizes by checking the buffer
979/// length first and constraining the pixel type.
980///
981/// Note that this does not eliminate panics as the `AsRef<[T]>` implementation of `Buffer` may be
982/// unreliable, i.e. return different buffers at different times. This of course is a non-issue for
983/// all common collections where the bounds check once must be enough.
984///
985/// # Inner invariants
986///
987/// * For all indices inside bounds, the corresponding index is valid in the buffer
988/// * `P::channel_count()` agrees with `self.inner.layout.channels`
989#[derive(Clone, Debug)]
990pub struct View<Buffer, P: Pixel>
991where
992    Buffer: AsRef<[P::Subpixel]>,
993{
994    inner: FlatSamples<Buffer>,
995    phantom: PhantomData<P>,
996}
997
998/// A mutable owning version of a flat buffer.
999///
1000/// While this wraps a buffer similar to `ImageBuffer`, this is mostly intended as a utility. The
1001/// library endorsed normalized representation is still `ImageBuffer`. Also, the implementation of
1002/// `AsMut<[P::Subpixel]>` must always yield the same buffer. Therefore there is no public way to
1003/// construct this with an owning buffer.
1004///
1005/// # Inner invariants
1006///
1007/// * For all indices inside bounds, the corresponding index is valid in the buffer
1008/// * There is no aliasing of samples
1009/// * The samples are packed, i.e. `self.inner.layout.sample_stride == 1`
1010/// * `P::channel_count()` agrees with `self.inner.layout.channels`
1011#[derive(Clone, Debug)]
1012pub struct ViewMut<Buffer, P: Pixel>
1013where
1014    Buffer: AsMut<[P::Subpixel]>,
1015{
1016    inner: FlatSamples<Buffer>,
1017    phantom: PhantomData<P>,
1018}
1019
1020/// Denotes invalid flat sample buffers when trying to convert to stricter types.
1021///
1022/// The biggest use case being `ImageBuffer` which expects closely packed
1023/// samples in a row major matrix representation. But this error type may be
1024/// reused for other import functions. A more versatile user may also try to
1025/// correct the underlying representation depending on the error variant.
1026#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1027pub enum Error {
1028    /// The represented image was too large.
1029    ///
1030    /// The optional value denotes a possibly accepted maximal bound.
1031    TooLarge,
1032
1033    /// The represented image can not use this representation.
1034    ///
1035    /// Has an additional value of the normalized form that would be accepted.
1036    NormalFormRequired(NormalForm),
1037
1038    /// The color format did not match the channel count.
1039    ///
1040    /// In some cases you might be able to fix this by lowering the reported pixel count of the
1041    /// buffer without touching the strides.
1042    ///
1043    /// In very special circumstances you *may* do the opposite. This is **VERY** dangerous but not
1044    /// directly memory unsafe although that will likely alias pixels. One scenario is when you
1045    /// want to construct an `Rgba` image but have only 3 bytes per pixel and for some reason don't
1046    /// care about the value of the alpha channel even though you need `Rgba`.
1047    ChannelCountMismatch(u8, u8),
1048
1049    /// Deprecated - `ChannelCountMismatch` is used instead
1050    WrongColor(ColorType),
1051}
1052
1053/// Different normal forms of buffers.
1054///
1055/// A normal form is an unaliased buffer with some additional constraints.  The `ÌmageBuffer` uses
1056/// row major form with packed samples.
1057#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1058pub enum NormalForm {
1059    /// No pixel aliases another.
1060    ///
1061    /// Unaliased also guarantees that all index calculations in the image bounds using
1062    /// `dim_index*dim_stride` (such as `x*width_stride + y*height_stride`) do not overflow.
1063    Unaliased,
1064
1065    /// At least pixels are packed.
1066    ///
1067    /// Images of these types can wrap `[T]`-slices into the standard color types. This is a
1068    /// precondition for `GenericImage` which requires by-reference access to pixels.
1069    PixelPacked,
1070
1071    /// All samples are packed.
1072    ///
1073    /// This is orthogonal to `PixelPacked`. It requires that there are no holes in the image but
1074    /// it is not necessary that the pixel samples themselves are adjacent. An example of this
1075    /// behaviour is a planar image layout.
1076    ImagePacked,
1077
1078    /// The samples are in row-major form and all samples are packed.
1079    ///
1080    /// In addition to `PixelPacked` and `ImagePacked` this also asserts that the pixel matrix is
1081    /// in row-major form.
1082    RowMajorPacked,
1083
1084    /// The samples are in column-major form and all samples are packed.
1085    ///
1086    /// In addition to `PixelPacked` and `ImagePacked` this also asserts that the pixel matrix is
1087    /// in column-major form.
1088    ColumnMajorPacked,
1089}
1090
1091impl<Buffer, P: Pixel> View<Buffer, P>
1092where
1093    Buffer: AsRef<[P::Subpixel]>,
1094{
1095    /// Take out the sample buffer.
1096    ///
1097    /// Gives up the normalization invariants on the buffer format.
1098    pub fn into_inner(self) -> FlatSamples<Buffer> {
1099        self.inner
1100    }
1101
1102    /// Get a reference on the inner sample descriptor.
1103    ///
1104    /// There is no mutable counterpart as modifying the buffer format, including strides and
1105    /// lengths, could invalidate the accessibility invariants of the `View`. It is not specified
1106    /// if the inner buffer is the same as the buffer of the image from which this view was
1107    /// created. It might have been truncated as an optimization.
1108    pub fn flat(&self) -> &FlatSamples<Buffer> {
1109        &self.inner
1110    }
1111
1112    /// Get a reference on the inner buffer.
1113    ///
1114    /// There is no mutable counter part since it is not intended to allow you to reassign the
1115    /// buffer or otherwise change its size or properties.
1116    pub fn samples(&self) -> &Buffer {
1117        &self.inner.samples
1118    }
1119
1120    /// Get a reference to a selected subpixel if it is in-bounds.
1121    ///
1122    /// This method will return `None` when the sample is out-of-bounds. All errors that could
1123    /// occur due to overflow have been eliminated while construction the `View`.
1124    pub fn get_sample(&self, channel: u8, x: u32, y: u32) -> Option<&P::Subpixel> {
1125        if !self.inner.in_bounds(channel, x, y) {
1126            return None;
1127        }
1128
1129        let index = self.inner.in_bounds_index(channel, x, y);
1130        // Should always be `Some(_)` but checking is more costly.
1131        self.samples().as_ref().get(index)
1132    }
1133
1134    /// Get a mutable reference to a selected subpixel if it is in-bounds.
1135    ///
1136    /// This is relevant only when constructed with `FlatSamples::as_view_with_mut_samples`.  This
1137    /// method will return `None` when the sample is out-of-bounds. All errors that could occur due
1138    /// to overflow have been eliminated while construction the `View`.
1139    ///
1140    /// **WARNING**: Note that of course samples may alias, so that the mutable reference returned
1141    /// here can in fact modify more than the coordinate in the argument.
1142    pub fn get_mut_sample(&mut self, channel: u8, x: u32, y: u32) -> Option<&mut P::Subpixel>
1143    where
1144        Buffer: AsMut<[P::Subpixel]>,
1145    {
1146        if !self.inner.in_bounds(channel, x, y) {
1147            return None;
1148        }
1149
1150        let index = self.inner.in_bounds_index(channel, x, y);
1151        // Should always be `Some(_)` but checking is more costly.
1152        self.inner.samples.as_mut().get_mut(index)
1153    }
1154
1155    /// Get the minimum length of a buffer such that all in-bounds samples have valid indices.
1156    ///
1157    /// See `FlatSamples::min_length`. This method will always succeed.
1158    pub fn min_length(&self) -> usize {
1159        self.inner.min_length().unwrap()
1160    }
1161
1162    /// Return the portion of the buffer that holds sample values.
1163    ///
1164    /// While this can not fail–the validity of all coordinates has been validated during the
1165    /// conversion from `FlatSamples`–the resulting slice may still contain holes.
1166    pub fn image_slice(&self) -> &[P::Subpixel] {
1167        &self.samples().as_ref()[..self.min_length()]
1168    }
1169
1170    /// Return the mutable portion of the buffer that holds sample values.
1171    ///
1172    /// This is relevant only when constructed with `FlatSamples::as_view_with_mut_samples`. While
1173    /// this can not fail–the validity of all coordinates has been validated during the conversion
1174    /// from `FlatSamples`–the resulting slice may still contain holes.
1175    pub fn image_mut_slice(&mut self) -> &mut [P::Subpixel]
1176    where
1177        Buffer: AsMut<[P::Subpixel]>,
1178    {
1179        let min_length = self.min_length();
1180        &mut self.inner.samples.as_mut()[..min_length]
1181    }
1182
1183    /// Shrink the inner image.
1184    ///
1185    /// The new dimensions will be the minimum of the previous dimensions. Since the set of
1186    /// in-bounds pixels afterwards is a subset of the current ones, this is allowed on a `View`.
1187    /// Note that you can not change the number of channels as an intrinsic property of `P`.
1188    pub fn shrink_to(&mut self, width: u32, height: u32) {
1189        let channels = self.inner.layout.channels;
1190        self.inner.shrink_to(channels, width, height);
1191    }
1192
1193    /// Try to convert this into an image with mutable pixels.
1194    ///
1195    /// The resulting image implements `GenericImage` in addition to `GenericImageView`. While this
1196    /// has mutable samples, it does not enforce that pixel can not alias and that samples are
1197    /// packed enough for a mutable pixel reference. This is slightly cheaper than the chain
1198    /// `self.into_inner().as_view_mut()` and keeps the `View` alive on failure.
1199    ///
1200    /// ```
1201    /// # use image::RgbImage;
1202    /// # use image::Rgb;
1203    /// let mut buffer = RgbImage::new(480, 640).into_flat_samples();
1204    /// let view = buffer.as_view_with_mut_samples::<Rgb<u8>>().unwrap();
1205    ///
1206    /// // Inspect some pixels, …
1207    ///
1208    /// // Doesn't fail because it was originally an `RgbImage`.
1209    /// let view_mut = view.try_upgrade().unwrap();
1210    /// ```
1211    pub fn try_upgrade(self) -> Result<ViewMut<Buffer, P>, (Error, Self)>
1212    where
1213        Buffer: AsMut<[P::Subpixel]>,
1214    {
1215        if !self.inner.is_normal(NormalForm::PixelPacked) {
1216            return Err((Error::NormalFormRequired(NormalForm::PixelPacked), self));
1217        }
1218
1219        // No length check or channel count check required, all the same.
1220        Ok(ViewMut {
1221            inner: self.inner,
1222            phantom: PhantomData,
1223        })
1224    }
1225}
1226
1227impl<Buffer, P: Pixel> ViewMut<Buffer, P>
1228where
1229    Buffer: AsMut<[P::Subpixel]>,
1230{
1231    /// Take out the sample buffer.
1232    ///
1233    /// Gives up the normalization invariants on the buffer format.
1234    pub fn into_inner(self) -> FlatSamples<Buffer> {
1235        self.inner
1236    }
1237
1238    /// Get a reference on the sample buffer descriptor.
1239    ///
1240    /// There is no mutable counterpart as modifying the buffer format, including strides and
1241    /// lengths, could invalidate the accessibility invariants of the `View`. It is not specified
1242    /// if the inner buffer is the same as the buffer of the image from which this view was
1243    /// created. It might have been truncated as an optimization.
1244    pub fn flat(&self) -> &FlatSamples<Buffer> {
1245        &self.inner
1246    }
1247
1248    /// Get a reference on the inner buffer.
1249    ///
1250    /// There is no mutable counter part since it is not intended to allow you to reassign the
1251    /// buffer or otherwise change its size or properties. However, its contents can be accessed
1252    /// mutable through a slice with `image_mut_slice`.
1253    pub fn samples(&self) -> &Buffer {
1254        &self.inner.samples
1255    }
1256
1257    /// Get the minimum length of a buffer such that all in-bounds samples have valid indices.
1258    ///
1259    /// See `FlatSamples::min_length`. This method will always succeed.
1260    pub fn min_length(&self) -> usize {
1261        self.inner.min_length().unwrap()
1262    }
1263
1264    /// Get a reference to a selected subpixel.
1265    ///
1266    /// This method will return `None` when the sample is out-of-bounds. All errors that could
1267    /// occur due to overflow have been eliminated while construction the `View`.
1268    pub fn get_sample(&self, channel: u8, x: u32, y: u32) -> Option<&P::Subpixel>
1269    where
1270        Buffer: AsRef<[P::Subpixel]>,
1271    {
1272        if !self.inner.in_bounds(channel, x, y) {
1273            return None;
1274        }
1275
1276        let index = self.inner.in_bounds_index(channel, x, y);
1277        // Should always be `Some(_)` but checking is more costly.
1278        self.samples().as_ref().get(index)
1279    }
1280
1281    /// Get a mutable reference to a selected sample.
1282    ///
1283    /// This method will return `None` when the sample is out-of-bounds. All errors that could
1284    /// occur due to overflow have been eliminated while construction the `View`.
1285    pub fn get_mut_sample(&mut self, channel: u8, x: u32, y: u32) -> Option<&mut P::Subpixel> {
1286        if !self.inner.in_bounds(channel, x, y) {
1287            return None;
1288        }
1289
1290        let index = self.inner.in_bounds_index(channel, x, y);
1291        // Should always be `Some(_)` but checking is more costly.
1292        self.inner.samples.as_mut().get_mut(index)
1293    }
1294
1295    /// Return the portion of the buffer that holds sample values.
1296    ///
1297    /// While this can not fail–the validity of all coordinates has been validated during the
1298    /// conversion from `FlatSamples`–the resulting slice may still contain holes.
1299    pub fn image_slice(&self) -> &[P::Subpixel]
1300    where
1301        Buffer: AsRef<[P::Subpixel]>,
1302    {
1303        &self.inner.samples.as_ref()[..self.min_length()]
1304    }
1305
1306    /// Return the mutable buffer that holds sample values.
1307    pub fn image_mut_slice(&mut self) -> &mut [P::Subpixel] {
1308        let length = self.min_length();
1309        &mut self.inner.samples.as_mut()[..length]
1310    }
1311
1312    /// Shrink the inner image.
1313    ///
1314    /// The new dimensions will be the minimum of the previous dimensions. Since the set of
1315    /// in-bounds pixels afterwards is a subset of the current ones, this is allowed on a `View`.
1316    /// Note that you can not change the number of channels as an intrinsic property of `P`.
1317    pub fn shrink_to(&mut self, width: u32, height: u32) {
1318        let channels = self.inner.layout.channels;
1319        self.inner.shrink_to(channels, width, height);
1320    }
1321}
1322
1323// The out-of-bounds panic for single sample access similar to `slice::index`.
1324#[inline(never)]
1325#[cold]
1326fn panic_cwh_out_of_bounds(
1327    (c, x, y): (u8, u32, u32),
1328    bounds: (u8, u32, u32),
1329    strides: (usize, usize, usize),
1330) -> ! {
1331    panic!(
1332        "Sample coordinates {:?} out of sample matrix bounds {:?} with strides {:?}",
1333        (c, x, y),
1334        bounds,
1335        strides
1336    )
1337}
1338
1339// The out-of-bounds panic for pixel access similar to `slice::index`.
1340#[inline(never)]
1341#[cold]
1342fn panic_pixel_out_of_bounds((x, y): (u32, u32), bounds: (u32, u32)) -> ! {
1343    panic!("Image index {:?} out of bounds {:?}", (x, y), bounds)
1344}
1345
1346impl<Buffer> Index<(u8, u32, u32)> for FlatSamples<Buffer>
1347where
1348    Buffer: Index<usize>,
1349{
1350    type Output = Buffer::Output;
1351
1352    /// Return a reference to a single sample at specified coordinates.
1353    ///
1354    /// # Panics
1355    ///
1356    /// When the coordinates are out of bounds or the index calculation fails.
1357    fn index(&self, (c, x, y): (u8, u32, u32)) -> &Self::Output {
1358        let bounds = self.bounds();
1359        let strides = self.strides_cwh();
1360        let index = self
1361            .index(c, x, y)
1362            .unwrap_or_else(|| panic_cwh_out_of_bounds((c, x, y), bounds, strides));
1363        &self.samples[index]
1364    }
1365}
1366
1367impl<Buffer> IndexMut<(u8, u32, u32)> for FlatSamples<Buffer>
1368where
1369    Buffer: IndexMut<usize>,
1370{
1371    /// Return a mutable reference to a single sample at specified coordinates.
1372    ///
1373    /// # Panics
1374    ///
1375    /// When the coordinates are out of bounds or the index calculation fails.
1376    fn index_mut(&mut self, (c, x, y): (u8, u32, u32)) -> &mut Self::Output {
1377        let bounds = self.bounds();
1378        let strides = self.strides_cwh();
1379        let index = self
1380            .index(c, x, y)
1381            .unwrap_or_else(|| panic_cwh_out_of_bounds((c, x, y), bounds, strides));
1382        &mut self.samples[index]
1383    }
1384}
1385
1386impl<Buffer, P: Pixel> GenericImageView for View<Buffer, P>
1387where
1388    Buffer: AsRef<[P::Subpixel]>,
1389{
1390    type Pixel = P;
1391
1392    fn dimensions(&self) -> (u32, u32) {
1393        (self.inner.layout.width, self.inner.layout.height)
1394    }
1395
1396    fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
1397        if !self.inner.in_bounds(0, x, y) {
1398            panic_pixel_out_of_bounds((x, y), self.dimensions())
1399        }
1400
1401        let image = self.inner.samples.as_ref();
1402        let base_index = self.inner.in_bounds_index(0, x, y);
1403        let channels = P::CHANNEL_COUNT as usize;
1404
1405        let mut buffer = [Zero::zero(); 256];
1406        buffer
1407            .iter_mut()
1408            .enumerate()
1409            .take(channels)
1410            .for_each(|(c, to)| {
1411                let index = base_index + c * self.inner.layout.channel_stride;
1412                *to = image[index];
1413            });
1414
1415        *P::from_slice(&buffer[..channels])
1416    }
1417}
1418
1419impl<Buffer, P: Pixel> GenericImageView for ViewMut<Buffer, P>
1420where
1421    Buffer: AsMut<[P::Subpixel]> + AsRef<[P::Subpixel]>,
1422{
1423    type Pixel = P;
1424
1425    fn dimensions(&self) -> (u32, u32) {
1426        (self.inner.layout.width, self.inner.layout.height)
1427    }
1428
1429    fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
1430        if !self.inner.in_bounds(0, x, y) {
1431            panic_pixel_out_of_bounds((x, y), self.dimensions())
1432        }
1433
1434        let image = self.inner.samples.as_ref();
1435        let base_index = self.inner.in_bounds_index(0, x, y);
1436        let channels = P::CHANNEL_COUNT as usize;
1437
1438        let mut buffer = [Zero::zero(); 256];
1439        buffer
1440            .iter_mut()
1441            .enumerate()
1442            .take(channels)
1443            .for_each(|(c, to)| {
1444                let index = base_index + c * self.inner.layout.channel_stride;
1445                *to = image[index];
1446            });
1447
1448        *P::from_slice(&buffer[..channels])
1449    }
1450}
1451
1452impl<Buffer, P: Pixel> GenericImage for ViewMut<Buffer, P>
1453where
1454    Buffer: AsMut<[P::Subpixel]> + AsRef<[P::Subpixel]>,
1455{
1456    fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut Self::Pixel {
1457        if !self.inner.in_bounds(0, x, y) {
1458            panic_pixel_out_of_bounds((x, y), self.dimensions())
1459        }
1460
1461        let base_index = self.inner.in_bounds_index(0, x, y);
1462        let channel_count = <P as Pixel>::CHANNEL_COUNT as usize;
1463        let pixel_range = base_index..base_index + channel_count;
1464        P::from_slice_mut(&mut self.inner.samples.as_mut()[pixel_range])
1465    }
1466
1467    #[allow(deprecated)]
1468    fn put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
1469        *self.get_pixel_mut(x, y) = pixel;
1470    }
1471
1472    #[allow(deprecated)]
1473    fn blend_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
1474        self.get_pixel_mut(x, y).blend(&pixel);
1475    }
1476}
1477
1478impl From<Error> for ImageError {
1479    fn from(error: Error) -> ImageError {
1480        #[derive(Debug)]
1481        struct NormalFormRequiredError(NormalForm);
1482        impl fmt::Display for NormalFormRequiredError {
1483            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1484                write!(f, "Required sample buffer in normal form {:?}", self.0)
1485            }
1486        }
1487        impl error::Error for NormalFormRequiredError {}
1488
1489        match error {
1490            Error::TooLarge => ImageError::Parameter(ParameterError::from_kind(
1491                ParameterErrorKind::DimensionMismatch,
1492            )),
1493            Error::NormalFormRequired(form) => ImageError::Decoding(DecodingError::new(
1494                ImageFormatHint::Unknown,
1495                NormalFormRequiredError(form),
1496            )),
1497            Error::ChannelCountMismatch(_lc, _pc) => ImageError::Parameter(
1498                ParameterError::from_kind(ParameterErrorKind::DimensionMismatch),
1499            ),
1500            Error::WrongColor(color) => {
1501                ImageError::Unsupported(UnsupportedError::from_format_and_kind(
1502                    ImageFormatHint::Unknown,
1503                    UnsupportedErrorKind::Color(color.into()),
1504                ))
1505            }
1506        }
1507    }
1508}
1509
1510impl fmt::Display for Error {
1511    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1512        match self {
1513            Error::TooLarge => write!(f, "The layout is too large"),
1514            Error::NormalFormRequired(form) => write!(
1515                f,
1516                "The layout needs to {}",
1517                match form {
1518                    NormalForm::ColumnMajorPacked => "be packed and in column major form",
1519                    NormalForm::ImagePacked => "be fully packed",
1520                    NormalForm::PixelPacked => "have packed pixels",
1521                    NormalForm::RowMajorPacked => "be packed and in row major form",
1522                    NormalForm::Unaliased => "not have any aliasing channels",
1523                }
1524            ),
1525            Error::ChannelCountMismatch(layout_channels, pixel_channels) => {
1526                write!(f, "The channel count of the chosen pixel (={pixel_channels}) does agree with the layout (={layout_channels})")
1527            }
1528            Error::WrongColor(color) => {
1529                write!(f, "The chosen color type does not match the hint {color:?}")
1530            }
1531        }
1532    }
1533}
1534
1535impl error::Error for Error {}
1536
1537impl PartialOrd for NormalForm {
1538    /// Compares the logical preconditions.
1539    ///
1540    /// `a < b` if the normal form `a` has less preconditions than `b`.
1541    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
1542        match (*self, *other) {
1543            (NormalForm::Unaliased, NormalForm::Unaliased) => Some(cmp::Ordering::Equal),
1544            (NormalForm::PixelPacked, NormalForm::PixelPacked) => Some(cmp::Ordering::Equal),
1545            (NormalForm::ImagePacked, NormalForm::ImagePacked) => Some(cmp::Ordering::Equal),
1546            (NormalForm::RowMajorPacked, NormalForm::RowMajorPacked) => Some(cmp::Ordering::Equal),
1547            (NormalForm::ColumnMajorPacked, NormalForm::ColumnMajorPacked) => {
1548                Some(cmp::Ordering::Equal)
1549            }
1550
1551            (NormalForm::Unaliased, _) => Some(cmp::Ordering::Less),
1552            (_, NormalForm::Unaliased) => Some(cmp::Ordering::Greater),
1553
1554            (NormalForm::PixelPacked, NormalForm::ColumnMajorPacked) => Some(cmp::Ordering::Less),
1555            (NormalForm::PixelPacked, NormalForm::RowMajorPacked) => Some(cmp::Ordering::Less),
1556            (NormalForm::RowMajorPacked, NormalForm::PixelPacked) => Some(cmp::Ordering::Greater),
1557            (NormalForm::ColumnMajorPacked, NormalForm::PixelPacked) => {
1558                Some(cmp::Ordering::Greater)
1559            }
1560
1561            (NormalForm::ImagePacked, NormalForm::ColumnMajorPacked) => Some(cmp::Ordering::Less),
1562            (NormalForm::ImagePacked, NormalForm::RowMajorPacked) => Some(cmp::Ordering::Less),
1563            (NormalForm::RowMajorPacked, NormalForm::ImagePacked) => Some(cmp::Ordering::Greater),
1564            (NormalForm::ColumnMajorPacked, NormalForm::ImagePacked) => {
1565                Some(cmp::Ordering::Greater)
1566            }
1567
1568            (NormalForm::ImagePacked, NormalForm::PixelPacked) => None,
1569            (NormalForm::PixelPacked, NormalForm::ImagePacked) => None,
1570            (NormalForm::RowMajorPacked, NormalForm::ColumnMajorPacked) => None,
1571            (NormalForm::ColumnMajorPacked, NormalForm::RowMajorPacked) => None,
1572        }
1573    }
1574}
1575
1576#[cfg(test)]
1577mod tests {
1578    use super::*;
1579    use crate::buffer_::GrayAlphaImage;
1580    use crate::color::{LumaA, Rgb};
1581
1582    #[test]
1583    fn aliasing_view() {
1584        let buffer = FlatSamples {
1585            samples: &[42],
1586            layout: SampleLayout {
1587                channels: 3,
1588                channel_stride: 0,
1589                width: 100,
1590                width_stride: 0,
1591                height: 100,
1592                height_stride: 0,
1593            },
1594            color_hint: None,
1595        };
1596
1597        let view = buffer.as_view::<Rgb<u8>>().expect("This is a valid view");
1598        let pixel_count = view
1599            .pixels()
1600            .inspect(|pixel| assert!(pixel.2 == Rgb([42, 42, 42])))
1601            .count();
1602        assert_eq!(pixel_count, 100 * 100);
1603    }
1604
1605    #[test]
1606    fn mutable_view() {
1607        let mut buffer = FlatSamples {
1608            samples: [0; 18],
1609            layout: SampleLayout {
1610                channels: 2,
1611                channel_stride: 1,
1612                width: 3,
1613                width_stride: 2,
1614                height: 3,
1615                height_stride: 6,
1616            },
1617            color_hint: None,
1618        };
1619
1620        {
1621            let mut view = buffer
1622                .as_view_mut::<LumaA<u16>>()
1623                .expect("This should be a valid mutable buffer");
1624            assert_eq!(view.dimensions(), (3, 3));
1625            #[allow(deprecated)]
1626            for i in 0..9 {
1627                *view.get_pixel_mut(i % 3, i / 3) = LumaA([2 * i as u16, 2 * i as u16 + 1]);
1628            }
1629        }
1630
1631        buffer
1632            .samples
1633            .iter()
1634            .enumerate()
1635            .for_each(|(idx, sample)| assert_eq!(idx, *sample as usize));
1636    }
1637
1638    #[test]
1639    fn normal_forms() {
1640        assert!(FlatSamples {
1641            samples: [0u8; 0],
1642            layout: SampleLayout {
1643                channels: 2,
1644                channel_stride: 1,
1645                width: 3,
1646                width_stride: 9,
1647                height: 3,
1648                height_stride: 28,
1649            },
1650            color_hint: None,
1651        }
1652        .is_normal(NormalForm::PixelPacked));
1653
1654        assert!(FlatSamples {
1655            samples: [0u8; 0],
1656            layout: SampleLayout {
1657                channels: 2,
1658                channel_stride: 8,
1659                width: 4,
1660                width_stride: 1,
1661                height: 2,
1662                height_stride: 4,
1663            },
1664            color_hint: None,
1665        }
1666        .is_normal(NormalForm::ImagePacked));
1667
1668        assert!(FlatSamples {
1669            samples: [0u8; 0],
1670            layout: SampleLayout {
1671                channels: 2,
1672                channel_stride: 1,
1673                width: 4,
1674                width_stride: 2,
1675                height: 2,
1676                height_stride: 8,
1677            },
1678            color_hint: None,
1679        }
1680        .is_normal(NormalForm::RowMajorPacked));
1681
1682        assert!(FlatSamples {
1683            samples: [0u8; 0],
1684            layout: SampleLayout {
1685                channels: 2,
1686                channel_stride: 1,
1687                width: 4,
1688                width_stride: 4,
1689                height: 2,
1690                height_stride: 2,
1691            },
1692            color_hint: None,
1693        }
1694        .is_normal(NormalForm::ColumnMajorPacked));
1695    }
1696
1697    #[test]
1698    fn image_buffer_conversion() {
1699        let expected_layout = SampleLayout {
1700            channels: 2,
1701            channel_stride: 1,
1702            width: 4,
1703            width_stride: 2,
1704            height: 2,
1705            height_stride: 8,
1706        };
1707
1708        let initial = GrayAlphaImage::new(expected_layout.width, expected_layout.height);
1709        let buffer = initial.into_flat_samples();
1710
1711        assert_eq!(buffer.layout, expected_layout);
1712
1713        let _: GrayAlphaImage = buffer.try_into_buffer().unwrap_or_else(|(error, _)| {
1714            panic!("Expected buffer to be convertible but {:?}", error)
1715        });
1716    }
1717}