Coverage Report

Created: 2025-07-11 07:25

/src/image/src/images/flat.rs
Line
Count
Source (jump to first uncovered line)
1
//! Image representations for ffi.
2
//!
3
//! # Usage
4
//!
5
//! Imagine you want to offer a very simple ffi interface: The caller provides an image buffer and
6
//! your program creates a thumbnail from it and dumps that image as `png`. This module is designed
7
//! to help you transition from raw memory data to Rust representation.
8
//!
9
//! ```no_run
10
//! use std::ptr;
11
//! use std::slice;
12
//! use image::Rgb;
13
//! use image::flat::{FlatSamples, SampleLayout};
14
//! use image::imageops::thumbnail;
15
//!
16
//! #[no_mangle]
17
//! pub extern "C" fn store_rgb8_compressed(
18
//!     data: *const u8, len: usize,
19
//!     layout: *const SampleLayout
20
//! )
21
//!     -> bool
22
//! {
23
//!     let samples = unsafe { slice::from_raw_parts(data, len) };
24
//!     let layout = unsafe { ptr::read(layout) };
25
//!
26
//!     let buffer = FlatSamples {
27
//!         samples,
28
//!         layout,
29
//!         color_hint: None,
30
//!     };
31
//!
32
//!     let view = match buffer.as_view::<Rgb<u8>>() {
33
//!         Err(_) => return false, // Invalid layout.
34
//!         Ok(view) => view,
35
//!     };
36
//!
37
//!     thumbnail(&view, 64, 64)
38
//!         .save("output.png")
39
//!         .map(|_| true)
40
//!         .unwrap_or_else(|_| false)
41
//! }
42
//! ```
43
//!
44
use std::marker::PhantomData;
45
use std::ops::{Deref, Index, IndexMut};
46
use std::{cmp, error, fmt};
47
48
use num_traits::Zero;
49
50
use crate::color::ColorType;
51
use crate::error::{
52
    DecodingError, ImageError, ImageFormatHint, ParameterError, ParameterErrorKind,
53
    UnsupportedError, UnsupportedErrorKind,
54
};
55
use crate::traits::Pixel;
56
use 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)]
83
pub 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)]
102
pub 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)]
124
struct Dim(usize, usize);
125
126
impl 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
0
    pub fn row_major_packed(channels: u8, width: u32, height: u32) -> Self {
145
0
        let height_stride = (channels as usize).checked_mul(width as usize).expect(
146
0
            "Row major packed image can not be described because it does not fit into memory",
147
0
        );
148
0
        SampleLayout {
149
0
            channels,
150
0
            channel_stride: 1,
151
0
            width,
152
0
            width_stride: channels as usize,
153
0
            height,
154
0
            height_stride,
155
0
        }
156
0
    }
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
0
    pub fn column_major_packed(channels: u8, width: u32, height: u32) -> Self {
176
0
        let width_stride = (channels as usize).checked_mul(height as usize).expect(
177
0
            "Column major packed image can not be described because it does not fit into memory",
178
0
        );
179
0
        SampleLayout {
180
0
            channels,
181
0
            channel_stride: 1,
182
0
            height,
183
0
            height_stride: channels as usize,
184
0
            width,
185
0
            width_stride,
186
0
        }
187
0
    }
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
0
    pub fn strides_cwh(&self) -> (usize, usize, usize) {
195
0
        (self.channel_stride, self.width_stride, self.height_stride)
196
0
    }
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
0
    pub fn extents(&self) -> (usize, usize, usize) {
204
0
        (
205
0
            self.channels as usize,
206
0
            self.width as usize,
207
0
            self.height as usize,
208
0
        )
209
0
    }
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
0
    pub fn bounds(&self) -> (u8, u32, u32) {
217
0
        (self.channels, self.width, self.height)
218
0
    }
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
0
    pub fn min_length(&self) -> Option<usize> {
273
0
        if self.width == 0 || self.height == 0 || self.channels == 0 {
274
0
            return Some(0);
275
0
        }
276
0
277
0
        self.index(self.channels - 1, self.width - 1, self.height - 1)
278
0
            .and_then(|idx| idx.checked_add(1))
279
0
    }
280
281
    /// Check if a buffer of length `len` is large enough.
282
    #[must_use]
283
0
    pub fn fits(&self, len: usize) -> bool {
284
0
        self.min_length().is_some_and(|min| len >= min)
285
0
    }
286
287
    /// The extents of this array, in order of increasing strides.
288
0
    fn increasing_stride_dims(&self) -> [Dim; 3] {
289
0
        // Order extents by strides, then check that each is less equal than the next stride.
290
0
        let mut grouped: [Dim; 3] = [
291
0
            Dim(self.channel_stride, self.channels as usize),
292
0
            Dim(self.width_stride, self.width as usize),
293
0
            Dim(self.height_stride, self.height as usize),
294
0
        ];
295
0
296
0
        grouped.sort();
297
0
298
0
        let (min_dim, mid_dim, max_dim) = (grouped[0], grouped[1], grouped[2]);
299
0
        assert!(min_dim.stride() <= mid_dim.stride() && mid_dim.stride() <= max_dim.stride());
300
301
0
        grouped
302
0
    }
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
0
    pub fn has_aliased_samples(&self) -> bool {
311
0
        let grouped = self.increasing_stride_dims();
312
0
        let (min_dim, mid_dim, max_dim) = (grouped[0], grouped[1], grouped[2]);
313
314
0
        let min_size = match min_dim.checked_len() {
315
0
            None => return true,
316
0
            Some(size) => size,
317
        };
318
319
0
        let mid_size = match mid_dim.checked_len() {
320
0
            None => return true,
321
0
            Some(size) => size,
322
0
        };
323
0
324
0
        if max_dim.checked_len().is_none() {
325
0
            return true;
326
0
        };
327
0
328
0
        // Each higher dimension must walk over all of one lower dimension.
329
0
        min_size > mid_dim.stride() || mid_size > max_dim.stride()
330
0
    }
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
0
    pub fn is_normal(&self, form: NormalForm) -> bool {
341
0
        if self.has_aliased_samples() {
342
0
            return false;
343
0
        }
344
0
345
0
        if form >= NormalForm::PixelPacked && self.channel_stride != 1 {
346
0
            return false;
347
0
        }
348
0
349
0
        if form >= NormalForm::ImagePacked {
350
            // has aliased already checked for overflows.
351
0
            let grouped = self.increasing_stride_dims();
352
0
            let (min_dim, mid_dim, max_dim) = (grouped[0], grouped[1], grouped[2]);
353
0
354
0
            if 1 != min_dim.stride() {
355
0
                return false;
356
0
            }
357
0
358
0
            if min_dim.len() != mid_dim.stride() {
359
0
                return false;
360
0
            }
361
0
362
0
            if mid_dim.len() != max_dim.stride() {
363
0
                return false;
364
0
            }
365
0
        }
366
367
0
        if form >= NormalForm::RowMajorPacked {
368
0
            if self.width_stride != self.channels as usize {
369
0
                return false;
370
0
            }
371
0
372
0
            if self.width as usize * self.width_stride != self.height_stride {
373
0
                return false;
374
0
            }
375
0
        }
376
377
0
        if form >= NormalForm::ColumnMajorPacked {
378
0
            if self.height_stride != self.channels as usize {
379
0
                return false;
380
0
            }
381
0
382
0
            if self.height as usize * self.height_stride != self.width_stride {
383
0
                return false;
384
0
            }
385
0
        }
386
387
0
        true
388
0
    }
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
0
    pub fn in_bounds(&self, channel: u8, x: u32, y: u32) -> bool {
397
0
        channel < self.channels && x < self.width && y < self.height
398
0
    }
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
0
    pub fn index(&self, channel: u8, x: u32, y: u32) -> Option<usize> {
405
0
        if !self.in_bounds(channel, x, y) {
406
0
            return None;
407
0
        }
408
0
409
0
        self.index_ignoring_bounds(channel as usize, x as usize, y as usize)
410
0
    }
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
0
    pub fn index_ignoring_bounds(&self, channel: usize, x: usize, y: usize) -> Option<usize> {
419
0
        let idx_c = channel.checked_mul(self.channel_stride);
420
0
        let idx_x = x.checked_mul(self.width_stride);
421
0
        let idx_y = y.checked_mul(self.height_stride);
422
423
0
        let (Some(idx_c), Some(idx_x), Some(idx_y)) = (idx_c, idx_x, idx_y) else {
424
0
            return None;
425
        };
426
427
0
        Some(0usize)
428
0
            .and_then(|b| b.checked_add(idx_c))
429
0
            .and_then(|b| b.checked_add(idx_x))
430
0
            .and_then(|b| b.checked_add(idx_y))
431
0
    }
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
0
    pub fn in_bounds_index(&self, c: u8, x: u32, y: u32) -> usize {
443
0
        let (c_stride, x_stride, y_stride) = self.strides_cwh();
444
0
        (y as usize * y_stride) + (x as usize * x_stride) + (c as usize * c_stride)
445
0
    }
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
0
    pub fn shrink_to(&mut self, channels: u8, width: u32, height: u32) {
453
0
        self.channels = self.channels.min(channels);
454
0
        self.width = self.width.min(width);
455
0
        self.height = self.height.min(height);
456
0
    }
457
}
458
459
impl Dim {
460
0
    fn stride(self) -> usize {
461
0
        self.0
462
0
    }
463
464
    /// Length of this dimension in memory.
465
0
    fn checked_len(self) -> Option<usize> {
466
0
        self.0.checked_mul(self.1)
467
0
    }
468
469
0
    fn len(self) -> usize {
470
0
        self.0 * self.1
471
0
    }
472
}
473
474
impl<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
0
    pub fn strides_cwh(&self) -> (usize, usize, usize) {
480
0
        self.layout.strides_cwh()
481
0
    }
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
0
    pub fn extents(&self) -> (usize, usize, usize) {
488
0
        self.layout.extents()
489
0
    }
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
0
    pub fn bounds(&self) -> (u8, u32, u32) {
496
0
        self.layout.bounds()
497
0
    }
498
499
    /// Get a reference based version.
500
0
    pub fn as_ref<T>(&self) -> FlatSamples<&[T]>
501
0
    where
502
0
        Buffer: AsRef<[T]>,
503
0
    {
504
0
        FlatSamples {
505
0
            samples: self.samples.as_ref(),
506
0
            layout: self.layout,
507
0
            color_hint: self.color_hint,
508
0
        }
509
0
    }
510
511
    /// Get a mutable reference based version.
512
0
    pub fn as_mut<T>(&mut self) -> FlatSamples<&mut [T]>
513
0
    where
514
0
        Buffer: AsMut<[T]>,
515
0
    {
516
0
        FlatSamples {
517
0
            samples: self.samples.as_mut(),
518
0
            layout: self.layout,
519
0
            color_hint: self.color_hint,
520
0
        }
521
0
    }
522
523
    /// Copy the data into an owned vector.
524
0
    pub fn to_vec<T>(&self) -> FlatSamples<Vec<T>>
525
0
    where
526
0
        T: Clone,
527
0
        Buffer: AsRef<[T]>,
528
0
    {
529
0
        FlatSamples {
530
0
            samples: self.samples.as_ref().to_vec(),
531
0
            layout: self.layout,
532
0
            color_hint: self.color_hint,
533
0
        }
534
0
    }
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
0
    pub fn get_sample<T>(&self, channel: u8, x: u32, y: u32) -> Option<&T>
558
0
    where
559
0
        Buffer: AsRef<[T]>,
560
0
    {
561
0
        self.index(channel, x, y)
562
0
            .and_then(|idx| self.samples.as_ref().get(idx))
563
0
    }
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
0
    pub fn get_mut_sample<T>(&mut self, channel: u8, x: u32, y: u32) -> Option<&mut T>
592
0
    where
593
0
        Buffer: AsMut<[T]>,
594
0
    {
595
0
        match self.index(channel, x, y) {
596
0
            None => None,
597
0
            Some(idx) => self.samples.as_mut().get_mut(idx),
598
        }
599
0
    }
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
0
    pub fn as_view<P>(&self) -> Result<View<&[P::Subpixel], P>, Error>
608
0
    where
609
0
        P: Pixel,
610
0
        Buffer: AsRef<[P::Subpixel]>,
611
0
    {
612
0
        if self.layout.channels != P::CHANNEL_COUNT {
613
0
            return Err(Error::ChannelCountMismatch(
614
0
                self.layout.channels,
615
0
                P::CHANNEL_COUNT,
616
0
            ));
617
0
        }
618
0
619
0
        let as_ref = self.samples.as_ref();
620
0
        if !self.layout.fits(as_ref.len()) {
621
0
            return Err(Error::TooLarge);
622
0
        }
623
0
624
0
        Ok(View {
625
0
            inner: FlatSamples {
626
0
                samples: as_ref,
627
0
                layout: self.layout,
628
0
                color_hint: self.color_hint,
629
0
            },
630
0
            phantom: PhantomData,
631
0
        })
632
0
    }
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
0
    pub fn as_view_with_mut_samples<P>(&mut self) -> Result<View<&mut [P::Subpixel], P>, Error>
650
0
    where
651
0
        P: Pixel,
652
0
        Buffer: AsMut<[P::Subpixel]>,
653
0
    {
654
0
        if self.layout.channels != P::CHANNEL_COUNT {
655
0
            return Err(Error::ChannelCountMismatch(
656
0
                self.layout.channels,
657
0
                P::CHANNEL_COUNT,
658
0
            ));
659
0
        }
660
0
661
0
        let as_mut = self.samples.as_mut();
662
0
        if !self.layout.fits(as_mut.len()) {
663
0
            return Err(Error::TooLarge);
664
0
        }
665
0
666
0
        Ok(View {
667
0
            inner: FlatSamples {
668
0
                samples: as_mut,
669
0
                layout: self.layout,
670
0
                color_hint: self.color_hint,
671
0
            },
672
0
            phantom: PhantomData,
673
0
        })
674
0
    }
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
0
    pub fn as_view_mut<P>(&mut self) -> Result<ViewMut<&mut [P::Subpixel], P>, Error>
688
0
    where
689
0
        P: Pixel,
690
0
        Buffer: AsMut<[P::Subpixel]>,
691
0
    {
692
0
        if !self.layout.is_normal(NormalForm::PixelPacked) {
693
0
            return Err(Error::NormalFormRequired(NormalForm::PixelPacked));
694
0
        }
695
0
696
0
        if self.layout.channels != P::CHANNEL_COUNT {
697
0
            return Err(Error::ChannelCountMismatch(
698
0
                self.layout.channels,
699
0
                P::CHANNEL_COUNT,
700
0
            ));
701
0
        }
702
0
703
0
        let as_mut = self.samples.as_mut();
704
0
        if !self.layout.fits(as_mut.len()) {
705
0
            return Err(Error::TooLarge);
706
0
        }
707
0
708
0
        Ok(ViewMut {
709
0
            inner: FlatSamples {
710
0
                samples: as_mut,
711
0
                layout: self.layout,
712
0
                color_hint: self.color_hint,
713
0
            },
714
0
            phantom: PhantomData,
715
0
        })
716
0
    }
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
0
    pub fn as_slice<T>(&self) -> &[T]
723
0
    where
724
0
        Buffer: AsRef<[T]>,
725
0
    {
726
0
        self.samples.as_ref()
727
0
    }
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
0
    pub fn as_mut_slice<T>(&mut self) -> &mut [T]
734
0
    where
735
0
        Buffer: AsMut<[T]>,
736
0
    {
737
0
        self.samples.as_mut()
738
0
    }
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
0
    pub fn image_slice<T>(&self) -> Option<&[T]>
746
0
    where
747
0
        Buffer: AsRef<[T]>,
748
0
    {
749
0
        let min_length = self.min_length()?;
750
751
0
        let slice = self.samples.as_ref();
752
0
        if slice.len() < min_length {
753
0
            return None;
754
0
        }
755
0
756
0
        Some(&slice[..min_length])
757
0
    }
758
759
    /// Mutable portion of the buffer that holds sample values.
760
0
    pub fn image_mut_slice<T>(&mut self) -> Option<&mut [T]>
761
0
    where
762
0
        Buffer: AsMut<[T]>,
763
0
    {
764
0
        let min_length = self.min_length()?;
765
766
0
        let slice = self.samples.as_mut();
767
0
        if slice.len() < min_length {
768
0
            return None;
769
0
        }
770
0
771
0
        Some(&mut slice[..min_length])
772
0
    }
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
0
    pub fn try_into_buffer<P>(self) -> Result<ImageBuffer<P, Buffer>, (Error, Self)>
780
0
    where
781
0
        P: Pixel + 'static,
782
0
        P::Subpixel: 'static,
783
0
        Buffer: Deref<Target = [P::Subpixel]>,
784
0
    {
785
0
        if !self.is_normal(NormalForm::RowMajorPacked) {
786
0
            return Err((Error::NormalFormRequired(NormalForm::RowMajorPacked), self));
787
0
        }
788
0
789
0
        if self.layout.channels != P::CHANNEL_COUNT {
790
0
            return Err((
791
0
                Error::ChannelCountMismatch(self.layout.channels, P::CHANNEL_COUNT),
792
0
                self,
793
0
            ));
794
0
        }
795
0
796
0
        if !self.fits(self.samples.deref().len()) {
797
0
            return Err((Error::TooLarge, self));
798
0
        }
799
0
800
0
        Ok(
801
0
            ImageBuffer::from_raw(self.layout.width, self.layout.height, self.samples)
802
0
                .unwrap_or_else(|| {
803
0
                    panic!("Preconditions should have been ensured before conversion")
804
0
                }),
805
0
        )
806
0
    }
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
0
    pub fn min_length(&self) -> Option<usize> {
860
0
        self.layout.min_length()
861
0
    }
862
863
    /// Check if a buffer of length `len` is large enough.
864
0
    pub fn fits(&self, len: usize) -> bool {
865
0
        self.layout.fits(len)
866
0
    }
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
0
    pub fn has_aliased_samples(&self) -> bool {
874
0
        self.layout.has_aliased_samples()
875
0
    }
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
0
    pub fn is_normal(&self, form: NormalForm) -> bool {
885
0
        self.layout.is_normal(form)
886
0
    }
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
0
    pub fn in_bounds(&self, channel: u8, x: u32, y: u32) -> bool {
894
0
        self.layout.in_bounds(channel, x, y)
895
0
    }
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
0
    pub fn index(&self, channel: u8, x: u32, y: u32) -> Option<usize> {
901
0
        self.layout.index(channel, x, y)
902
0
    }
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
0
    pub fn index_ignoring_bounds(&self, channel: usize, x: usize, y: usize) -> Option<usize> {
910
0
        self.layout.index_ignoring_bounds(channel, x, y)
911
0
    }
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
0
    pub fn in_bounds_index(&self, channel: u8, x: u32, y: u32) -> usize {
919
0
        self.layout.in_bounds_index(channel, x, y)
920
0
    }
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
0
    pub fn shrink_to(&mut self, channels: u8, width: u32, height: u32) {
928
0
        self.layout.shrink_to(channels, width, height);
929
0
    }
930
}
931
932
impl<'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
0
    pub fn with_monocolor<P>(pixel: &'buf P, width: u32, height: u32) -> Self
954
0
    where
955
0
        P: Pixel<Subpixel = Subpixel>,
956
0
        Subpixel: crate::Primitive,
957
0
    {
958
0
        FlatSamples {
959
0
            samples: pixel.channels(),
960
0
            layout: SampleLayout {
961
0
                channels: P::CHANNEL_COUNT,
962
0
                channel_stride: 1,
963
0
                width,
964
0
                width_stride: 0,
965
0
                height,
966
0
                height_stride: 0,
967
0
            },
968
0
969
0
            // TODO this value is never set. It should be set in all places where the Pixel type implements PixelWithColorType
970
0
            color_hint: None,
971
0
        }
972
0
    }
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)]
989
pub struct View<Buffer, P: Pixel>
990
where
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)]
1011
pub struct ViewMut<Buffer, P: Pixel>
1012
where
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)]
1026
pub 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)]
1057
pub 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
1090
impl<Buffer, P: Pixel> View<Buffer, P>
1091
where
1092
    Buffer: AsRef<[P::Subpixel]>,
1093
{
1094
    /// Take out the sample buffer.
1095
    ///
1096
    /// Gives up the normalization invariants on the buffer format.
1097
0
    pub fn into_inner(self) -> FlatSamples<Buffer> {
1098
0
        self.inner
1099
0
    }
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
0
    pub fn flat(&self) -> &FlatSamples<Buffer> {
1108
0
        &self.inner
1109
0
    }
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
0
    pub fn samples(&self) -> &Buffer {
1116
0
        &self.inner.samples
1117
0
    }
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
0
    pub fn get_sample(&self, channel: u8, x: u32, y: u32) -> Option<&P::Subpixel> {
1124
0
        if !self.inner.in_bounds(channel, x, y) {
1125
0
            return None;
1126
0
        }
1127
0
1128
0
        let index = self.inner.in_bounds_index(channel, x, y);
1129
0
        // Should always be `Some(_)` but checking is more costly.
1130
0
        self.samples().as_ref().get(index)
1131
0
    }
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
0
    pub fn get_mut_sample(&mut self, channel: u8, x: u32, y: u32) -> Option<&mut P::Subpixel>
1142
0
    where
1143
0
        Buffer: AsMut<[P::Subpixel]>,
1144
0
    {
1145
0
        if !self.inner.in_bounds(channel, x, y) {
1146
0
            return None;
1147
0
        }
1148
0
1149
0
        let index = self.inner.in_bounds_index(channel, x, y);
1150
0
        // Should always be `Some(_)` but checking is more costly.
1151
0
        self.inner.samples.as_mut().get_mut(index)
1152
0
    }
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
0
    pub fn min_length(&self) -> usize {
1158
0
        self.inner.min_length().unwrap()
1159
0
    }
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
0
    pub fn image_slice(&self) -> &[P::Subpixel] {
1166
0
        &self.samples().as_ref()[..self.min_length()]
1167
0
    }
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
0
    pub fn image_mut_slice(&mut self) -> &mut [P::Subpixel]
1175
0
    where
1176
0
        Buffer: AsMut<[P::Subpixel]>,
1177
0
    {
1178
0
        let min_length = self.min_length();
1179
0
        &mut self.inner.samples.as_mut()[..min_length]
1180
0
    }
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
0
    pub fn shrink_to(&mut self, width: u32, height: u32) {
1188
0
        let channels = self.inner.layout.channels;
1189
0
        self.inner.shrink_to(channels, width, height);
1190
0
    }
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
0
    pub fn try_upgrade(self) -> Result<ViewMut<Buffer, P>, (Error, Self)>
1211
0
    where
1212
0
        Buffer: AsMut<[P::Subpixel]>,
1213
0
    {
1214
0
        if !self.inner.is_normal(NormalForm::PixelPacked) {
1215
0
            return Err((Error::NormalFormRequired(NormalForm::PixelPacked), self));
1216
0
        }
1217
0
1218
0
        // No length check or channel count check required, all the same.
1219
0
        Ok(ViewMut {
1220
0
            inner: self.inner,
1221
0
            phantom: PhantomData,
1222
0
        })
1223
0
    }
1224
}
1225
1226
impl<Buffer, P: Pixel> ViewMut<Buffer, P>
1227
where
1228
    Buffer: AsMut<[P::Subpixel]>,
1229
{
1230
    /// Take out the sample buffer.
1231
    ///
1232
    /// Gives up the normalization invariants on the buffer format.
1233
0
    pub fn into_inner(self) -> FlatSamples<Buffer> {
1234
0
        self.inner
1235
0
    }
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
0
    pub fn flat(&self) -> &FlatSamples<Buffer> {
1244
0
        &self.inner
1245
0
    }
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
0
    pub fn samples(&self) -> &Buffer {
1253
0
        &self.inner.samples
1254
0
    }
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
0
    pub fn min_length(&self) -> usize {
1260
0
        self.inner.min_length().unwrap()
1261
0
    }
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
0
    pub fn get_sample(&self, channel: u8, x: u32, y: u32) -> Option<&P::Subpixel>
1268
0
    where
1269
0
        Buffer: AsRef<[P::Subpixel]>,
1270
0
    {
1271
0
        if !self.inner.in_bounds(channel, x, y) {
1272
0
            return None;
1273
0
        }
1274
0
1275
0
        let index = self.inner.in_bounds_index(channel, x, y);
1276
0
        // Should always be `Some(_)` but checking is more costly.
1277
0
        self.samples().as_ref().get(index)
1278
0
    }
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
0
    pub fn get_mut_sample(&mut self, channel: u8, x: u32, y: u32) -> Option<&mut P::Subpixel> {
1285
0
        if !self.inner.in_bounds(channel, x, y) {
1286
0
            return None;
1287
0
        }
1288
0
1289
0
        let index = self.inner.in_bounds_index(channel, x, y);
1290
0
        // Should always be `Some(_)` but checking is more costly.
1291
0
        self.inner.samples.as_mut().get_mut(index)
1292
0
    }
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
0
    pub fn image_slice(&self) -> &[P::Subpixel]
1299
0
    where
1300
0
        Buffer: AsRef<[P::Subpixel]>,
1301
0
    {
1302
0
        &self.inner.samples.as_ref()[..self.min_length()]
1303
0
    }
1304
1305
    /// Return the mutable buffer that holds sample values.
1306
0
    pub fn image_mut_slice(&mut self) -> &mut [P::Subpixel] {
1307
0
        let length = self.min_length();
1308
0
        &mut self.inner.samples.as_mut()[..length]
1309
0
    }
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
0
    pub fn shrink_to(&mut self, width: u32, height: u32) {
1317
0
        let channels = self.inner.layout.channels;
1318
0
        self.inner.shrink_to(channels, width, height);
1319
0
    }
1320
}
1321
1322
// The out-of-bounds panic for single sample access similar to `slice::index`.
1323
#[inline(never)]
1324
#[cold]
1325
0
fn panic_cwh_out_of_bounds(
1326
0
    (c, x, y): (u8, u32, u32),
1327
0
    bounds: (u8, u32, u32),
1328
0
    strides: (usize, usize, usize),
1329
0
) -> ! {
1330
0
    panic!(
1331
0
        "Sample coordinates {:?} out of sample matrix bounds {:?} with strides {:?}",
1332
0
        (c, x, y),
1333
0
        bounds,
1334
0
        strides
1335
0
    )
1336
}
1337
1338
// The out-of-bounds panic for pixel access similar to `slice::index`.
1339
#[inline(never)]
1340
#[cold]
1341
0
fn panic_pixel_out_of_bounds((x, y): (u32, u32), bounds: (u32, u32)) -> ! {
1342
0
    panic!("Image index {:?} out of bounds {:?}", (x, y), bounds)
1343
}
1344
1345
impl<Buffer> Index<(u8, u32, u32)> for FlatSamples<Buffer>
1346
where
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
0
    fn index(&self, (c, x, y): (u8, u32, u32)) -> &Self::Output {
1357
0
        let bounds = self.bounds();
1358
0
        let strides = self.strides_cwh();
1359
0
        let index = self
1360
0
            .index(c, x, y)
1361
0
            .unwrap_or_else(|| panic_cwh_out_of_bounds((c, x, y), bounds, strides));
1362
0
        &self.samples[index]
1363
0
    }
1364
}
1365
1366
impl<Buffer> IndexMut<(u8, u32, u32)> for FlatSamples<Buffer>
1367
where
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
0
    fn index_mut(&mut self, (c, x, y): (u8, u32, u32)) -> &mut Self::Output {
1376
0
        let bounds = self.bounds();
1377
0
        let strides = self.strides_cwh();
1378
0
        let index = self
1379
0
            .index(c, x, y)
1380
0
            .unwrap_or_else(|| panic_cwh_out_of_bounds((c, x, y), bounds, strides));
1381
0
        &mut self.samples[index]
1382
0
    }
1383
}
1384
1385
impl<Buffer, P: Pixel> GenericImageView for View<Buffer, P>
1386
where
1387
    Buffer: AsRef<[P::Subpixel]>,
1388
{
1389
    type Pixel = P;
1390
1391
0
    fn dimensions(&self) -> (u32, u32) {
1392
0
        (self.inner.layout.width, self.inner.layout.height)
1393
0
    }
1394
1395
0
    fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
1396
0
        if !self.inner.in_bounds(0, x, y) {
1397
0
            panic_pixel_out_of_bounds((x, y), self.dimensions())
1398
0
        }
1399
0
1400
0
        let image = self.inner.samples.as_ref();
1401
0
        let base_index = self.inner.in_bounds_index(0, x, y);
1402
0
        let channels = P::CHANNEL_COUNT as usize;
1403
0
1404
0
        let mut buffer = [Zero::zero(); 256];
1405
0
        buffer
1406
0
            .iter_mut()
1407
0
            .enumerate()
1408
0
            .take(channels)
1409
0
            .for_each(|(c, to)| {
1410
0
                let index = base_index + c * self.inner.layout.channel_stride;
1411
0
                *to = image[index];
1412
0
            });
1413
0
1414
0
        *P::from_slice(&buffer[..channels])
1415
0
    }
1416
}
1417
1418
impl<Buffer, P: Pixel> GenericImageView for ViewMut<Buffer, P>
1419
where
1420
    Buffer: AsMut<[P::Subpixel]> + AsRef<[P::Subpixel]>,
1421
{
1422
    type Pixel = P;
1423
1424
0
    fn dimensions(&self) -> (u32, u32) {
1425
0
        (self.inner.layout.width, self.inner.layout.height)
1426
0
    }
1427
1428
0
    fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
1429
0
        if !self.inner.in_bounds(0, x, y) {
1430
0
            panic_pixel_out_of_bounds((x, y), self.dimensions())
1431
0
        }
1432
0
1433
0
        let image = self.inner.samples.as_ref();
1434
0
        let base_index = self.inner.in_bounds_index(0, x, y);
1435
0
        let channels = P::CHANNEL_COUNT as usize;
1436
0
1437
0
        let mut buffer = [Zero::zero(); 256];
1438
0
        buffer
1439
0
            .iter_mut()
1440
0
            .enumerate()
1441
0
            .take(channels)
1442
0
            .for_each(|(c, to)| {
1443
0
                let index = base_index + c * self.inner.layout.channel_stride;
1444
0
                *to = image[index];
1445
0
            });
1446
0
1447
0
        *P::from_slice(&buffer[..channels])
1448
0
    }
1449
}
1450
1451
impl<Buffer, P: Pixel> GenericImage for ViewMut<Buffer, P>
1452
where
1453
    Buffer: AsMut<[P::Subpixel]> + AsRef<[P::Subpixel]>,
1454
{
1455
0
    fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut Self::Pixel {
1456
0
        if !self.inner.in_bounds(0, x, y) {
1457
0
            panic_pixel_out_of_bounds((x, y), self.dimensions())
1458
0
        }
1459
0
1460
0
        let base_index = self.inner.in_bounds_index(0, x, y);
1461
0
        let channel_count = <P as Pixel>::CHANNEL_COUNT as usize;
1462
0
        let pixel_range = base_index..base_index + channel_count;
1463
0
        P::from_slice_mut(&mut self.inner.samples.as_mut()[pixel_range])
1464
0
    }
1465
1466
    #[allow(deprecated)]
1467
0
    fn put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
1468
0
        *self.get_pixel_mut(x, y) = pixel;
1469
0
    }
1470
1471
    #[allow(deprecated)]
1472
0
    fn blend_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
1473
0
        self.get_pixel_mut(x, y).blend(&pixel);
1474
0
    }
1475
}
1476
1477
impl From<Error> for ImageError {
1478
0
    fn from(error: Error) -> ImageError {
1479
        #[derive(Debug)]
1480
        struct NormalFormRequiredError(NormalForm);
1481
        impl fmt::Display for NormalFormRequiredError {
1482
0
            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1483
0
                write!(f, "Required sample buffer in normal form {:?}", self.0)
1484
0
            }
1485
        }
1486
        impl error::Error for NormalFormRequiredError {}
1487
1488
0
        match error {
1489
0
            Error::TooLarge => ImageError::Parameter(ParameterError::from_kind(
1490
0
                ParameterErrorKind::DimensionMismatch,
1491
0
            )),
1492
0
            Error::NormalFormRequired(form) => ImageError::Decoding(DecodingError::new(
1493
0
                ImageFormatHint::Unknown,
1494
0
                NormalFormRequiredError(form),
1495
0
            )),
1496
0
            Error::ChannelCountMismatch(_lc, _pc) => ImageError::Parameter(
1497
0
                ParameterError::from_kind(ParameterErrorKind::DimensionMismatch),
1498
0
            ),
1499
0
            Error::WrongColor(color) => {
1500
0
                ImageError::Unsupported(UnsupportedError::from_format_and_kind(
1501
0
                    ImageFormatHint::Unknown,
1502
0
                    UnsupportedErrorKind::Color(color.into()),
1503
0
                ))
1504
            }
1505
        }
1506
0
    }
1507
}
1508
1509
impl fmt::Display for Error {
1510
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1511
0
        match self {
1512
0
            Error::TooLarge => write!(f, "The layout is too large"),
1513
0
            Error::NormalFormRequired(form) => write!(
1514
0
                f,
1515
0
                "The layout needs to {}",
1516
0
                match form {
1517
0
                    NormalForm::ColumnMajorPacked => "be packed and in column major form",
1518
0
                    NormalForm::ImagePacked => "be fully packed",
1519
0
                    NormalForm::PixelPacked => "have packed pixels",
1520
0
                    NormalForm::RowMajorPacked => "be packed and in row major form",
1521
0
                    NormalForm::Unaliased => "not have any aliasing channels",
1522
                }
1523
            ),
1524
0
            Error::ChannelCountMismatch(layout_channels, pixel_channels) => {
1525
0
                write!(f, "The channel count of the chosen pixel (={pixel_channels}) does agree with the layout (={layout_channels})")
1526
            }
1527
0
            Error::WrongColor(color) => {
1528
0
                write!(f, "The chosen color type does not match the hint {color:?}")
1529
            }
1530
        }
1531
0
    }
1532
}
1533
1534
impl error::Error for Error {}
1535
1536
impl PartialOrd for NormalForm {
1537
    /// Compares the logical preconditions.
1538
    ///
1539
    /// `a < b` if the normal form `a` has less preconditions than `b`.
1540
0
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
1541
0
        match (*self, *other) {
1542
0
            (NormalForm::Unaliased, NormalForm::Unaliased) => Some(cmp::Ordering::Equal),
1543
0
            (NormalForm::PixelPacked, NormalForm::PixelPacked) => Some(cmp::Ordering::Equal),
1544
0
            (NormalForm::ImagePacked, NormalForm::ImagePacked) => Some(cmp::Ordering::Equal),
1545
0
            (NormalForm::RowMajorPacked, NormalForm::RowMajorPacked) => Some(cmp::Ordering::Equal),
1546
            (NormalForm::ColumnMajorPacked, NormalForm::ColumnMajorPacked) => {
1547
0
                Some(cmp::Ordering::Equal)
1548
            }
1549
1550
0
            (NormalForm::Unaliased, _) => Some(cmp::Ordering::Less),
1551
0
            (_, NormalForm::Unaliased) => Some(cmp::Ordering::Greater),
1552
1553
0
            (NormalForm::PixelPacked, NormalForm::ColumnMajorPacked) => Some(cmp::Ordering::Less),
1554
0
            (NormalForm::PixelPacked, NormalForm::RowMajorPacked) => Some(cmp::Ordering::Less),
1555
0
            (NormalForm::RowMajorPacked, NormalForm::PixelPacked) => Some(cmp::Ordering::Greater),
1556
            (NormalForm::ColumnMajorPacked, NormalForm::PixelPacked) => {
1557
0
                Some(cmp::Ordering::Greater)
1558
            }
1559
1560
0
            (NormalForm::ImagePacked, NormalForm::ColumnMajorPacked) => Some(cmp::Ordering::Less),
1561
0
            (NormalForm::ImagePacked, NormalForm::RowMajorPacked) => Some(cmp::Ordering::Less),
1562
0
            (NormalForm::RowMajorPacked, NormalForm::ImagePacked) => Some(cmp::Ordering::Greater),
1563
            (NormalForm::ColumnMajorPacked, NormalForm::ImagePacked) => {
1564
0
                Some(cmp::Ordering::Greater)
1565
            }
1566
1567
0
            (NormalForm::ImagePacked, NormalForm::PixelPacked) => None,
1568
0
            (NormalForm::PixelPacked, NormalForm::ImagePacked) => None,
1569
0
            (NormalForm::RowMajorPacked, NormalForm::ColumnMajorPacked) => None,
1570
0
            (NormalForm::ColumnMajorPacked, NormalForm::RowMajorPacked) => None,
1571
        }
1572
0
    }
1573
}
1574
1575
#[cfg(test)]
1576
mod 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
}