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