/rust/registry/src/index.crates.io-1949cf8c6b5b557f/imgref-1.12.1/src/lib.rs
Line | Count | Source |
1 | | //! In graphics code it's very common to pass `width` and `height` along with a `Vec` of pixels, |
2 | | //! all as separate arguments. This is tedious, and can lead to errors. |
3 | | //! |
4 | | //! This crate is a simple struct that adds dimensions to the underlying buffer. This makes it easier to correctly keep track |
5 | | //! of the image size and allows passing images with just one function argument instead three or four. |
6 | | //! |
7 | | //! Additionally, it has a concept of a `stride`, which allows defining sub-regions of images without copying, |
8 | | //! as well as handling padding (e.g. buffers for video frames may require to be a multiple of 8, regardless of logical image size). |
9 | | //! |
10 | | //! For convenience, there are iterators over rows or all pixels of a (sub)image and |
11 | | //! pixel-based indexing directly with `img[(x,y)]` (where `x`/`y` can be `u32` as well as `usize`). |
12 | | //! |
13 | | //! `Img<Container>` type has aliases for common uses: |
14 | | //! |
15 | | //! * Owned: `ImgVec<T>` → `Img<Vec<T>>` (use it in `struct`s and return types) |
16 | | //! * Reference: `ImgRef<T>` → `Img<&[T]>` (use it in function arguments) |
17 | | //! * Mutable reference: `ImgRefMut<T>` → `Img<&mut [T]>` |
18 | | //! |
19 | | //! It is assumed that the container is [one element per pixel](https://crates.io/crates/rgb/), e.g. `Vec<RGBA>`, |
20 | | //! and _not_ a `Vec<u8>` where 4 `u8` elements are interpreted as one pixel. |
21 | | //! |
22 | | //! |
23 | | //! ```rust |
24 | | //! use imgref::*; |
25 | | //! # fn some_image_processing_function(img: ImgRef<u8>) -> ImgVec<u8> { img.new_buf(img.buf().to_vec()) } |
26 | | //! |
27 | | //! let img = Img::new(vec![0; 1000], 50, 20); // 1000 pixels of a 50×20 image |
28 | | //! |
29 | | //! let new_image = some_image_processing_function(img.as_ref()); // Use imgvec.as_ref() instead of &imgvec for better efficiency |
30 | | //! |
31 | | //! println!("New size is {}×{}", new_image.width(), new_image.height()); |
32 | | //! println!("And the top left pixel is {:?}", new_image[(0u32,0u32)]); |
33 | | //! |
34 | | //! let first_row_slice = &new_image[0]; |
35 | | //! |
36 | | //! for row in new_image.rows() { |
37 | | //! // … |
38 | | //! } |
39 | | //! for px in new_image.pixels() { |
40 | | //! // … |
41 | | //! } |
42 | | //! |
43 | | //! // slice (x, y, width, height) by reference - no copy! |
44 | | //! let fragment = img.sub_image(5, 5, 15, 15); |
45 | | //! |
46 | | //! let (vec, width, height) = fragment.to_contiguous_buf(); |
47 | | //! ``` |
48 | | |
49 | | #![no_std] |
50 | | |
51 | | extern crate alloc; |
52 | | #[cfg(test)] |
53 | | extern crate std; |
54 | | |
55 | | use alloc::borrow::{Cow, ToOwned}; |
56 | | use alloc::vec::Vec; |
57 | | use core::slice; |
58 | | |
59 | | mod traits; |
60 | | |
61 | | mod iter; |
62 | | mod ops; |
63 | | pub use iter::*; |
64 | | |
65 | | /// Image owning its pixels. |
66 | | /// |
67 | | /// A 2D array of pixels. The pixels are oriented top-left first and rows are `stride` pixels wide. |
68 | | /// |
69 | | /// If size of the `buf` is larger than `width`*`height`, then any excess space is a padding (see `width_padded()`/`height_padded()`). |
70 | | pub type ImgVec<Pixel> = Img<Vec<Pixel>>; |
71 | | |
72 | | /// Reference to pixels inside another image. |
73 | | /// Pass this structure by value (i.e. `ImgRef`, not `&ImgRef`). |
74 | | /// |
75 | | /// Only `width` of pixels of every `stride` can be modified. The `buf` may be longer than `height`*`stride`, but the extra space should be ignored. |
76 | | pub type ImgRef<'slice, Pixel> = Img<&'slice [Pixel]>; |
77 | | |
78 | | /// Same as `ImgRef`, but mutable |
79 | | /// Pass this structure by value (i.e. `ImgRefMut`, not `&ImgRefMut`). This type isn't `Copy`, but [`.as_mut()`](ImgRefMut::as_mut) can reborrow it. |
80 | | /// |
81 | | pub type ImgRefMut<'slice, Pixel> = Img<&'slice mut [Pixel]>; |
82 | | |
83 | | /// Additional methods that depend on buffer size |
84 | | /// |
85 | | /// To use these methods you need: |
86 | | /// |
87 | | /// ```rust |
88 | | /// use imgref::*; |
89 | | /// ``` |
90 | | pub trait ImgExt<Pixel> { |
91 | | /// Maximum possible width of the data, including the stride. |
92 | | /// |
93 | | /// # Panics |
94 | | /// |
95 | | /// This method may panic if the underlying buffer is not at least `height()*stride()` pixels large. |
96 | | #[cfg(feature = "deprecated")] |
97 | | fn width_padded(&self) -> usize; |
98 | | |
99 | | /// Height in number of full strides. |
100 | | /// If the underlying buffer is not an even multiple of strides, the last row is ignored. |
101 | | /// |
102 | | /// # Panics |
103 | | /// |
104 | | /// This method may panic if the underlying buffer is not at least `height()*stride()` pixels large. |
105 | | #[cfg(feature = "deprecated")] |
106 | | fn height_padded(&self) -> usize; |
107 | | |
108 | | /// Iterate over the entire buffer as rows, including all padding |
109 | | /// |
110 | | /// Rows will have up to `stride` width, but the last row may be shorter. |
111 | | #[cfg(feature = "deprecated")] |
112 | | fn rows_padded(&self) -> slice::Chunks<'_, Pixel>; |
113 | | |
114 | | /// Borrow the container |
115 | | fn as_ref(&self) -> ImgRef<'_, Pixel>; |
116 | | } |
117 | | |
118 | | /// Additional methods that depend on buffer size |
119 | | /// |
120 | | /// To use these methods you need: |
121 | | /// |
122 | | /// ```rust |
123 | | /// use imgref::*; |
124 | | /// ``` |
125 | | pub trait ImgExtMut<Pixel> { |
126 | | /// Iterate over the entire buffer as rows, including all padding |
127 | | /// |
128 | | /// Rows will have up to `stride` width, but the last row may be shorter. |
129 | | #[cfg(feature = "deprecated")] |
130 | | fn rows_padded_mut(&mut self) -> slice::ChunksMut<'_, Pixel>; |
131 | | |
132 | | /// Borrow the container mutably |
133 | | fn as_mut(&mut self) -> ImgRefMut<'_, Pixel>; |
134 | | } |
135 | | |
136 | | /// Basic struct used for both owned (alias `ImgVec`) and borrowed (alias `ImgRef`) image fragments. |
137 | | /// |
138 | | /// Note: the fields are `pub` only because of borrow checker limitations. Please consider them as read-only. |
139 | | #[derive(Debug, Copy, Clone)] |
140 | | pub struct Img<Container> { |
141 | | /// Storage for the pixels. Usually `Vec<Pixel>` or `&[Pixel]`. See `ImgVec` and `ImgRef`. |
142 | | /// |
143 | | /// Note that future version will make this field private. Use `.rows()` and `.pixels()` iterators where possible, or `buf()`/`buf_mut()`/`into_buf()`. |
144 | | #[deprecated(note = "Don't access struct fields directly. Use buf(), buf_mut() or into_buf()")] |
145 | | #[cfg(feature = "deprecated")] |
146 | | pub buf: Container, |
147 | | |
148 | | #[cfg(not(feature = "deprecated"))] |
149 | | buf: Container, |
150 | | |
151 | | /// Number of pixels to skip in the container to advance to the next row. |
152 | | /// |
153 | | /// Note: pixels between `width` and `stride` may not be usable, and may not even exist in the last row. |
154 | | #[deprecated(note = "Don't access struct fields directly. Use stride()")] |
155 | | #[cfg(feature = "deprecated")] |
156 | | pub stride: usize, |
157 | | |
158 | | #[cfg(not(feature = "deprecated"))] |
159 | | stride: usize, |
160 | | |
161 | | /// Width of the image in pixels. |
162 | | /// |
163 | | /// Note that this isn't same as the width of the row in the `buf`, see `stride` |
164 | | #[deprecated(note = "Don't access struct fields directly. Use width()")] |
165 | | #[cfg(feature = "deprecated")] |
166 | | pub width: u32, |
167 | | |
168 | | #[cfg(not(feature = "deprecated"))] |
169 | | width: u32, |
170 | | |
171 | | /// Height of the image in pixels. |
172 | | #[deprecated(note = "Don't access struct fields directly. Use height()")] |
173 | | #[cfg(feature = "deprecated")] |
174 | | pub height: u32, |
175 | | |
176 | | #[cfg(not(feature = "deprecated"))] |
177 | | height: u32, |
178 | | } |
179 | | |
180 | | impl<Container> Img<Container> { |
181 | | /// Width of the image in pixels. |
182 | | /// |
183 | | /// Note that this isn't same as the width of the row in image data, see [`stride()`](Self::stride) |
184 | | #[inline(always)] |
185 | | #[allow(deprecated)] |
186 | 0 | pub const fn width(&self) -> usize { self.width as usize }Unexecuted instantiation: <imgref::Img<alloc::vec::Vec<rgb::formats::rgba::Rgba<u8>>>>::width Unexecuted instantiation: <imgref::Img<&[rgb::formats::rgba::Rgba<u8>]>>::width Unexecuted instantiation: <imgref::Img<_>>::width Unexecuted instantiation: <imgref::Img<&[rgb::formats::rgb::Rgb<u8>]>>::width |
187 | | |
188 | | /// Height of the image in pixels. |
189 | | #[inline(always)] |
190 | | #[allow(deprecated)] |
191 | 0 | pub const fn height(&self) -> usize { self.height as usize }Unexecuted instantiation: <imgref::Img<alloc::vec::Vec<rgb::formats::rgba::Rgba<u8>>>>::height Unexecuted instantiation: <imgref::Img<&[rgb::formats::rgba::Rgba<u8>]>>::height Unexecuted instantiation: <imgref::Img<_>>::height Unexecuted instantiation: <imgref::Img<&[rgb::formats::rgb::Rgb<u8>]>>::height |
192 | | |
193 | | /// Number of _pixels_ to skip in the container to advance to the next row. |
194 | | /// |
195 | | /// Must be >= `width` and can't be 0. |
196 | | /// |
197 | | /// Note the last row may have fewer pixels than the stride. |
198 | | /// |
199 | | /// Some APIs use number of bytes for a stride, but this stride is in pixels. |
200 | | #[inline(always)] |
201 | | #[allow(deprecated)] |
202 | 0 | pub const fn stride(&self) -> usize { self.stride }Unexecuted instantiation: <imgref::Img<alloc::vec::Vec<rgb::formats::rgba::Rgba<u8>>>>::stride Unexecuted instantiation: <imgref::Img<&[rgb::formats::rgba::Rgba<u8>]>>::stride Unexecuted instantiation: <imgref::Img<_>>::stride Unexecuted instantiation: <imgref::Img<&[rgb::formats::rgb::Rgb<u8>]>>::stride |
203 | | |
204 | | /// Immutable reference to the pixel storage. Warning: exposes stride. Use [`pixels()`](Self::pixels) or [`rows()`](Self::rows) instead. |
205 | | /// |
206 | | /// See also [`into_contiguous_buf()`](Self::into_contiguous_buf). |
207 | | #[inline(always)] |
208 | | #[allow(deprecated)] |
209 | 0 | pub const fn buf(&self) -> &Container { &self.buf }Unexecuted instantiation: <imgref::Img<alloc::vec::Vec<rgb::formats::rgba::Rgba<u8>>>>::buf Unexecuted instantiation: <imgref::Img<&[rgb::formats::rgba::Rgba<u8>]>>::buf Unexecuted instantiation: <imgref::Img<_>>::buf Unexecuted instantiation: <imgref::Img<&[rgb::formats::rgb::Rgb<u8>]>>::buf |
210 | | |
211 | | /// Mutable reference to the pixel storage. Warning: exposes stride. Use [`pixels_mut()`](Self::pixels_mut) or [`rows_mut()`](Self::rows_mut) instead. |
212 | | /// |
213 | | /// See also [`into_contiguous_buf()`](Self::into_contiguous_buf). |
214 | | #[inline(always)] |
215 | | #[allow(deprecated)] |
216 | 0 | pub fn buf_mut(&mut self) -> &mut Container { &mut self.buf } |
217 | | |
218 | | /// Get the pixel storage by consuming the image. Be careful about stride — see [`into_contiguous_buf()`](Self::into_contiguous_buf) for a safe version. |
219 | | #[inline(always)] |
220 | | #[allow(deprecated)] |
221 | 0 | pub fn into_buf(self) -> Container { self.buf } |
222 | | } |
223 | | |
224 | | impl<Pixel,Container> ImgExt<Pixel> for Img<Container> where Container: AsRef<[Pixel]> { |
225 | | #[inline(always)] |
226 | | #[cfg(feature = "deprecated")] |
227 | 0 | fn width_padded(&self) -> usize { |
228 | 0 | self.stride() |
229 | 0 | } |
230 | | |
231 | | #[inline(always)] |
232 | | #[cfg(feature = "deprecated")] |
233 | 0 | fn height_padded(&self) -> usize { |
234 | 0 | let len = self.buf().as_ref().len(); |
235 | 0 | assert_eq!(0, len % self.stride()); |
236 | 0 | len / self.stride() |
237 | 0 | } |
238 | | |
239 | | /// Iterate over the entire buffer as rows, including all padding |
240 | | /// |
241 | | /// Rows will have up to `stride` width, but the last row may be shorter. |
242 | | #[inline(always)] |
243 | | #[cfg(feature = "deprecated")] |
244 | 0 | fn rows_padded(&self) -> slice::Chunks<'_, Pixel> { |
245 | 0 | self.buf().as_ref().chunks(self.stride()) |
246 | 0 | } |
247 | | |
248 | | #[inline(always)] |
249 | | #[allow(deprecated)] |
250 | 0 | fn as_ref(&self) -> ImgRef<'_, Pixel> { |
251 | 0 | Img { |
252 | 0 | buf: self.buf.as_ref(), |
253 | 0 | width: self.width, |
254 | 0 | height: self.height, |
255 | 0 | stride: self.stride, |
256 | 0 | } |
257 | 0 | } |
258 | | } |
259 | | |
260 | | impl<Pixel,Container> ImgExtMut<Pixel> for Img<Container> where Container: AsMut<[Pixel]> { |
261 | | /// Iterate over the entire buffer as rows, including all padding |
262 | | /// |
263 | | /// Rows will have up to `stride` width, but the last row may be shorter. |
264 | | /// |
265 | | /// # Panics |
266 | | /// |
267 | | /// If stride is 0 |
268 | | #[cfg(feature = "deprecated")] |
269 | 0 | fn rows_padded_mut(&mut self) -> slice::ChunksMut<'_, Pixel> { |
270 | 0 | let stride = self.stride(); |
271 | 0 | self.buf_mut().as_mut().chunks_mut(stride) |
272 | 0 | } |
273 | | |
274 | | #[inline(always)] |
275 | | #[allow(deprecated)] |
276 | 0 | fn as_mut(&mut self) -> ImgRefMut<'_, Pixel> { |
277 | 0 | Img { |
278 | 0 | buf: self.buf.as_mut(), |
279 | 0 | width: self.width, |
280 | 0 | height: self.height, |
281 | 0 | stride: self.stride, |
282 | 0 | } |
283 | 0 | } |
284 | | } |
285 | | |
286 | | #[inline] |
287 | 0 | fn sub_image(left: usize, top: usize, width: usize, height: usize, stride: usize, buf_len: usize) -> (usize, usize, usize) { |
288 | 0 | let start = stride * top + left; |
289 | 0 | let full_strides_end = start + stride * height; |
290 | | // when left > 0 and height is full, the last line is shorter than the stride |
291 | 0 | let end = if buf_len >= full_strides_end { |
292 | 0 | full_strides_end |
293 | | } else { |
294 | 0 | debug_assert!(height > 0); |
295 | 0 | let min_strides_len = full_strides_end + width - stride; |
296 | 0 | debug_assert!(buf_len >= min_strides_len, "the buffer is too small to fit the subimage"); |
297 | | // if can't use full buffer, then shrink to min required (last line having exact width) |
298 | 0 | min_strides_len |
299 | | }; |
300 | 0 | (start, end, stride) |
301 | 0 | } |
302 | | |
303 | | impl<'slice, T> ImgRef<'slice, T> { |
304 | | /// Make a reference for a part of the image, without copying any pixels. |
305 | | /// |
306 | | /// # Panics |
307 | | /// |
308 | | /// It will panic if `sub_image` is outside of the image area |
309 | | /// (left + width must be <= container width, etc.) |
310 | | #[inline] |
311 | | #[must_use] |
312 | | #[track_caller] |
313 | 0 | pub fn sub_image(&self, left: usize, top: usize, width: usize, height: usize) -> Self { |
314 | 0 | assert!(top + height <= self.height()); |
315 | 0 | assert!(left + width <= self.width()); |
316 | 0 | let (start, end, stride) = sub_image(left, top, width, height, self.stride(), self.buf().len()); |
317 | 0 | let buf = &self.buf()[start..end]; |
318 | 0 | Self::new_stride(buf, width, height, stride) |
319 | 0 | } |
320 | | |
321 | | #[inline] |
322 | | /// Iterate over whole rows of pixels as slices |
323 | | /// |
324 | | /// # Panics |
325 | | /// |
326 | | /// If stride is 0 |
327 | | /// |
328 | | /// See also `pixels()` |
329 | | #[cfg_attr(debug_assertions, track_caller)] |
330 | 0 | pub fn rows(&self) -> RowsIter<'slice, T> { |
331 | 0 | RowsIter { |
332 | 0 | inner: self.valid_buf().chunks(self.stride()), |
333 | 0 | width: self.width(), |
334 | 0 | } |
335 | 0 | } |
336 | | |
337 | | /// Deprecated |
338 | | /// |
339 | | /// Note: it iterates **all** pixels in the underlying buffer, not just limited by width/height. |
340 | | #[deprecated(note = "Size of this buffer is unpredictable. Use .rows() instead")] |
341 | | #[cfg(feature = "deprecated")] |
342 | | #[doc(hidden)] |
343 | 0 | pub fn iter(&self) -> slice::Iter<'slice, T> { |
344 | 0 | self.buf().iter() |
345 | 0 | } |
346 | | } |
347 | | |
348 | | impl<'a, T: Clone> ImgRef<'a, T> { |
349 | | /// Returns a reference to the buffer, width, height. Guarantees that the buffer is contiguous, |
350 | | /// i.e. it's `width*height` elements long, and `[x + y*width]` addresses each pixel. |
351 | | /// |
352 | | /// It will create a copy if the buffer isn't contiguous (width != stride). |
353 | | /// For a more efficient version, see `into_contiguous_buf()` |
354 | | #[allow(deprecated)] |
355 | | #[must_use] |
356 | 0 | pub fn to_contiguous_buf(&self) -> (Cow<'a, [T]>, usize, usize) { |
357 | 0 | let width = self.width(); |
358 | 0 | let height = self.height(); |
359 | 0 | let stride = self.stride(); |
360 | 0 | if width == stride { |
361 | 0 | return (Cow::Borrowed(self.buf), width, height); |
362 | 0 | } |
363 | 0 | let mut buf = Vec::with_capacity(width * height); |
364 | 0 | for row in self.rows() { |
365 | 0 | buf.extend_from_slice(row); |
366 | 0 | } |
367 | 0 | (Cow::Owned(buf), width, height) |
368 | 0 | } |
369 | | } |
370 | | |
371 | | impl<'slice, T> ImgRefMut<'slice, T> { |
372 | | /// Turn this into immutable reference, and slice a subregion of it |
373 | | #[inline] |
374 | | #[allow(deprecated)] |
375 | | #[must_use] |
376 | 0 | pub fn sub_image(&'slice self, left: usize, top: usize, width: usize, height: usize) -> ImgRef<'slice, T> { |
377 | 0 | self.as_ref().sub_image(left, top, width, height) |
378 | 0 | } |
379 | | |
380 | | /// Slices this image reference to produce another reference to a subregion of it. |
381 | | /// |
382 | | /// Note that mutable borrows are exclusive, so it's not possible to have more than |
383 | | /// one mutable subimage at a time. |
384 | | /// |
385 | | /// ## Panics |
386 | | /// |
387 | | /// If the coordinates are out of bounds |
388 | | #[inline] |
389 | | #[allow(deprecated)] |
390 | | #[must_use] |
391 | | #[track_caller] |
392 | 0 | pub fn sub_image_mut(&mut self, left: usize, top: usize, width: usize, height: usize) -> ImgRefMut<'_, T> { |
393 | 0 | assert!(top + height <= self.height()); |
394 | 0 | assert!(left + width <= self.width()); |
395 | 0 | let (start, end, stride) = sub_image(left, top, width, height, self.stride(), self.buf.len()); |
396 | 0 | let buf = &mut self.buf[start..end]; |
397 | 0 | ImgRefMut::new_stride(buf, width, height, stride) |
398 | 0 | } |
399 | | |
400 | | /// Transforms this image reference to refer to a subregion. |
401 | | /// |
402 | | /// This is identical in behavior to [`ImgRefMut::sub_image_mut()`], except that it returns an |
403 | | /// [`ImgRefMut`] with the same lifetime, rather than a reborrow with a shorter lifetime. |
404 | | /// |
405 | | /// ## Panics |
406 | | /// |
407 | | /// If the coordinates are out of bounds |
408 | | #[allow(deprecated)] |
409 | | #[must_use] |
410 | | #[track_caller] |
411 | 0 | pub fn into_sub_image_mut(self, left: usize, top: usize, width: usize, height: usize) -> Self { |
412 | 0 | assert!(top + height <= self.height()); |
413 | 0 | assert!(left + width <= self.width()); |
414 | 0 | let (start, end, stride) = sub_image(left, top, width, height, self.stride(), self.buf.len()); |
415 | 0 | let buf = &mut self.buf[start..end]; |
416 | 0 | ImgRefMut::new_stride(buf, width, height, stride) |
417 | 0 | } |
418 | | |
419 | | /// Make mutable reference immutable |
420 | | #[inline] |
421 | | #[must_use] |
422 | 0 | pub fn as_ref(&self) -> ImgRef<'_, T> { |
423 | 0 | self.new_buf(self.buf().as_ref()) |
424 | 0 | } |
425 | | } |
426 | | |
427 | | impl<'slice, T: Copy> ImgRef<'slice, T> { |
428 | | /// Iterate `width*height` pixels in the `Img`, ignoring padding area |
429 | | /// |
430 | | /// If you want to iterate in parallel, parallelize `rows()` instead. |
431 | | /// |
432 | | /// # Panics |
433 | | /// |
434 | | /// if width is 0 |
435 | | #[inline] |
436 | | #[track_caller] |
437 | 0 | pub fn pixels(&self) -> PixelsIter<'slice, T> { |
438 | 0 | PixelsIter::new(*self) |
439 | 0 | } Unexecuted instantiation: <imgref::Img<&[rgb::formats::rgba::Rgba<u8>]>>::pixels Unexecuted instantiation: <imgref::Img<&[_]>>::pixels Unexecuted instantiation: <imgref::Img<&[rgb::formats::rgb::Rgb<u8>]>>::pixels |
440 | | } |
441 | | |
442 | | impl<'slice, T> ImgRef<'slice, T> { |
443 | | /// Iterate `width*height` pixels in the `Img`, by reference, ignoring padding area |
444 | | /// |
445 | | /// If you want to iterate in parallel, parallelize `rows()` instead. |
446 | | /// |
447 | | /// # Panics |
448 | | /// |
449 | | /// if width is 0 |
450 | | #[inline] |
451 | 0 | pub fn pixels_ref(&self) -> PixelsRefIter<'slice, T> { |
452 | 0 | PixelsRefIter::new(*self) |
453 | 0 | } |
454 | | } |
455 | | |
456 | | impl<T: Copy> ImgRefMut<'_, T> { |
457 | | /// # Panics |
458 | | /// |
459 | | /// If you want to iterate in parallel, parallelize `rows()` instead. |
460 | | /// |
461 | | /// if width is 0 |
462 | | #[inline] |
463 | 0 | pub fn pixels(&self) -> PixelsIter<'_, T> { |
464 | 0 | PixelsIter::new(self.as_ref()) |
465 | 0 | } |
466 | | } |
467 | | |
468 | | impl<T> ImgRefMut<'_, T> { |
469 | | /// If you want to iterate in parallel, parallelize `rows()` instead. |
470 | | /// # Panics |
471 | | /// |
472 | | /// if width is 0 |
473 | | #[inline] |
474 | 0 | pub fn pixels_mut(&mut self) -> PixelsIterMut<'_, T> { |
475 | 0 | PixelsIterMut::new(self.as_mut()) |
476 | 0 | } |
477 | | } |
478 | | |
479 | | impl<T: Copy> ImgVec<T> { |
480 | | /// If you want to iterate in parallel, parallelize `rows()` instead. |
481 | | /// # Panics |
482 | | /// |
483 | | /// if width is 0 |
484 | | #[inline] |
485 | | #[cfg_attr(debug_assertions, track_caller)] |
486 | 0 | pub fn pixels(&self) -> PixelsIter<'_, T> { |
487 | 0 | PixelsIter::new(self.as_ref()) |
488 | 0 | } |
489 | | } |
490 | | |
491 | | impl<T> ImgVec<T> { |
492 | | /// If you want to iterate in parallel, parallelize `rows()` instead. |
493 | | /// # Panics |
494 | | /// |
495 | | /// if width is 0 |
496 | | #[inline] |
497 | | #[cfg_attr(debug_assertions, track_caller)] |
498 | 0 | pub fn pixels_mut(&mut self) -> PixelsIterMut<'_, T> { |
499 | 0 | PixelsIterMut::new(self.as_mut()) |
500 | 0 | } |
501 | | } |
502 | | |
503 | | impl<T> ImgRefMut<'_, T> { |
504 | | /// Iterate over whole rows as slices |
505 | | /// |
506 | | /// # Panics |
507 | | /// |
508 | | /// if stride is 0 |
509 | | #[inline] |
510 | 0 | pub fn rows(&self) -> RowsIter<'_, T> { |
511 | 0 | self.as_ref().rows() |
512 | 0 | } |
513 | | |
514 | | /// Iterate over whole rows as slices |
515 | | /// |
516 | | /// # Panics |
517 | | /// |
518 | | /// if stride is 0 |
519 | | #[inline] |
520 | | #[allow(deprecated)] |
521 | 0 | pub fn rows_mut(&mut self) -> RowsIterMut<'_, T> { |
522 | 0 | let stride = self.stride(); |
523 | 0 | let width = self.width(); |
524 | 0 | let height = self.height(); |
525 | 0 | let non_padded = &mut self.buf[0..stride * height + width - stride]; |
526 | 0 | RowsIterMut { |
527 | 0 | width, |
528 | 0 | inner: non_padded.chunks_mut(stride), |
529 | 0 | } |
530 | 0 | } |
531 | | } |
532 | | |
533 | | /// Deprecated. Use .`rows()` or .`pixels()` iterators which are more predictable |
534 | | #[cfg(feature = "deprecated")] |
535 | | impl<Container> IntoIterator for Img<Container> where Container: IntoIterator { |
536 | | type Item = Container::Item; |
537 | | type IntoIter = Container::IntoIter; |
538 | | /// Deprecated. Use .`rows()` or .`pixels()` iterators which are more predictable |
539 | 0 | fn into_iter(self) -> Container::IntoIter { |
540 | 0 | self.into_buf().into_iter() |
541 | 0 | } |
542 | | } |
543 | | |
544 | | impl<T> ImgVec<T> { |
545 | | /// Create a mutable view into a region within the image. See `sub_image()` for read-only views. |
546 | | /// |
547 | | /// ## Panics |
548 | | /// |
549 | | /// If the coordinates are out of bounds |
550 | | #[allow(deprecated)] |
551 | | #[must_use] |
552 | | #[track_caller] |
553 | 0 | pub fn sub_image_mut(&mut self, left: usize, top: usize, width: usize, height: usize) -> ImgRefMut<'_, T> { |
554 | 0 | assert!(top + height <= self.height()); |
555 | 0 | assert!(left + width <= self.width()); |
556 | 0 | let start = self.stride * top + left; |
557 | 0 | let min_buf_size = if self.height > 0 { self.stride * height + width - self.stride } else {0}; |
558 | 0 | let buf = &mut self.buf[start .. start + min_buf_size]; |
559 | 0 | Img::new_stride(buf, width, height, self.stride) |
560 | 0 | } |
561 | | |
562 | | #[inline] |
563 | | #[must_use] |
564 | | /// Make a reference for a part of the image, without copying any pixels. |
565 | 0 | pub fn sub_image(&self, left: usize, top: usize, width: usize, height: usize) -> ImgRef<'_, T> { |
566 | 0 | self.as_ref().sub_image(left, top, width, height) |
567 | 0 | } |
568 | | |
569 | | /// Make a reference to this image to pass it to functions without giving up ownership |
570 | | /// |
571 | | /// The reference should be passed by value (`ImgRef`, not `&ImgRef`). |
572 | | /// |
573 | | /// If you need a mutable reference, see `as_mut()` and `sub_image_mut()` |
574 | | #[inline] |
575 | | #[must_use] |
576 | 0 | pub fn as_ref(&self) -> ImgRef<'_, T> { |
577 | 0 | self.new_buf(self.buf().as_ref()) |
578 | 0 | } Unexecuted instantiation: <imgref::Img<alloc::vec::Vec<rgb::formats::rgba::Rgba<u8>>>>::as_ref Unexecuted instantiation: <imgref::Img<alloc::vec::Vec<_>>>::as_ref |
579 | | |
580 | | /// Make a mutable reference to the entire image |
581 | | /// |
582 | | /// The reference should be passed by value (`ImgRefMut`, not `&mut ImgRefMut`). |
583 | | /// |
584 | | /// See also `sub_image_mut()` and `rows_mut()` |
585 | | #[inline] |
586 | 0 | pub fn as_mut(&mut self) -> ImgRefMut<'_, T> { |
587 | 0 | let width = self.width(); |
588 | 0 | let height = self.height(); |
589 | 0 | let stride = self.stride(); |
590 | 0 | Img::new_stride(self.buf_mut().as_mut(), width, height, stride) |
591 | 0 | } |
592 | | |
593 | | #[deprecated(note = "Size of this buffer may be unpredictable. Use .rows() instead")] |
594 | | #[cfg(feature = "deprecated")] |
595 | | #[doc(hidden)] |
596 | 0 | pub fn iter(&self) -> slice::Iter<'_, T> { |
597 | 0 | self.buf().iter() |
598 | 0 | } |
599 | | |
600 | | /// Iterate over rows of the image as slices |
601 | | /// |
602 | | /// Each slice is guaranteed to be exactly `width` pixels wide. |
603 | | /// |
604 | | /// This iterator is a good candidate for parallelization (e.g. rayon's `par_bridge()`) |
605 | | #[inline] |
606 | | #[cfg_attr(debug_assertions, track_caller)] |
607 | 0 | pub fn rows(&self) -> RowsIter<'_, T> { |
608 | 0 | self.as_ref().rows() |
609 | 0 | } |
610 | | |
611 | | /// Iterate over rows of the image as mutable slices |
612 | | /// |
613 | | /// Each slice is guaranteed to be exactly `width` pixels wide. |
614 | | /// |
615 | | /// This iterator is a good candidate for parallelization (e.g. rayon's `par_bridge()`) |
616 | | #[inline] |
617 | | #[allow(deprecated)] |
618 | 0 | pub fn rows_mut(&mut self) -> RowsIterMut<'_, T> { |
619 | 0 | let stride = self.stride(); |
620 | 0 | let width = self.width(); |
621 | 0 | let height = self.height(); |
622 | 0 | let non_padded = &mut self.buf[0..stride * height + width - stride]; |
623 | 0 | RowsIterMut { |
624 | 0 | width, |
625 | 0 | inner: non_padded.chunks_mut(stride), |
626 | 0 | } |
627 | 0 | } |
628 | | } |
629 | | |
630 | | impl<Container> Img<Container> { |
631 | | /// Same as `new()`, except each row is located `stride` number of pixels after the previous one. |
632 | | /// |
633 | | /// Stride can be equal to `width` or larger. If it's larger, then pixels between end of previous row and start of the next are considered a padding, and may be ignored. |
634 | | /// |
635 | | /// The `Container` is usually a `Vec` or a slice. |
636 | | /// |
637 | | /// ## Panics |
638 | | /// |
639 | | /// If stride is 0. |
640 | | /// |
641 | | /// <div class="warning"> |
642 | | /// |
643 | | /// This method is (too) generic over the container type, and can't check its length. Other methods will panic if the buffer is too small. |
644 | | /// |
645 | | /// </div> |
646 | | #[inline] |
647 | | #[allow(deprecated)] |
648 | | #[track_caller] |
649 | 0 | pub fn new_stride(buf: Container, width: usize, height: usize, stride: usize) -> Self { |
650 | 0 | assert!(stride > 0); |
651 | 0 | assert!(stride >= width); |
652 | 0 | debug_assert!(height < u32::MAX as usize); |
653 | 0 | debug_assert!(width < u32::MAX as usize); |
654 | 0 | Self { |
655 | 0 | buf, |
656 | 0 | width: width as u32, |
657 | 0 | height: height as u32, |
658 | 0 | stride, |
659 | 0 | } |
660 | 0 | } Unexecuted instantiation: <imgref::Img<alloc::vec::Vec<rgb::formats::rgba::Rgba<u8>>>>::new_stride Unexecuted instantiation: <imgref::Img<&[rgb::formats::rgba::Rgba<u8>]>>::new_stride Unexecuted instantiation: <imgref::Img<_>>::new_stride Unexecuted instantiation: <imgref::Img<&[rgb::formats::rgb::Rgb<u8>]>>::new_stride |
661 | | |
662 | | /// Create new image with `Container` (which can be `Vec`, `&[]` or something else) with given `width` and `height` in pixels. |
663 | | /// |
664 | | /// Assumes the pixels in container are contiguous, layed out row by row with `width` pixels per row and at least `height` rows. |
665 | | /// |
666 | | /// If the container is larger than `width`×`height` pixels, the extra rows are a considered a padding and may be ignored. |
667 | | /// |
668 | | /// # Panics |
669 | | /// |
670 | | /// <div class="warning"> |
671 | | /// |
672 | | /// This method is (too) generic over the container type, and can't check its length. Other methods will panic if the buffer is too small. |
673 | | /// |
674 | | /// </div> |
675 | | #[inline] |
676 | 0 | pub fn new(buf: Container, width: usize, height: usize) -> Self { |
677 | 0 | Self::new_stride(buf, width, height, width) |
678 | 0 | } Unexecuted instantiation: <imgref::Img<alloc::vec::Vec<rgb::formats::rgba::Rgba<u8>>>>::new Unexecuted instantiation: <imgref::Img<_>>::new Unexecuted instantiation: <imgref::Img<&[rgb::formats::rgb::Rgb<u8>]>>::new Unexecuted instantiation: <imgref::Img<&[rgb::formats::rgba::Rgba<u8>]>>::new |
679 | | } |
680 | | |
681 | | #[cold] |
682 | | #[inline(never)] |
683 | | #[cfg_attr(debug_assertions, track_caller)] |
684 | 0 | fn imgref_invalid_size(width: u32, height: u32, stride: usize, min_size: usize, len: usize) { |
685 | 0 | panic!("Invalid ImgRef params. Got stride={stride} for {width}×{height}; len={len} (needed {min_size})"); |
686 | | } |
687 | | |
688 | | impl<T> ImgRefMut<'_, T> { |
689 | | #[cfg_attr(debug_assertions, track_caller)] |
690 | 0 | fn valid_buf_mut(&mut self) -> &mut [T] { |
691 | 0 | let len = self.as_ref().valid_min_len(); |
692 | 0 | &mut self.buf_mut()[..len] |
693 | 0 | } |
694 | | } |
695 | | |
696 | | impl<'buf, T> ImgRef<'buf, T> { |
697 | | #[cfg_attr(debug_assertions, track_caller)] |
698 | 0 | fn valid_buf(&self) -> &'buf [T] { |
699 | 0 | &self.buf()[..self.valid_min_len()] |
700 | 0 | } Unexecuted instantiation: <imgref::Img<&[rgb::formats::rgba::Rgba<u8>]>>::valid_buf Unexecuted instantiation: <imgref::Img<&[_]>>::valid_buf Unexecuted instantiation: <imgref::Img<&[rgb::formats::rgb::Rgb<u8>]>>::valid_buf |
701 | | |
702 | | #[cfg_attr(debug_assertions, track_caller)] |
703 | | #[inline(always)] |
704 | 0 | fn valid_min_len(&self) -> usize { |
705 | 0 | let stride = self.stride(); |
706 | 0 | let width = self.width(); |
707 | 0 | let height = self.height(); |
708 | 0 | let min_size = if height == 0 || width == 0 { 0 } else { stride * height + width - stride }; |
709 | 0 | let buf = self.buf(); |
710 | | #[allow(deprecated)] |
711 | 0 | if stride == 0 || stride < width || buf.len() < min_size { |
712 | 0 | imgref_invalid_size(self.width, self.height, stride, min_size, buf.len()); |
713 | 0 | } |
714 | 0 | min_size |
715 | 0 | } Unexecuted instantiation: <imgref::Img<&[rgb::formats::rgba::Rgba<u8>]>>::valid_min_len Unexecuted instantiation: <imgref::Img<&[_]>>::valid_min_len Unexecuted instantiation: <imgref::Img<&[rgb::formats::rgb::Rgb<u8>]>>::valid_min_len |
716 | | } |
717 | | |
718 | | impl<T: Copy> Img<Vec<T>> { |
719 | | /// Returns the buffer, width, height. Guarantees that the buffer is contiguous, |
720 | | /// i.e. it's `width*height` elements long, and `[x + y*width]` addresses each pixel. |
721 | | /// |
722 | | /// Efficiently performs operation in-place. For other containers use `pixels().collect()`. |
723 | | #[allow(deprecated)] |
724 | | #[must_use] |
725 | | #[cfg_attr(debug_assertions, track_caller)] |
726 | 0 | pub fn into_contiguous_buf(mut self) -> (Vec<T>, usize, usize) { |
727 | 0 | let (_, w, h) = self.as_contiguous_buf(); |
728 | 0 | (self.buf, w, h) |
729 | 0 | } |
730 | | |
731 | | /// Returns a reference to the buffer, width, height. Guarantees that the buffer is contiguous, |
732 | | /// i.e. it's `width*height` elements long, and `[x + y*width]` addresses each pixel. |
733 | | /// |
734 | | /// Efficiently performs operation in-place. For other containers use `pixels().collect()`. |
735 | | #[allow(deprecated)] |
736 | | #[must_use] |
737 | | #[cfg_attr(debug_assertions, track_caller)] |
738 | 0 | pub fn as_contiguous_buf(&mut self) -> (&[T], usize, usize) { |
739 | 0 | let width = self.width(); |
740 | 0 | let height = self.height(); |
741 | 0 | let stride = self.stride(); |
742 | 0 | if width != stride { |
743 | 0 | let mut ref_mut = self.as_mut(); |
744 | 0 | let buf = ref_mut.valid_buf_mut(); |
745 | 0 | for row in 1..height { |
746 | 0 | buf.copy_within(row * stride .. row * stride + width, row * width); |
747 | 0 | } |
748 | 0 | } |
749 | 0 | self.buf.truncate(width * height); |
750 | 0 | (&mut self.buf, width, height) |
751 | 0 | } |
752 | | } |
753 | | |
754 | | impl<OldContainer> Img<OldContainer> { |
755 | | /// A convenience method for creating an image of the same size and stride, but with a new buffer. |
756 | | /// |
757 | | /// # Panics |
758 | | /// |
759 | | /// If the new buffer has a different length |
760 | | #[inline] |
761 | | #[track_caller] |
762 | 0 | pub fn map_buf<NewContainer, OldPixel, NewPixel, F>(self, callback: F) -> Img<NewContainer> |
763 | 0 | where NewContainer: AsRef<[NewPixel]>, OldContainer: AsRef<[OldPixel]>, F: FnOnce(OldContainer) -> NewContainer { |
764 | 0 | let width = self.width(); |
765 | 0 | let height = self.height(); |
766 | 0 | let stride = self.stride(); |
767 | 0 | let old_buf_len = self.buf().as_ref().len(); |
768 | | #[allow(deprecated)] |
769 | 0 | let new_buf = callback(self.buf); |
770 | 0 | assert_eq!(old_buf_len, new_buf.as_ref().len()); |
771 | 0 | Img::new_stride(new_buf, width, height, stride) |
772 | 0 | } |
773 | | |
774 | | /// A convenience method for creating an image of the same size and stride, but with a new buffer. |
775 | | /// |
776 | | /// # Panics |
777 | | /// |
778 | | /// If the new buffer has a different length |
779 | | #[inline] |
780 | | #[track_caller] |
781 | 0 | pub fn new_buf<NewContainer, OldPixel, NewPixel>(&self, new_buf: NewContainer) -> Img<NewContainer> |
782 | 0 | where NewContainer: AsRef<[NewPixel]>, OldContainer: AsRef<[OldPixel]> { |
783 | 0 | assert_eq!(self.buf().as_ref().len(), new_buf.as_ref().len()); |
784 | 0 | Img::new_stride(new_buf, self.width(), self.height(), self.stride()) |
785 | 0 | } Unexecuted instantiation: <imgref::Img<alloc::vec::Vec<rgb::formats::rgba::Rgba<u8>>>>::new_buf::<&[rgb::formats::rgba::Rgba<u8>], rgb::formats::rgba::Rgba<u8>, rgb::formats::rgba::Rgba<u8>> Unexecuted instantiation: <imgref::Img<_>>::new_buf::<_, _, _> |
786 | | } |
787 | | |
788 | | impl<T: Clone> From<Img<Cow<'_, [T]>>> for Img<Vec<T>> { |
789 | | #[allow(deprecated)] |
790 | 0 | fn from(img: Img<Cow<'_, [T]>>) -> Self { |
791 | 0 | Self { |
792 | 0 | width: img.width, |
793 | 0 | height: img.height, |
794 | 0 | stride: img.stride, |
795 | 0 | buf: img.buf.into_owned(), |
796 | 0 | } |
797 | 0 | } |
798 | | } |
799 | | |
800 | | impl<T: Clone> From<ImgVec<T>> for Img<Cow<'static, [T]>> { |
801 | | #[allow(deprecated)] |
802 | 0 | fn from(img: ImgVec<T>) -> Self { |
803 | 0 | Img { |
804 | 0 | width: img.width, |
805 | 0 | height: img.height, |
806 | 0 | stride: img.stride, |
807 | 0 | buf: img.buf.into(), |
808 | 0 | } |
809 | 0 | } |
810 | | } |
811 | | |
812 | | impl<'a, T: Clone> From<ImgRef<'a, T>> for Img<Cow<'a, [T]>> { |
813 | | #[allow(deprecated)] |
814 | 0 | fn from(img: ImgRef<'a, T>) -> Self { |
815 | 0 | Img { |
816 | 0 | buf: img.buf.into(), |
817 | 0 | width: img.width, |
818 | 0 | height: img.height, |
819 | 0 | stride: img.stride, |
820 | 0 | } |
821 | 0 | } |
822 | | } |
823 | | |
824 | | impl<T: Clone> Img<Cow<'_, [T]>> { |
825 | | /// Convert underlying buffer to owned (e.g. slice to vec) |
826 | | /// |
827 | | /// See also `to_contiguous_buf().0.into_owned()` |
828 | | #[allow(deprecated)] |
829 | | #[must_use] |
830 | 0 | pub fn into_owned(self) -> ImgVec<T> { |
831 | 0 | match self.buf { |
832 | | Cow::Borrowed(_) => { |
833 | 0 | let tmp = self.as_ref(); |
834 | 0 | let (buf, w, h) = tmp.to_contiguous_buf(); |
835 | 0 | ImgVec::new(buf.into_owned(), w, h) |
836 | | }, |
837 | 0 | Cow::Owned(buf) => Img { |
838 | 0 | buf, |
839 | 0 | width: self.width, |
840 | 0 | height: self.height, |
841 | 0 | stride: self.stride, |
842 | 0 | }, |
843 | | } |
844 | 0 | } |
845 | | } |
846 | | |
847 | | impl<T> Img<T> where T: ToOwned { |
848 | | /// Convert underlying buffer to owned (e.g. slice to vec) |
849 | | /// |
850 | | /// See also `to_contiguous_buf().0.into_owned()` |
851 | | #[allow(deprecated)] |
852 | 0 | pub fn to_owned(&self) -> Img<T::Owned> { |
853 | 0 | Img { |
854 | 0 | buf: self.buf.to_owned(), |
855 | 0 | width: self.width, |
856 | 0 | height: self.height, |
857 | 0 | stride: self.stride, |
858 | 0 | } |
859 | 0 | } |
860 | | } |
861 | | |
862 | | #[cfg(test)] |
863 | | mod tests { |
864 | | use super::*; |
865 | | use alloc::vec; |
866 | | |
867 | | mod with_opinionated_container { |
868 | | use super::*; |
869 | | |
870 | | struct IDontDeriveAnything; |
871 | | |
872 | | #[test] |
873 | | fn compiles() { |
874 | | let _ = Img::new(IDontDeriveAnything, 1, 1); |
875 | | } |
876 | | } |
877 | | |
878 | | #[test] |
879 | | fn with_vec() { |
880 | | let bytes = vec![0u8;20]; |
881 | | let old = Img::new_stride(bytes, 10,2,10); |
882 | | let _ = old.new_buf(vec![6u16;20]); |
883 | | } |
884 | | |
885 | | #[test] |
886 | | fn zero() { |
887 | | let bytes = vec![0u8]; |
888 | | let mut img = Img::new_stride(bytes,0,0,1); |
889 | | let _ = img.sub_image(0,0,0,0); |
890 | | let _ = img.sub_image_mut(0,0,0,0); |
891 | | let _ = img.as_ref(); |
892 | | } |
893 | | |
894 | | #[test] |
895 | | fn zero_width() { |
896 | | let bytes = vec![0u8]; |
897 | | let mut img = Img::new_stride(bytes,0,1,1); |
898 | | let _ = img.sub_image(0,1,0,0); |
899 | | let _ = img.sub_image_mut(0,0,0,1); |
900 | | } |
901 | | |
902 | | #[test] |
903 | | fn zero_height() { |
904 | | let bytes = vec![0u8]; |
905 | | let mut img = Img::new_stride(bytes,1,0,1); |
906 | | assert_eq!(0, img.rows().count()); |
907 | | let _ = img.sub_image(1,0,0,0); |
908 | | let _ = img.sub_image_mut(0,0,1,0); |
909 | | } |
910 | | |
911 | | #[test] |
912 | | #[allow(deprecated)] |
913 | | fn with_slice() { |
914 | | let bytes = vec![0u8;20]; |
915 | | let _ = Img::new_stride(bytes.as_slice(), 10,2,10); |
916 | | let vec = ImgVec::new_stride(bytes, 10,2,10); |
917 | | |
918 | | #[cfg(feature = "deprecated")] |
919 | | for _ in vec.iter() {} |
920 | | |
921 | | assert_eq!(2, vec.rows().count()); |
922 | | for _ in *vec.as_ref().buf() {} |
923 | | |
924 | | #[cfg(feature = "deprecated")] |
925 | | for _ in vec {} |
926 | | } |
927 | | |
928 | | #[test] |
929 | | fn sub() { |
930 | | let img = Img::new_stride(vec![1,2,3,4, |
931 | | 5,6,7,8, |
932 | | 9], 3, 2, 4); |
933 | | assert_eq!(img.buf()[img.stride()], 5); |
934 | | assert_eq!(img.buf()[img.stride() + img.width()-1], 7); |
935 | | |
936 | | assert_eq!(img.pixels().count(), img.width() * img.height()); |
937 | | assert_eq!(img.pixels().sum::<i32>(), 24); |
938 | | |
939 | | { |
940 | | let refimg = img.as_ref(); |
941 | | let refimg2 = refimg; // Test is Copy |
942 | | |
943 | | // sub-image with stride hits end of the buffer |
944 | | let s1 = refimg.sub_image(1, 0, refimg.width()-1, refimg.height()); |
945 | | let _ = s1.sub_image(1, 0, s1.width()-1, s1.height()); |
946 | | |
947 | | let subimg = refimg.sub_image(1, 1, 2, 1); |
948 | | assert_eq!(subimg.pixels().count(), subimg.width() * subimg.height()); |
949 | | |
950 | | assert_eq!(subimg.buf()[0], 6); |
951 | | assert_eq!(subimg.stride(), refimg2.stride()); |
952 | | assert!(subimg.stride() * subimg.height() + subimg.width() - subimg.stride() <= subimg.buf().len()); |
953 | | assert_eq!(refimg.buf()[0], 1); |
954 | | assert_eq!(1, subimg.rows().count()); |
955 | | } |
956 | | |
957 | | // 3 different methods for constructing mutable sub-images |
958 | | let mut img_for_mut_1 = img.clone(); |
959 | | let mut img_for_mut_2 = img.clone(); |
960 | | let mut img_for_mut_3 = img; |
961 | | for mut subimg in [ |
962 | | img_for_mut_1.sub_image_mut(1, 1, 2, 1), |
963 | | img_for_mut_2.as_mut().sub_image_mut(1, 1, 2, 1), |
964 | | img_for_mut_3.as_mut().into_sub_image_mut(1, 1, 2, 1), |
965 | | ] { |
966 | | assert_eq!(1, subimg.rows().count()); |
967 | | assert_eq!(1, subimg.rows_mut().count()); |
968 | | assert_eq!(1, subimg.rows_mut().rev().count()); |
969 | | assert_eq!(1, subimg.rows_mut().fuse().rev().count()); |
970 | | assert_eq!(subimg.buf()[0], 6); |
971 | | } |
972 | | } |
973 | | |
974 | | #[test] |
975 | | fn rows() { |
976 | | let img = ImgVec::new_stride(vec![0u8; 10000], 10, 15, 100); |
977 | | assert_eq!(img.height(), img.rows().count()); |
978 | | assert_eq!(img.height(), img.rows().rev().count()); |
979 | | assert_eq!(img.height(), img.rows().fuse().rev().count()); |
980 | | } |
981 | | |
982 | | #[test] |
983 | | fn mut_pixels() { |
984 | | for y in 1..15 { |
985 | | for x in 1..10 { |
986 | | let mut img = ImgVec::new_stride(vec![0u8; 10000], x, y, 100); |
987 | | assert_eq!(x*y, img.pixels_mut().count()); |
988 | | assert_eq!(x*y, img.as_mut().pixels().count()); |
989 | | assert_eq!(x*y, img.as_mut().pixels_mut().count()); |
990 | | assert_eq!(x*y, img.as_mut().as_ref().pixels().count()); |
991 | | } |
992 | | } |
993 | | } |
994 | | |
995 | | #[test] |
996 | | fn into_contiguous_buf() { |
997 | | for in_h in [1, 2, 3, 38, 39, 40, 41].iter().copied() { |
998 | | for in_w in [1, 2, 3, 120, 121].iter().copied() { |
999 | | for stride in [in_w, 121, 122, 166, 242, 243].iter().copied() { |
1000 | | let img = ImgVec::new_stride((0..10000).map(|x| x as u8).collect(), in_w, in_h, stride) |
1001 | | .map_buf(|x| x); |
1002 | | let pixels: Vec<_> = img.pixels().collect(); |
1003 | | let (buf, w, h) = img.into_contiguous_buf(); |
1004 | | assert_eq!(pixels, buf); |
1005 | | assert_eq!(in_w*in_h, buf.len()); |
1006 | | assert_eq!(10000, buf.capacity()); |
1007 | | assert_eq!(in_w, w); |
1008 | | assert_eq!(in_h, h); |
1009 | | } |
1010 | | } |
1011 | | } |
1012 | | |
1013 | | let img = ImgVec::new((0..55*33).map(|x| x as u8).collect(), 55, 33); |
1014 | | let pixels: Vec<_> = img.pixels().collect(); |
1015 | | let tmp = img.as_ref(); |
1016 | | let (buf, ..) = tmp.to_contiguous_buf(); |
1017 | | assert_eq!(&pixels[..], &buf[..]); |
1018 | | let (buf, ..) = img.into_contiguous_buf(); |
1019 | | assert_eq!(pixels, buf); |
1020 | | } |
1021 | | } |