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