1 | //! Contains the generic `ImageBuffer` struct. |
---|---|
2 | use num_traits::Zero; |
3 | use std::fmt; |
4 | use std::marker::PhantomData; |
5 | use std::ops::{Deref, DerefMut, Index, IndexMut, Range}; |
6 | use std::path::Path; |
7 | use std::slice::{ChunksExact, ChunksExactMut}; |
8 | |
9 | use crate::color::{FromColor, Luma, LumaA, Rgb, Rgba}; |
10 | use crate::dynimage::{save_buffer, save_buffer_with_format, write_buffer_with_format}; |
11 | use crate::error::ImageResult; |
12 | use crate::flat::{FlatSamples, SampleLayout}; |
13 | use crate::image::{GenericImage, GenericImageView, ImageEncoder, ImageFormat, ImageOutputFormat}; |
14 | use crate::math::Rect; |
15 | use crate::traits::{EncodableLayout, Pixel, PixelWithColorType}; |
16 | use crate::utils::expand_packed; |
17 | use crate::DynamicImage; |
18 | |
19 | /// Iterate over pixel refs. |
20 | pub struct Pixels<'a, P: Pixel + 'a> |
21 | where |
22 | P::Subpixel: 'a, |
23 | { |
24 | chunks: ChunksExact<'a, P::Subpixel>, |
25 | } |
26 | |
27 | impl<'a, P: Pixel + 'a> Iterator for Pixels<'a, P> |
28 | where |
29 | P::Subpixel: 'a, |
30 | { |
31 | type Item = &'a P; |
32 | |
33 | #[inline(always)] |
34 | fn next(&mut self) -> Option<&'a P> { |
35 | self.chunks.next().map(|v: &[ ::Subpixel] | <P as Pixel>::from_slice(v)) |
36 | } |
37 | |
38 | #[inline(always)] |
39 | fn size_hint(&self) -> (usize, Option<usize>) { |
40 | let len: usize = self.len(); |
41 | (len, Some(len)) |
42 | } |
43 | } |
44 | |
45 | impl<'a, P: Pixel + 'a> ExactSizeIterator for Pixels<'a, P> |
46 | where |
47 | P::Subpixel: 'a, |
48 | { |
49 | fn len(&self) -> usize { |
50 | self.chunks.len() |
51 | } |
52 | } |
53 | |
54 | impl<'a, P: Pixel + 'a> DoubleEndedIterator for Pixels<'a, P> |
55 | where |
56 | P::Subpixel: 'a, |
57 | { |
58 | #[inline(always)] |
59 | fn next_back(&mut self) -> Option<&'a P> { |
60 | self.chunks.next_back().map(|v: &[ ::Subpixel] | <P as Pixel>::from_slice(v)) |
61 | } |
62 | } |
63 | |
64 | impl<P: Pixel> Clone for Pixels<'_, P> { |
65 | fn clone(&self) -> Self { |
66 | Pixels { |
67 | chunks: self.chunks.clone(), |
68 | } |
69 | } |
70 | } |
71 | |
72 | impl<P: Pixel> fmt::Debug for Pixels<'_, P> |
73 | where |
74 | P::Subpixel: fmt::Debug, |
75 | { |
76 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
77 | f&mut DebugStruct<'_, '_>.debug_struct("Pixels") |
78 | .field(name:"chunks", &self.chunks) |
79 | .finish() |
80 | } |
81 | } |
82 | |
83 | /// Iterate over mutable pixel refs. |
84 | pub struct PixelsMut<'a, P: Pixel + 'a> |
85 | where |
86 | P::Subpixel: 'a, |
87 | { |
88 | chunks: ChunksExactMut<'a, P::Subpixel>, |
89 | } |
90 | |
91 | impl<'a, P: Pixel + 'a> Iterator for PixelsMut<'a, P> |
92 | where |
93 | P::Subpixel: 'a, |
94 | { |
95 | type Item = &'a mut P; |
96 | |
97 | #[inline(always)] |
98 | fn next(&mut self) -> Option<&'a mut P> { |
99 | self.chunks.next().map(|v: &mut [ ::Subpixel] | <P as Pixel>::from_slice_mut(slice:v)) |
100 | } |
101 | |
102 | #[inline(always)] |
103 | fn size_hint(&self) -> (usize, Option<usize>) { |
104 | let len: usize = self.len(); |
105 | (len, Some(len)) |
106 | } |
107 | } |
108 | |
109 | impl<'a, P: Pixel + 'a> ExactSizeIterator for PixelsMut<'a, P> |
110 | where |
111 | P::Subpixel: 'a, |
112 | { |
113 | fn len(&self) -> usize { |
114 | self.chunks.len() |
115 | } |
116 | } |
117 | |
118 | impl<'a, P: Pixel + 'a> DoubleEndedIterator for PixelsMut<'a, P> |
119 | where |
120 | P::Subpixel: 'a, |
121 | { |
122 | #[inline(always)] |
123 | fn next_back(&mut self) -> Option<&'a mut P> { |
124 | self.chunks |
125 | .next_back() |
126 | .map(|v: &mut [ ::Subpixel] | <P as Pixel>::from_slice_mut(slice:v)) |
127 | } |
128 | } |
129 | |
130 | impl<P: Pixel> fmt::Debug for PixelsMut<'_, P> |
131 | where |
132 | P::Subpixel: fmt::Debug, |
133 | { |
134 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
135 | f&mut DebugStruct<'_, '_>.debug_struct("PixelsMut") |
136 | .field(name:"chunks", &self.chunks) |
137 | .finish() |
138 | } |
139 | } |
140 | |
141 | /// Iterate over rows of an image |
142 | /// |
143 | /// This iterator is created with [`ImageBuffer::rows`]. See its document for details. |
144 | /// |
145 | /// [`ImageBuffer::rows`]: ../struct.ImageBuffer.html#method.rows |
146 | pub struct Rows<'a, P: Pixel + 'a> |
147 | where |
148 | <P as Pixel>::Subpixel: 'a, |
149 | { |
150 | pixels: ChunksExact<'a, P::Subpixel>, |
151 | } |
152 | |
153 | impl<'a, P: Pixel + 'a> Rows<'a, P> { |
154 | /// Construct the iterator from image pixels. This is not public since it has a (hidden) panic |
155 | /// condition. The `pixels` slice must be large enough so that all pixels are addressable. |
156 | fn with_image(pixels: &'a [P::Subpixel], width: u32, height: u32) -> Self { |
157 | let row_len: usize = (width as usize) * usize::from(<P as Pixel>::CHANNEL_COUNT); |
158 | if row_len == 0 { |
159 | Rows { |
160 | pixels: [].chunks_exact(chunk_size:1), |
161 | } |
162 | } else { |
163 | let pixels: &[ ::Subpixel] = pixels |
164 | .get(..row_len * height as usize) |
165 | .expect(msg:"Pixel buffer has too few subpixels"); |
166 | // Rows are physically present. In particular, height is smaller than `usize::MAX` as |
167 | // all subpixels can be indexed. |
168 | Rows { |
169 | pixels: pixels.chunks_exact(chunk_size:row_len), |
170 | } |
171 | } |
172 | } |
173 | } |
174 | |
175 | impl<'a, P: Pixel + 'a> Iterator for Rows<'a, P> |
176 | where |
177 | P::Subpixel: 'a, |
178 | { |
179 | type Item = Pixels<'a, P>; |
180 | |
181 | #[inline(always)] |
182 | fn next(&mut self) -> Option<Pixels<'a, P>> { |
183 | let row: &[ ::Subpixel] = self.pixels.next()?; |
184 | Some(Pixels { |
185 | // Note: this is not reached when CHANNEL_COUNT is 0. |
186 | chunks: row.chunks_exact(<P as Pixel>::CHANNEL_COUNT as usize), |
187 | }) |
188 | } |
189 | |
190 | #[inline(always)] |
191 | fn size_hint(&self) -> (usize, Option<usize>) { |
192 | let len: usize = self.len(); |
193 | (len, Some(len)) |
194 | } |
195 | } |
196 | |
197 | impl<'a, P: Pixel + 'a> ExactSizeIterator for Rows<'a, P> |
198 | where |
199 | P::Subpixel: 'a, |
200 | { |
201 | fn len(&self) -> usize { |
202 | self.pixels.len() |
203 | } |
204 | } |
205 | |
206 | impl<'a, P: Pixel + 'a> DoubleEndedIterator for Rows<'a, P> |
207 | where |
208 | P::Subpixel: 'a, |
209 | { |
210 | #[inline(always)] |
211 | fn next_back(&mut self) -> Option<Pixels<'a, P>> { |
212 | let row: &[ ::Subpixel] = self.pixels.next_back()?; |
213 | Some(Pixels { |
214 | // Note: this is not reached when CHANNEL_COUNT is 0. |
215 | chunks: row.chunks_exact(<P as Pixel>::CHANNEL_COUNT as usize), |
216 | }) |
217 | } |
218 | } |
219 | |
220 | impl<P: Pixel> Clone for Rows<'_, P> { |
221 | fn clone(&self) -> Self { |
222 | Rows { |
223 | pixels: self.pixels.clone(), |
224 | } |
225 | } |
226 | } |
227 | |
228 | impl<P: Pixel> fmt::Debug for Rows<'_, P> |
229 | where |
230 | P::Subpixel: fmt::Debug, |
231 | { |
232 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
233 | f&mut DebugStruct<'_, '_>.debug_struct("Rows") |
234 | .field(name:"pixels", &self.pixels) |
235 | .finish() |
236 | } |
237 | } |
238 | |
239 | /// Iterate over mutable rows of an image |
240 | /// |
241 | /// This iterator is created with [`ImageBuffer::rows_mut`]. See its document for details. |
242 | /// |
243 | /// [`ImageBuffer::rows_mut`]: ../struct.ImageBuffer.html#method.rows_mut |
244 | pub struct RowsMut<'a, P: Pixel + 'a> |
245 | where |
246 | <P as Pixel>::Subpixel: 'a, |
247 | { |
248 | pixels: ChunksExactMut<'a, P::Subpixel>, |
249 | } |
250 | |
251 | impl<'a, P: Pixel + 'a> RowsMut<'a, P> { |
252 | /// Construct the iterator from image pixels. This is not public since it has a (hidden) panic |
253 | /// condition. The `pixels` slice must be large enough so that all pixels are addressable. |
254 | fn with_image(pixels: &'a mut [P::Subpixel], width: u32, height: u32) -> Self { |
255 | let row_len: usize = (width as usize) * usize::from(<P as Pixel>::CHANNEL_COUNT); |
256 | if row_len == 0 { |
257 | RowsMut { |
258 | pixels: [].chunks_exact_mut(chunk_size:1), |
259 | } |
260 | } else { |
261 | let pixels: &mut [ ::Subpixel] = pixels |
262 | .get_mut(..row_len * height as usize) |
263 | .expect(msg:"Pixel buffer has too few subpixels"); |
264 | // Rows are physically present. In particular, height is smaller than `usize::MAX` as |
265 | // all subpixels can be indexed. |
266 | RowsMut { |
267 | pixels: pixels.chunks_exact_mut(chunk_size:row_len), |
268 | } |
269 | } |
270 | } |
271 | } |
272 | |
273 | impl<'a, P: Pixel + 'a> Iterator for RowsMut<'a, P> |
274 | where |
275 | P::Subpixel: 'a, |
276 | { |
277 | type Item = PixelsMut<'a, P>; |
278 | |
279 | #[inline(always)] |
280 | fn next(&mut self) -> Option<PixelsMut<'a, P>> { |
281 | let row: &mut [ ::Subpixel] = self.pixels.next()?; |
282 | Some(PixelsMut { |
283 | // Note: this is not reached when CHANNEL_COUNT is 0. |
284 | chunks: row.chunks_exact_mut(<P as Pixel>::CHANNEL_COUNT as usize), |
285 | }) |
286 | } |
287 | |
288 | #[inline(always)] |
289 | fn size_hint(&self) -> (usize, Option<usize>) { |
290 | let len: usize = self.len(); |
291 | (len, Some(len)) |
292 | } |
293 | } |
294 | |
295 | impl<'a, P: Pixel + 'a> ExactSizeIterator for RowsMut<'a, P> |
296 | where |
297 | P::Subpixel: 'a, |
298 | { |
299 | fn len(&self) -> usize { |
300 | self.pixels.len() |
301 | } |
302 | } |
303 | |
304 | impl<'a, P: Pixel + 'a> DoubleEndedIterator for RowsMut<'a, P> |
305 | where |
306 | P::Subpixel: 'a, |
307 | { |
308 | #[inline(always)] |
309 | fn next_back(&mut self) -> Option<PixelsMut<'a, P>> { |
310 | let row: &mut [ ::Subpixel] = self.pixels.next_back()?; |
311 | Some(PixelsMut { |
312 | // Note: this is not reached when CHANNEL_COUNT is 0. |
313 | chunks: row.chunks_exact_mut(<P as Pixel>::CHANNEL_COUNT as usize), |
314 | }) |
315 | } |
316 | } |
317 | |
318 | impl<P: Pixel> fmt::Debug for RowsMut<'_, P> |
319 | where |
320 | P::Subpixel: fmt::Debug, |
321 | { |
322 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
323 | f&mut DebugStruct<'_, '_>.debug_struct("RowsMut") |
324 | .field(name:"pixels", &self.pixels) |
325 | .finish() |
326 | } |
327 | } |
328 | |
329 | /// Enumerate the pixels of an image. |
330 | pub struct EnumeratePixels<'a, P: Pixel + 'a> |
331 | where |
332 | <P as Pixel>::Subpixel: 'a, |
333 | { |
334 | pixels: Pixels<'a, P>, |
335 | x: u32, |
336 | y: u32, |
337 | width: u32, |
338 | } |
339 | |
340 | impl<'a, P: Pixel + 'a> Iterator for EnumeratePixels<'a, P> |
341 | where |
342 | P::Subpixel: 'a, |
343 | { |
344 | type Item = (u32, u32, &'a P); |
345 | |
346 | #[inline(always)] |
347 | fn next(&mut self) -> Option<(u32, u32, &'a P)> { |
348 | if self.x >= self.width { |
349 | self.x = 0; |
350 | self.y += 1; |
351 | } |
352 | let (x: u32, y: u32) = (self.x, self.y); |
353 | self.x += 1; |
354 | self.pixels.next().map(|p: &P| (x, y, p)) |
355 | } |
356 | |
357 | #[inline(always)] |
358 | fn size_hint(&self) -> (usize, Option<usize>) { |
359 | let len: usize = self.len(); |
360 | (len, Some(len)) |
361 | } |
362 | } |
363 | |
364 | impl<'a, P: Pixel + 'a> ExactSizeIterator for EnumeratePixels<'a, P> |
365 | where |
366 | P::Subpixel: 'a, |
367 | { |
368 | fn len(&self) -> usize { |
369 | self.pixels.len() |
370 | } |
371 | } |
372 | |
373 | impl<P: Pixel> Clone for EnumeratePixels<'_, P> { |
374 | fn clone(&self) -> Self { |
375 | EnumeratePixels { |
376 | pixels: self.pixels.clone(), |
377 | ..*self |
378 | } |
379 | } |
380 | } |
381 | |
382 | impl<P: Pixel> fmt::Debug for EnumeratePixels<'_, P> |
383 | where |
384 | P::Subpixel: fmt::Debug, |
385 | { |
386 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
387 | f&mut DebugStruct<'_, '_>.debug_struct("EnumeratePixels") |
388 | .field("pixels", &self.pixels) |
389 | .field("x", &self.x) |
390 | .field("y", &self.y) |
391 | .field(name:"width", &self.width) |
392 | .finish() |
393 | } |
394 | } |
395 | |
396 | /// Enumerate the rows of an image. |
397 | pub struct EnumerateRows<'a, P: Pixel + 'a> |
398 | where |
399 | <P as Pixel>::Subpixel: 'a, |
400 | { |
401 | rows: Rows<'a, P>, |
402 | y: u32, |
403 | width: u32, |
404 | } |
405 | |
406 | impl<'a, P: Pixel + 'a> Iterator for EnumerateRows<'a, P> |
407 | where |
408 | P::Subpixel: 'a, |
409 | { |
410 | type Item = (u32, EnumeratePixels<'a, P>); |
411 | |
412 | #[inline(always)] |
413 | fn next(&mut self) -> Option<(u32, EnumeratePixels<'a, P>)> { |
414 | let y = self.y; |
415 | self.y += 1; |
416 | self.rows.next().map(|r| { |
417 | ( |
418 | y, |
419 | EnumeratePixels { |
420 | x: 0, |
421 | y, |
422 | width: self.width, |
423 | pixels: r, |
424 | }, |
425 | ) |
426 | }) |
427 | } |
428 | |
429 | #[inline(always)] |
430 | fn size_hint(&self) -> (usize, Option<usize>) { |
431 | let len = self.len(); |
432 | (len, Some(len)) |
433 | } |
434 | } |
435 | |
436 | impl<'a, P: Pixel + 'a> ExactSizeIterator for EnumerateRows<'a, P> |
437 | where |
438 | P::Subpixel: 'a, |
439 | { |
440 | fn len(&self) -> usize { |
441 | self.rows.len() |
442 | } |
443 | } |
444 | |
445 | impl<P: Pixel> Clone for EnumerateRows<'_, P> { |
446 | fn clone(&self) -> Self { |
447 | EnumerateRows { |
448 | rows: self.rows.clone(), |
449 | ..*self |
450 | } |
451 | } |
452 | } |
453 | |
454 | impl<P: Pixel> fmt::Debug for EnumerateRows<'_, P> |
455 | where |
456 | P::Subpixel: fmt::Debug, |
457 | { |
458 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
459 | f&mut DebugStruct<'_, '_>.debug_struct("EnumerateRows") |
460 | .field("rows", &self.rows) |
461 | .field("y", &self.y) |
462 | .field(name:"width", &self.width) |
463 | .finish() |
464 | } |
465 | } |
466 | |
467 | /// Enumerate the pixels of an image. |
468 | pub struct EnumeratePixelsMut<'a, P: Pixel + 'a> |
469 | where |
470 | <P as Pixel>::Subpixel: 'a, |
471 | { |
472 | pixels: PixelsMut<'a, P>, |
473 | x: u32, |
474 | y: u32, |
475 | width: u32, |
476 | } |
477 | |
478 | impl<'a, P: Pixel + 'a> Iterator for EnumeratePixelsMut<'a, P> |
479 | where |
480 | P::Subpixel: 'a, |
481 | { |
482 | type Item = (u32, u32, &'a mut P); |
483 | |
484 | #[inline(always)] |
485 | fn next(&mut self) -> Option<(u32, u32, &'a mut P)> { |
486 | if self.x >= self.width { |
487 | self.x = 0; |
488 | self.y += 1; |
489 | } |
490 | let (x: u32, y: u32) = (self.x, self.y); |
491 | self.x += 1; |
492 | self.pixels.next().map(|p: &mut P| (x, y, p)) |
493 | } |
494 | |
495 | #[inline(always)] |
496 | fn size_hint(&self) -> (usize, Option<usize>) { |
497 | let len: usize = self.len(); |
498 | (len, Some(len)) |
499 | } |
500 | } |
501 | |
502 | impl<'a, P: Pixel + 'a> ExactSizeIterator for EnumeratePixelsMut<'a, P> |
503 | where |
504 | P::Subpixel: 'a, |
505 | { |
506 | fn len(&self) -> usize { |
507 | self.pixels.len() |
508 | } |
509 | } |
510 | |
511 | impl<P: Pixel> fmt::Debug for EnumeratePixelsMut<'_, P> |
512 | where |
513 | P::Subpixel: fmt::Debug, |
514 | { |
515 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
516 | f&mut DebugStruct<'_, '_>.debug_struct("EnumeratePixelsMut") |
517 | .field("pixels", &self.pixels) |
518 | .field("x", &self.x) |
519 | .field("y", &self.y) |
520 | .field(name:"width", &self.width) |
521 | .finish() |
522 | } |
523 | } |
524 | |
525 | /// Enumerate the rows of an image. |
526 | pub struct EnumerateRowsMut<'a, P: Pixel + 'a> |
527 | where |
528 | <P as Pixel>::Subpixel: 'a, |
529 | { |
530 | rows: RowsMut<'a, P>, |
531 | y: u32, |
532 | width: u32, |
533 | } |
534 | |
535 | impl<'a, P: Pixel + 'a> Iterator for EnumerateRowsMut<'a, P> |
536 | where |
537 | P::Subpixel: 'a, |
538 | { |
539 | type Item = (u32, EnumeratePixelsMut<'a, P>); |
540 | |
541 | #[inline(always)] |
542 | fn next(&mut self) -> Option<(u32, EnumeratePixelsMut<'a, P>)> { |
543 | let y = self.y; |
544 | self.y += 1; |
545 | self.rows.next().map(|r| { |
546 | ( |
547 | y, |
548 | EnumeratePixelsMut { |
549 | x: 0, |
550 | y, |
551 | width: self.width, |
552 | pixels: r, |
553 | }, |
554 | ) |
555 | }) |
556 | } |
557 | |
558 | #[inline(always)] |
559 | fn size_hint(&self) -> (usize, Option<usize>) { |
560 | let len = self.len(); |
561 | (len, Some(len)) |
562 | } |
563 | } |
564 | |
565 | impl<'a, P: Pixel + 'a> ExactSizeIterator for EnumerateRowsMut<'a, P> |
566 | where |
567 | P::Subpixel: 'a, |
568 | { |
569 | fn len(&self) -> usize { |
570 | self.rows.len() |
571 | } |
572 | } |
573 | |
574 | impl<P: Pixel> fmt::Debug for EnumerateRowsMut<'_, P> |
575 | where |
576 | P::Subpixel: fmt::Debug, |
577 | { |
578 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
579 | f&mut DebugStruct<'_, '_>.debug_struct("EnumerateRowsMut") |
580 | .field("rows", &self.rows) |
581 | .field("y", &self.y) |
582 | .field(name:"width", &self.width) |
583 | .finish() |
584 | } |
585 | } |
586 | |
587 | /// Generic image buffer |
588 | /// |
589 | /// This is an image parameterised by its Pixel types, represented by a width and height and a |
590 | /// container of channel data. It provides direct access to its pixels and implements the |
591 | /// [`GenericImageView`] and [`GenericImage`] traits. In many ways, this is the standard buffer |
592 | /// implementing those traits. Using this concrete type instead of a generic type parameter has |
593 | /// been shown to improve performance. |
594 | /// |
595 | /// The crate defines a few type aliases with regularly used pixel types for your convenience, such |
596 | /// as [`RgbImage`], [`GrayImage`] etc. |
597 | /// |
598 | /// [`GenericImage`]: trait.GenericImage.html |
599 | /// [`GenericImageView`]: trait.GenericImageView.html |
600 | /// [`RgbImage`]: type.RgbImage.html |
601 | /// [`GrayImage`]: type.GrayImage.html |
602 | /// |
603 | /// To convert between images of different Pixel types use [`DynamicImage`]. |
604 | /// |
605 | /// You can retrieve a complete description of the buffer's layout and contents through |
606 | /// [`as_flat_samples`] and [`as_flat_samples_mut`]. This can be handy to also use the contents in |
607 | /// a foreign language, map it as a GPU host buffer or other similar tasks. |
608 | /// |
609 | /// [`DynamicImage`]: enum.DynamicImage.html |
610 | /// [`as_flat_samples`]: #method.as_flat_samples |
611 | /// [`as_flat_samples_mut`]: #method.as_flat_samples_mut |
612 | /// |
613 | /// ## Examples |
614 | /// |
615 | /// Create a simple canvas and paint a small cross. |
616 | /// |
617 | /// ``` |
618 | /// use image::{RgbImage, Rgb}; |
619 | /// |
620 | /// let mut img = RgbImage::new(32, 32); |
621 | /// |
622 | /// for x in 15..=17 { |
623 | /// for y in 8..24 { |
624 | /// img.put_pixel(x, y, Rgb([255, 0, 0])); |
625 | /// img.put_pixel(y, x, Rgb([255, 0, 0])); |
626 | /// } |
627 | /// } |
628 | /// ``` |
629 | /// |
630 | /// Overlays an image on top of a larger background raster. |
631 | /// |
632 | /// ```no_run |
633 | /// use image::{GenericImage, GenericImageView, ImageBuffer, open}; |
634 | /// |
635 | /// let on_top = open("path/to/some.png").unwrap().into_rgb8(); |
636 | /// let mut img = ImageBuffer::from_fn(512, 512, |x, y| { |
637 | /// if (x + y) % 2 == 0 { |
638 | /// image::Rgb([0, 0, 0]) |
639 | /// } else { |
640 | /// image::Rgb([255, 255, 255]) |
641 | /// } |
642 | /// }); |
643 | /// |
644 | /// image::imageops::overlay(&mut img, &on_top, 128, 128); |
645 | /// ``` |
646 | /// |
647 | /// Convert an RgbaImage to a GrayImage. |
648 | /// |
649 | /// ```no_run |
650 | /// use image::{open, DynamicImage}; |
651 | /// |
652 | /// let rgba = open("path/to/some.png").unwrap().into_rgba8(); |
653 | /// let gray = DynamicImage::ImageRgba8(rgba).into_luma8(); |
654 | /// ``` |
655 | #[derive(Debug, Hash, PartialEq, Eq)] |
656 | pub struct ImageBuffer<P: Pixel, Container> { |
657 | width: u32, |
658 | height: u32, |
659 | _phantom: PhantomData<P>, |
660 | data: Container, |
661 | } |
662 | |
663 | // generic implementation, shared along all image buffers |
664 | impl<P, Container> ImageBuffer<P, Container> |
665 | where |
666 | P: Pixel, |
667 | Container: Deref<Target = [P::Subpixel]>, |
668 | { |
669 | /// Constructs a buffer from a generic container |
670 | /// (for example a `Vec` or a slice) |
671 | /// |
672 | /// Returns `None` if the container is not big enough (including when the image dimensions |
673 | /// necessitate an allocation of more bytes than supported by the container). |
674 | pub fn from_raw(width: u32, height: u32, buf: Container) -> Option<ImageBuffer<P, Container>> { |
675 | if Self::check_image_fits(width, height, buf.len()) { |
676 | Some(ImageBuffer { |
677 | data: buf, |
678 | width, |
679 | height, |
680 | _phantom: PhantomData, |
681 | }) |
682 | } else { |
683 | None |
684 | } |
685 | } |
686 | |
687 | /// Returns the underlying raw buffer |
688 | pub fn into_raw(self) -> Container { |
689 | self.data |
690 | } |
691 | |
692 | /// Returns the underlying raw buffer |
693 | pub fn as_raw(&self) -> &Container { |
694 | &self.data |
695 | } |
696 | |
697 | /// The width and height of this image. |
698 | pub fn dimensions(&self) -> (u32, u32) { |
699 | (self.width, self.height) |
700 | } |
701 | |
702 | /// The width of this image. |
703 | pub fn width(&self) -> u32 { |
704 | self.width |
705 | } |
706 | |
707 | /// The height of this image. |
708 | pub fn height(&self) -> u32 { |
709 | self.height |
710 | } |
711 | |
712 | // TODO: choose name under which to expose. |
713 | pub(crate) fn inner_pixels(&self) -> &[P::Subpixel] { |
714 | let len = Self::image_buffer_len(self.width, self.height).unwrap(); |
715 | &self.data[..len] |
716 | } |
717 | |
718 | /// Returns an iterator over the pixels of this image. |
719 | /// The iteration order is x = 0 to width then y = 0 to height |
720 | pub fn pixels(&self) -> Pixels<P> { |
721 | Pixels { |
722 | chunks: self |
723 | .inner_pixels() |
724 | .chunks_exact(<P as Pixel>::CHANNEL_COUNT as usize), |
725 | } |
726 | } |
727 | |
728 | /// Returns an iterator over the rows of this image. |
729 | /// |
730 | /// Only non-empty rows can be iterated in this manner. In particular the iterator will not |
731 | /// yield any item when the width of the image is `0` or a pixel type without any channels is |
732 | /// used. This ensures that its length can always be represented by `usize`. |
733 | pub fn rows(&self) -> Rows<P> { |
734 | Rows::with_image(&self.data, self.width, self.height) |
735 | } |
736 | |
737 | /// Enumerates over the pixels of the image. |
738 | /// The iterator yields the coordinates of each pixel |
739 | /// along with a reference to them. |
740 | /// The iteration order is x = 0 to width then y = 0 to height |
741 | /// Starting from the top left. |
742 | pub fn enumerate_pixels(&self) -> EnumeratePixels<P> { |
743 | EnumeratePixels { |
744 | pixels: self.pixels(), |
745 | x: 0, |
746 | y: 0, |
747 | width: self.width, |
748 | } |
749 | } |
750 | |
751 | /// Enumerates over the rows of the image. |
752 | /// The iterator yields the y-coordinate of each row |
753 | /// along with a reference to them. |
754 | pub fn enumerate_rows(&self) -> EnumerateRows<P> { |
755 | EnumerateRows { |
756 | rows: self.rows(), |
757 | y: 0, |
758 | width: self.width, |
759 | } |
760 | } |
761 | |
762 | /// Gets a reference to the pixel at location `(x, y)` |
763 | /// |
764 | /// # Panics |
765 | /// |
766 | /// Panics if `(x, y)` is out of the bounds `(width, height)`. |
767 | #[inline] |
768 | #[track_caller] |
769 | pub fn get_pixel(&self, x: u32, y: u32) -> &P { |
770 | match self.pixel_indices(x, y) { |
771 | None => panic!( |
772 | "Image index{:?} out of bounds{:?} ", |
773 | (x, y), |
774 | (self.width, self.height) |
775 | ), |
776 | Some(pixel_indices) => <P as Pixel>::from_slice(&self.data[pixel_indices]), |
777 | } |
778 | } |
779 | |
780 | /// Gets a reference to the pixel at location `(x, y)` or returns `None` if |
781 | /// the index is out of the bounds `(width, height)`. |
782 | pub fn get_pixel_checked(&self, x: u32, y: u32) -> Option<&P> { |
783 | if x >= self.width { |
784 | return None; |
785 | } |
786 | let num_channels = <P as Pixel>::CHANNEL_COUNT as usize; |
787 | let i = (y as usize) |
788 | .saturating_mul(self.width as usize) |
789 | .saturating_add(x as usize) |
790 | .saturating_mul(num_channels); |
791 | |
792 | self.data |
793 | .get(i..i.checked_add(num_channels)?) |
794 | .map(|pixel_indices| <P as Pixel>::from_slice(pixel_indices)) |
795 | } |
796 | |
797 | /// Test that the image fits inside the buffer. |
798 | /// |
799 | /// Verifies that the maximum image of pixels inside the bounds is smaller than the provided |
800 | /// length. Note that as a corrolary we also have that the index calculation of pixels inside |
801 | /// the bounds will not overflow. |
802 | fn check_image_fits(width: u32, height: u32, len: usize) -> bool { |
803 | let checked_len = Self::image_buffer_len(width, height); |
804 | checked_len.map(|min_len| min_len <= len).unwrap_or(false) |
805 | } |
806 | |
807 | fn image_buffer_len(width: u32, height: u32) -> Option<usize> { |
808 | Some(<P as Pixel>::CHANNEL_COUNT as usize) |
809 | .and_then(|size| size.checked_mul(width as usize)) |
810 | .and_then(|size| size.checked_mul(height as usize)) |
811 | } |
812 | |
813 | #[inline(always)] |
814 | fn pixel_indices(&self, x: u32, y: u32) -> Option<Range<usize>> { |
815 | if x >= self.width || y >= self.height { |
816 | return None; |
817 | } |
818 | |
819 | Some(self.pixel_indices_unchecked(x, y)) |
820 | } |
821 | |
822 | #[inline(always)] |
823 | fn pixel_indices_unchecked(&self, x: u32, y: u32) -> Range<usize> { |
824 | let no_channels = <P as Pixel>::CHANNEL_COUNT as usize; |
825 | // If in bounds, this can't overflow as we have tested that at construction! |
826 | let min_index = (y as usize * self.width as usize + x as usize) * no_channels; |
827 | min_index..min_index + no_channels |
828 | } |
829 | |
830 | /// Get the format of the buffer when viewed as a matrix of samples. |
831 | pub fn sample_layout(&self) -> SampleLayout { |
832 | // None of these can overflow, as all our memory is addressable. |
833 | SampleLayout::row_major_packed(<P as Pixel>::CHANNEL_COUNT, self.width, self.height) |
834 | } |
835 | |
836 | /// Return the raw sample buffer with its stride an dimension information. |
837 | /// |
838 | /// The returned buffer is guaranteed to be well formed in all cases. It is laid out by |
839 | /// colors, width then height, meaning `channel_stride <= width_stride <= height_stride`. All |
840 | /// strides are in numbers of elements but those are mostly `u8` in which case the strides are |
841 | /// also byte strides. |
842 | pub fn into_flat_samples(self) -> FlatSamples<Container> |
843 | where |
844 | Container: AsRef<[P::Subpixel]>, |
845 | { |
846 | // None of these can overflow, as all our memory is addressable. |
847 | let layout = self.sample_layout(); |
848 | FlatSamples { |
849 | samples: self.data, |
850 | layout, |
851 | color_hint: None, // TODO: the pixel type might contain P::COLOR_TYPE if it satisfies PixelWithColorType |
852 | } |
853 | } |
854 | |
855 | /// Return a view on the raw sample buffer. |
856 | /// |
857 | /// See [`into_flat_samples`](#method.into_flat_samples) for more details. |
858 | pub fn as_flat_samples(&self) -> FlatSamples<&[P::Subpixel]> |
859 | where |
860 | Container: AsRef<[P::Subpixel]>, |
861 | { |
862 | let layout = self.sample_layout(); |
863 | FlatSamples { |
864 | samples: self.data.as_ref(), |
865 | layout, |
866 | color_hint: None, // TODO: the pixel type might contain P::COLOR_TYPE if it satisfies PixelWithColorType |
867 | } |
868 | } |
869 | |
870 | /// Return a mutable view on the raw sample buffer. |
871 | /// |
872 | /// See [`into_flat_samples`](#method.into_flat_samples) for more details. |
873 | pub fn as_flat_samples_mut(&mut self) -> FlatSamples<&mut [P::Subpixel]> |
874 | where |
875 | Container: AsMut<[P::Subpixel]>, |
876 | { |
877 | let layout = self.sample_layout(); |
878 | FlatSamples { |
879 | samples: self.data.as_mut(), |
880 | layout, |
881 | color_hint: None, // TODO: the pixel type might contain P::COLOR_TYPE if it satisfies PixelWithColorType |
882 | } |
883 | } |
884 | } |
885 | |
886 | impl<P, Container> ImageBuffer<P, Container> |
887 | where |
888 | P: Pixel, |
889 | Container: Deref<Target = [P::Subpixel]> + DerefMut, |
890 | { |
891 | // TODO: choose name under which to expose. |
892 | pub(crate) fn inner_pixels_mut(&mut self) -> &mut [P::Subpixel] { |
893 | let len = Self::image_buffer_len(self.width, self.height).unwrap(); |
894 | &mut self.data[..len] |
895 | } |
896 | |
897 | /// Returns an iterator over the mutable pixels of this image. |
898 | pub fn pixels_mut(&mut self) -> PixelsMut<P> { |
899 | PixelsMut { |
900 | chunks: self |
901 | .inner_pixels_mut() |
902 | .chunks_exact_mut(<P as Pixel>::CHANNEL_COUNT as usize), |
903 | } |
904 | } |
905 | |
906 | /// Returns an iterator over the mutable rows of this image. |
907 | /// |
908 | /// Only non-empty rows can be iterated in this manner. In particular the iterator will not |
909 | /// yield any item when the width of the image is `0` or a pixel type without any channels is |
910 | /// used. This ensures that its length can always be represented by `usize`. |
911 | pub fn rows_mut(&mut self) -> RowsMut<P> { |
912 | RowsMut::with_image(&mut self.data, self.width, self.height) |
913 | } |
914 | |
915 | /// Enumerates over the pixels of the image. |
916 | /// The iterator yields the coordinates of each pixel |
917 | /// along with a mutable reference to them. |
918 | pub fn enumerate_pixels_mut(&mut self) -> EnumeratePixelsMut<P> { |
919 | let width = self.width; |
920 | EnumeratePixelsMut { |
921 | pixels: self.pixels_mut(), |
922 | x: 0, |
923 | y: 0, |
924 | width, |
925 | } |
926 | } |
927 | |
928 | /// Enumerates over the rows of the image. |
929 | /// The iterator yields the y-coordinate of each row |
930 | /// along with a mutable reference to them. |
931 | pub fn enumerate_rows_mut(&mut self) -> EnumerateRowsMut<P> { |
932 | let width = self.width; |
933 | EnumerateRowsMut { |
934 | rows: self.rows_mut(), |
935 | y: 0, |
936 | width, |
937 | } |
938 | } |
939 | |
940 | /// Gets a reference to the mutable pixel at location `(x, y)` |
941 | /// |
942 | /// # Panics |
943 | /// |
944 | /// Panics if `(x, y)` is out of the bounds `(width, height)`. |
945 | #[inline] |
946 | #[track_caller] |
947 | pub fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut P { |
948 | match self.pixel_indices(x, y) { |
949 | None => panic!( |
950 | "Image index{:?} out of bounds{:?} ", |
951 | (x, y), |
952 | (self.width, self.height) |
953 | ), |
954 | Some(pixel_indices) => <P as Pixel>::from_slice_mut(&mut self.data[pixel_indices]), |
955 | } |
956 | } |
957 | |
958 | /// Gets a reference to the mutable pixel at location `(x, y)` or returns |
959 | /// `None` if the index is out of the bounds `(width, height)`. |
960 | pub fn get_pixel_mut_checked(&mut self, x: u32, y: u32) -> Option<&mut P> { |
961 | if x >= self.width { |
962 | return None; |
963 | } |
964 | let num_channels = <P as Pixel>::CHANNEL_COUNT as usize; |
965 | let i = (y as usize) |
966 | .saturating_mul(self.width as usize) |
967 | .saturating_add(x as usize) |
968 | .saturating_mul(num_channels); |
969 | |
970 | self.data |
971 | .get_mut(i..i.checked_add(num_channels)?) |
972 | .map(|pixel_indices| <P as Pixel>::from_slice_mut(pixel_indices)) |
973 | } |
974 | |
975 | /// Puts a pixel at location `(x, y)` |
976 | /// |
977 | /// # Panics |
978 | /// |
979 | /// Panics if `(x, y)` is out of the bounds `(width, height)`. |
980 | #[inline] |
981 | #[track_caller] |
982 | pub fn put_pixel(&mut self, x: u32, y: u32, pixel: P) { |
983 | *self.get_pixel_mut(x, y) = pixel |
984 | } |
985 | } |
986 | |
987 | impl<P, Container> ImageBuffer<P, Container> |
988 | where |
989 | P: Pixel, |
990 | [P::Subpixel]: EncodableLayout, |
991 | Container: Deref<Target = [P::Subpixel]>, |
992 | { |
993 | /// Saves the buffer to a file at the path specified. |
994 | /// |
995 | /// The image format is derived from the file extension. |
996 | pub fn save<Q>(&self, path: Q) -> ImageResult<()> |
997 | where |
998 | Q: AsRef<Path>, |
999 | P: PixelWithColorType, |
1000 | { |
1001 | save_buffer( |
1002 | path, |
1003 | self.inner_pixels().as_bytes(), |
1004 | self.width(), |
1005 | self.height(), |
1006 | <P as PixelWithColorType>::COLOR_TYPE, |
1007 | ) |
1008 | } |
1009 | } |
1010 | |
1011 | impl<P, Container> ImageBuffer<P, Container> |
1012 | where |
1013 | P: Pixel, |
1014 | [P::Subpixel]: EncodableLayout, |
1015 | Container: Deref<Target = [P::Subpixel]>, |
1016 | { |
1017 | /// Saves the buffer to a file at the specified path in |
1018 | /// the specified format. |
1019 | /// |
1020 | /// See [`save_buffer_with_format`](fn.save_buffer_with_format.html) for |
1021 | /// supported types. |
1022 | pub fn save_with_format<Q>(&self, path: Q, format: ImageFormat) -> ImageResult<()> |
1023 | where |
1024 | Q: AsRef<Path>, |
1025 | P: PixelWithColorType, |
1026 | { |
1027 | // This is valid as the subpixel is u8. |
1028 | save_buffer_with_format( |
1029 | path, |
1030 | self.inner_pixels().as_bytes(), |
1031 | self.width(), |
1032 | self.height(), |
1033 | <P as PixelWithColorType>::COLOR_TYPE, |
1034 | format, |
1035 | ) |
1036 | } |
1037 | } |
1038 | |
1039 | impl<P, Container> ImageBuffer<P, Container> |
1040 | where |
1041 | P: Pixel, |
1042 | [P::Subpixel]: EncodableLayout, |
1043 | Container: Deref<Target = [P::Subpixel]>, |
1044 | { |
1045 | /// Writes the buffer to a writer in the specified format. |
1046 | /// |
1047 | /// Assumes the writer is buffered. In most cases, |
1048 | /// you should wrap your writer in a `BufWriter` for best performance. |
1049 | /// |
1050 | /// See [`ImageOutputFormat`](enum.ImageOutputFormat.html) for |
1051 | /// supported types. |
1052 | pub fn write_to<W, F>(&self, writer: &mut W, format: F) -> ImageResult<()> |
1053 | where |
1054 | W: std::io::Write + std::io::Seek, |
1055 | F: Into<ImageOutputFormat>, |
1056 | P: PixelWithColorType, |
1057 | { |
1058 | // This is valid as the subpixel is u8. |
1059 | write_buffer_with_format( |
1060 | writer, |
1061 | self.inner_pixels().as_bytes(), |
1062 | self.width(), |
1063 | self.height(), |
1064 | <P as PixelWithColorType>::COLOR_TYPE, |
1065 | format, |
1066 | ) |
1067 | } |
1068 | } |
1069 | |
1070 | impl<P, Container> ImageBuffer<P, Container> |
1071 | where |
1072 | P: Pixel, |
1073 | [P::Subpixel]: EncodableLayout, |
1074 | Container: Deref<Target = [P::Subpixel]>, |
1075 | { |
1076 | /// Writes the buffer with the given encoder. |
1077 | pub fn write_with_encoder<E>(&self, encoder: E) -> ImageResult<()> |
1078 | where |
1079 | E: ImageEncoder, |
1080 | P: PixelWithColorType, |
1081 | { |
1082 | // This is valid as the subpixel is u8. |
1083 | encoder.write_image( |
1084 | self.inner_pixels().as_bytes(), |
1085 | self.width(), |
1086 | self.height(), |
1087 | <P as PixelWithColorType>::COLOR_TYPE, |
1088 | ) |
1089 | } |
1090 | } |
1091 | |
1092 | impl<P, Container> Default for ImageBuffer<P, Container> |
1093 | where |
1094 | P: Pixel, |
1095 | Container: Default, |
1096 | { |
1097 | fn default() -> Self { |
1098 | Self { |
1099 | width: 0, |
1100 | height: 0, |
1101 | _phantom: PhantomData, |
1102 | data: Default::default(), |
1103 | } |
1104 | } |
1105 | } |
1106 | |
1107 | impl<P, Container> Deref for ImageBuffer<P, Container> |
1108 | where |
1109 | P: Pixel, |
1110 | Container: Deref<Target = [P::Subpixel]>, |
1111 | { |
1112 | type Target = [P::Subpixel]; |
1113 | |
1114 | fn deref(&self) -> &<Self as Deref>::Target { |
1115 | &self.data |
1116 | } |
1117 | } |
1118 | |
1119 | impl<P, Container> DerefMut for ImageBuffer<P, Container> |
1120 | where |
1121 | P: Pixel, |
1122 | Container: Deref<Target = [P::Subpixel]> + DerefMut, |
1123 | { |
1124 | fn deref_mut(&mut self) -> &mut <Self as Deref>::Target { |
1125 | &mut self.data |
1126 | } |
1127 | } |
1128 | |
1129 | impl<P, Container> Index<(u32, u32)> for ImageBuffer<P, Container> |
1130 | where |
1131 | P: Pixel, |
1132 | Container: Deref<Target = [P::Subpixel]>, |
1133 | { |
1134 | type Output = P; |
1135 | |
1136 | fn index(&self, (x: u32, y: u32): (u32, u32)) -> &P { |
1137 | self.get_pixel(x, y) |
1138 | } |
1139 | } |
1140 | |
1141 | impl<P, Container> IndexMut<(u32, u32)> for ImageBuffer<P, Container> |
1142 | where |
1143 | P: Pixel, |
1144 | Container: Deref<Target = [P::Subpixel]> + DerefMut, |
1145 | { |
1146 | fn index_mut(&mut self, (x: u32, y: u32): (u32, u32)) -> &mut P { |
1147 | self.get_pixel_mut(x, y) |
1148 | } |
1149 | } |
1150 | |
1151 | impl<P, Container> Clone for ImageBuffer<P, Container> |
1152 | where |
1153 | P: Pixel, |
1154 | Container: Deref<Target = [P::Subpixel]> + Clone, |
1155 | { |
1156 | fn clone(&self) -> ImageBuffer<P, Container> { |
1157 | ImageBuffer { |
1158 | data: self.data.clone(), |
1159 | width: self.width, |
1160 | height: self.height, |
1161 | _phantom: PhantomData, |
1162 | } |
1163 | } |
1164 | } |
1165 | |
1166 | impl<P, Container> GenericImageView for ImageBuffer<P, Container> |
1167 | where |
1168 | P: Pixel, |
1169 | Container: Deref<Target = [P::Subpixel]> + Deref, |
1170 | { |
1171 | type Pixel = P; |
1172 | |
1173 | fn dimensions(&self) -> (u32, u32) { |
1174 | self.dimensions() |
1175 | } |
1176 | |
1177 | fn bounds(&self) -> (u32, u32, u32, u32) { |
1178 | (0, 0, self.width, self.height) |
1179 | } |
1180 | |
1181 | fn get_pixel(&self, x: u32, y: u32) -> P { |
1182 | *self.get_pixel(x, y) |
1183 | } |
1184 | |
1185 | /// Returns the pixel located at (x, y), ignoring bounds checking. |
1186 | #[inline(always)] |
1187 | unsafe fn unsafe_get_pixel(&self, x: u32, y: u32) -> P { |
1188 | let indices: Range |
1189 | *<P as Pixel>::from_slice(self.data.get_unchecked(index:indices)) |
1190 | } |
1191 | } |
1192 | |
1193 | impl<P, Container> GenericImage for ImageBuffer<P, Container> |
1194 | where |
1195 | P: Pixel, |
1196 | Container: Deref<Target = [P::Subpixel]> + DerefMut, |
1197 | { |
1198 | fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut P { |
1199 | self.get_pixel_mut(x, y) |
1200 | } |
1201 | |
1202 | fn put_pixel(&mut self, x: u32, y: u32, pixel: P) { |
1203 | *self.get_pixel_mut(x, y) = pixel |
1204 | } |
1205 | |
1206 | /// Puts a pixel at location (x, y), ignoring bounds checking. |
1207 | #[inline(always)] |
1208 | unsafe fn unsafe_put_pixel(&mut self, x: u32, y: u32, pixel: P) { |
1209 | let indices = self.pixel_indices_unchecked(x, y); |
1210 | let p = <P as Pixel>::from_slice_mut(self.data.get_unchecked_mut(indices)); |
1211 | *p = pixel |
1212 | } |
1213 | |
1214 | /// Put a pixel at location (x, y), taking into account alpha channels |
1215 | /// |
1216 | /// DEPRECATED: This method will be removed. Blend the pixel directly instead. |
1217 | fn blend_pixel(&mut self, x: u32, y: u32, p: P) { |
1218 | self.get_pixel_mut(x, y).blend(&p) |
1219 | } |
1220 | |
1221 | fn copy_within(&mut self, source: Rect, x: u32, y: u32) -> bool { |
1222 | let Rect { |
1223 | x: sx, |
1224 | y: sy, |
1225 | width, |
1226 | height, |
1227 | } = source; |
1228 | let dx = x; |
1229 | let dy = y; |
1230 | assert!(sx < self.width() && dx < self.width()); |
1231 | assert!(sy < self.height() && dy < self.height()); |
1232 | if self.width() - dx.max(sx) < width || self.height() - dy.max(sy) < height { |
1233 | return false; |
1234 | } |
1235 | |
1236 | if sy < dy { |
1237 | for y in (0..height).rev() { |
1238 | let sy = sy + y; |
1239 | let dy = dy + y; |
1240 | let Range { start, .. } = self.pixel_indices_unchecked(sx, sy); |
1241 | let Range { end, .. } = self.pixel_indices_unchecked(sx + width - 1, sy); |
1242 | let dst = self.pixel_indices_unchecked(dx, dy).start; |
1243 | self.data.copy_within(start..end, dst); |
1244 | } |
1245 | } else { |
1246 | for y in 0..height { |
1247 | let sy = sy + y; |
1248 | let dy = dy + y; |
1249 | let Range { start, .. } = self.pixel_indices_unchecked(sx, sy); |
1250 | let Range { end, .. } = self.pixel_indices_unchecked(sx + width - 1, sy); |
1251 | let dst = self.pixel_indices_unchecked(dx, dy).start; |
1252 | self.data.copy_within(start..end, dst); |
1253 | } |
1254 | } |
1255 | true |
1256 | } |
1257 | } |
1258 | |
1259 | // concrete implementation for `Vec`-backed buffers |
1260 | // TODO: I think that rustc does not "see" this impl any more: the impl with |
1261 | // Container meets the same requirements. At least, I got compile errors that |
1262 | // there is no such function as `into_vec`, whereas `into_raw` did work, and |
1263 | // `into_vec` is redundant anyway, because `into_raw` will give you the vector, |
1264 | // and it is more generic. |
1265 | impl<P: Pixel> ImageBuffer<P, Vec<P::Subpixel>> { |
1266 | /// Creates a new image buffer based on a `Vec<P::Subpixel>`. |
1267 | /// |
1268 | /// # Panics |
1269 | /// |
1270 | /// Panics when the resulting image is larger than the maximum size of a vector. |
1271 | pub fn new(width: u32, height: u32) -> ImageBuffer<P, Vec<P::Subpixel>> { |
1272 | let size = Self::image_buffer_len(width, height) |
1273 | .expect("Buffer length in `ImageBuffer::new` overflows usize"); |
1274 | ImageBuffer { |
1275 | data: vec![Zero::zero(); size], |
1276 | width, |
1277 | height, |
1278 | _phantom: PhantomData, |
1279 | } |
1280 | } |
1281 | |
1282 | /// Constructs a new ImageBuffer by copying a pixel |
1283 | /// |
1284 | /// # Panics |
1285 | /// |
1286 | /// Panics when the resulting image is larger the the maximum size of a vector. |
1287 | pub fn from_pixel(width: u32, height: u32, pixel: P) -> ImageBuffer<P, Vec<P::Subpixel>> { |
1288 | let mut buf = ImageBuffer::new(width, height); |
1289 | for p in buf.pixels_mut() { |
1290 | *p = pixel |
1291 | } |
1292 | buf |
1293 | } |
1294 | |
1295 | /// Constructs a new ImageBuffer by repeated application of the supplied function. |
1296 | /// |
1297 | /// The arguments to the function are the pixel's x and y coordinates. |
1298 | /// |
1299 | /// # Panics |
1300 | /// |
1301 | /// Panics when the resulting image is larger the the maximum size of a vector. |
1302 | pub fn from_fn<F>(width: u32, height: u32, mut f: F) -> ImageBuffer<P, Vec<P::Subpixel>> |
1303 | where |
1304 | F: FnMut(u32, u32) -> P, |
1305 | { |
1306 | let mut buf = ImageBuffer::new(width, height); |
1307 | for (x, y, p) in buf.enumerate_pixels_mut() { |
1308 | *p = f(x, y) |
1309 | } |
1310 | buf |
1311 | } |
1312 | |
1313 | /// Creates an image buffer out of an existing buffer. |
1314 | /// Returns None if the buffer is not big enough. |
1315 | pub fn from_vec( |
1316 | width: u32, |
1317 | height: u32, |
1318 | buf: Vec<P::Subpixel>, |
1319 | ) -> Option<ImageBuffer<P, Vec<P::Subpixel>>> { |
1320 | ImageBuffer::from_raw(width, height, buf) |
1321 | } |
1322 | |
1323 | /// Consumes the image buffer and returns the underlying data |
1324 | /// as an owned buffer |
1325 | pub fn into_vec(self) -> Vec<P::Subpixel> { |
1326 | self.into_raw() |
1327 | } |
1328 | } |
1329 | |
1330 | /// Provides color conversions for whole image buffers. |
1331 | pub trait ConvertBuffer<T> { |
1332 | /// Converts `self` to a buffer of type T |
1333 | /// |
1334 | /// A generic implementation is provided to convert any image buffer to a image buffer |
1335 | /// based on a `Vec<T>`. |
1336 | fn convert(&self) -> T; |
1337 | } |
1338 | |
1339 | // concrete implementation Luma -> Rgba |
1340 | impl GrayImage { |
1341 | /// Expands a color palette by re-using the existing buffer. |
1342 | /// Assumes 8 bit per pixel. Uses an optionally transparent index to |
1343 | /// adjust it's alpha value accordingly. |
1344 | pub fn expand_palette( |
1345 | self, |
1346 | palette: &[(u8, u8, u8)], |
1347 | transparent_idx: Option<u8>, |
1348 | ) -> RgbaImage { |
1349 | let (width, height) = self.dimensions(); |
1350 | let mut data = self.into_raw(); |
1351 | let entries = data.len(); |
1352 | data.resize(entries.checked_mul(4).unwrap(), 0); |
1353 | let mut buffer = ImageBuffer::from_vec(width, height, data).unwrap(); |
1354 | expand_packed(&mut buffer, 4, 8, |idx, pixel| { |
1355 | let (r, g, b) = palette[idx as usize]; |
1356 | let a = if let Some(t_idx) = transparent_idx { |
1357 | if t_idx == idx { |
1358 | 0 |
1359 | } else { |
1360 | 255 |
1361 | } |
1362 | } else { |
1363 | 255 |
1364 | }; |
1365 | pixel[0] = r; |
1366 | pixel[1] = g; |
1367 | pixel[2] = b; |
1368 | pixel[3] = a; |
1369 | }); |
1370 | buffer |
1371 | } |
1372 | } |
1373 | |
1374 | // TODO: Equality constraints are not yet supported in where clauses, when they |
1375 | // are, the T parameter should be removed in favor of ToType::Subpixel, which |
1376 | // will then be FromType::Subpixel. |
1377 | impl<Container, FromType: Pixel, ToType: Pixel> |
1378 | ConvertBuffer<ImageBuffer<ToType, Vec<ToType::Subpixel>>> for ImageBuffer<FromType, Container> |
1379 | where |
1380 | Container: Deref<Target = [FromType::Subpixel]>, |
1381 | ToType: FromColor<FromType>, |
1382 | { |
1383 | /// # Examples |
1384 | /// Convert RGB image to gray image. |
1385 | /// ```no_run |
1386 | /// use image::buffer::ConvertBuffer; |
1387 | /// use image::GrayImage; |
1388 | /// |
1389 | /// let image_path = "examples/fractal.png"; |
1390 | /// let image = image::open(&image_path) |
1391 | /// .expect("Open file failed") |
1392 | /// .to_rgba8(); |
1393 | /// |
1394 | /// let gray_image: GrayImage = image.convert(); |
1395 | /// ``` |
1396 | fn convert(&self) -> ImageBuffer<ToType, Vec<ToType::Subpixel>> { |
1397 | let mut buffer: ImageBuffer<ToType, Vec<ToType::Subpixel>> = |
1398 | ImageBuffer::new(self.width, self.height); |
1399 | for (to: &mut ToType, from: &FromType) in buffer.pixels_mut().zip(self.pixels()) { |
1400 | to.from_color(from) |
1401 | } |
1402 | buffer |
1403 | } |
1404 | } |
1405 | |
1406 | /// Sendable Rgb image buffer |
1407 | pub type RgbImage = ImageBuffer<Rgb<u8>, Vec<u8>>; |
1408 | /// Sendable Rgb + alpha channel image buffer |
1409 | pub type RgbaImage = ImageBuffer<Rgba<u8>, Vec<u8>>; |
1410 | /// Sendable grayscale image buffer |
1411 | pub type GrayImage = ImageBuffer<Luma<u8>, Vec<u8>>; |
1412 | /// Sendable grayscale + alpha channel image buffer |
1413 | pub type GrayAlphaImage = ImageBuffer<LumaA<u8>, Vec<u8>>; |
1414 | /// Sendable 16-bit Rgb image buffer |
1415 | pub(crate) type Rgb16Image = ImageBuffer<Rgb<u16>, Vec<u16>>; |
1416 | /// Sendable 16-bit Rgb + alpha channel image buffer |
1417 | pub(crate) type Rgba16Image = ImageBuffer<Rgba<u16>, Vec<u16>>; |
1418 | /// Sendable 16-bit grayscale image buffer |
1419 | pub(crate) type Gray16Image = ImageBuffer<Luma<u16>, Vec<u16>>; |
1420 | /// Sendable 16-bit grayscale + alpha channel image buffer |
1421 | pub(crate) type GrayAlpha16Image = ImageBuffer<LumaA<u16>, Vec<u16>>; |
1422 | |
1423 | /// An image buffer for 32-bit float RGB pixels, |
1424 | /// where the backing container is a flattened vector of floats. |
1425 | pub type Rgb32FImage = ImageBuffer<Rgb<f32>, Vec<f32>>; |
1426 | |
1427 | /// An image buffer for 32-bit float RGBA pixels, |
1428 | /// where the backing container is a flattened vector of floats. |
1429 | pub type Rgba32FImage = ImageBuffer<Rgba<f32>, Vec<f32>>; |
1430 | |
1431 | impl From<DynamicImage> for RgbImage { |
1432 | fn from(value: DynamicImage) -> Self { |
1433 | value.into_rgb8() |
1434 | } |
1435 | } |
1436 | |
1437 | impl From<DynamicImage> for RgbaImage { |
1438 | fn from(value: DynamicImage) -> Self { |
1439 | value.into_rgba8() |
1440 | } |
1441 | } |
1442 | |
1443 | impl From<DynamicImage> for GrayImage { |
1444 | fn from(value: DynamicImage) -> Self { |
1445 | value.into_luma8() |
1446 | } |
1447 | } |
1448 | |
1449 | impl From<DynamicImage> for GrayAlphaImage { |
1450 | fn from(value: DynamicImage) -> Self { |
1451 | value.into_luma_alpha8() |
1452 | } |
1453 | } |
1454 | |
1455 | impl From<DynamicImage> for Rgb16Image { |
1456 | fn from(value: DynamicImage) -> Self { |
1457 | value.into_rgb16() |
1458 | } |
1459 | } |
1460 | |
1461 | impl From<DynamicImage> for Rgba16Image { |
1462 | fn from(value: DynamicImage) -> Self { |
1463 | value.into_rgba16() |
1464 | } |
1465 | } |
1466 | |
1467 | impl From<DynamicImage> for Gray16Image { |
1468 | fn from(value: DynamicImage) -> Self { |
1469 | value.into_luma16() |
1470 | } |
1471 | } |
1472 | |
1473 | impl From<DynamicImage> for GrayAlpha16Image { |
1474 | fn from(value: DynamicImage) -> Self { |
1475 | value.into_luma_alpha16() |
1476 | } |
1477 | } |
1478 | |
1479 | impl From<DynamicImage> for Rgba32FImage { |
1480 | fn from(value: DynamicImage) -> Self { |
1481 | value.into_rgba32f() |
1482 | } |
1483 | } |
1484 | |
1485 | #[cfg(test)] |
1486 | mod test { |
1487 | use super::{GrayImage, ImageBuffer, ImageOutputFormat, RgbImage}; |
1488 | use crate::math::Rect; |
1489 | use crate::GenericImage as _; |
1490 | use crate::{color, Rgb}; |
1491 | |
1492 | #[test] |
1493 | /// Tests if image buffers from slices work |
1494 | fn slice_buffer() { |
1495 | let data = [0; 9]; |
1496 | let buf: ImageBuffer<color::Luma<u8>, _> = ImageBuffer::from_raw(3, 3, &data[..]).unwrap(); |
1497 | assert_eq!(&*buf, &data[..]) |
1498 | } |
1499 | |
1500 | #[test] |
1501 | fn get_pixel() { |
1502 | let mut a: RgbImage = ImageBuffer::new(10, 10); |
1503 | { |
1504 | let b = a.get_mut(3 * 10).unwrap(); |
1505 | *b = 255; |
1506 | } |
1507 | assert_eq!(a.get_pixel(0, 1)[0], 255) |
1508 | } |
1509 | |
1510 | #[test] |
1511 | fn get_pixel_checked() { |
1512 | let mut a: RgbImage = ImageBuffer::new(10, 10); |
1513 | a.get_pixel_mut_checked(0, 1).unwrap()[0] = 255; |
1514 | |
1515 | assert_eq!(a.get_pixel_checked(0, 1), Some(&Rgb([255, 0, 0]))); |
1516 | assert_eq!(a.get_pixel_checked(0, 1).unwrap(), a.get_pixel(0, 1)); |
1517 | assert_eq!(a.get_pixel_checked(10, 0), None); |
1518 | assert_eq!(a.get_pixel_checked(0, 10), None); |
1519 | assert_eq!(a.get_pixel_mut_checked(10, 0), None); |
1520 | assert_eq!(a.get_pixel_mut_checked(0, 10), None); |
1521 | |
1522 | // From image/issues/1672 |
1523 | const WHITE: Rgb<u8> = Rgb([255_u8, 255, 255]); |
1524 | let mut a = RgbImage::new(2, 1); |
1525 | a.put_pixel(1, 0, WHITE); |
1526 | |
1527 | assert_eq!(a.get_pixel_checked(1, 0), Some(&WHITE)); |
1528 | assert_eq!(a.get_pixel_checked(1, 0).unwrap(), a.get_pixel(1, 0)); |
1529 | } |
1530 | |
1531 | #[test] |
1532 | fn mut_iter() { |
1533 | let mut a: RgbImage = ImageBuffer::new(10, 10); |
1534 | { |
1535 | let val = a.pixels_mut().next().unwrap(); |
1536 | *val = Rgb([42, 0, 0]); |
1537 | } |
1538 | assert_eq!(a.data[0], 42) |
1539 | } |
1540 | |
1541 | #[test] |
1542 | fn zero_width_zero_height() { |
1543 | let mut image = RgbImage::new(0, 0); |
1544 | |
1545 | assert_eq!(image.rows_mut().count(), 0); |
1546 | assert_eq!(image.pixels_mut().count(), 0); |
1547 | assert_eq!(image.rows().count(), 0); |
1548 | assert_eq!(image.pixels().count(), 0); |
1549 | } |
1550 | |
1551 | #[test] |
1552 | fn zero_width_nonzero_height() { |
1553 | let mut image = RgbImage::new(0, 2); |
1554 | |
1555 | assert_eq!(image.rows_mut().count(), 0); |
1556 | assert_eq!(image.pixels_mut().count(), 0); |
1557 | assert_eq!(image.rows().count(), 0); |
1558 | assert_eq!(image.pixels().count(), 0); |
1559 | } |
1560 | |
1561 | #[test] |
1562 | fn nonzero_width_zero_height() { |
1563 | let mut image = RgbImage::new(2, 0); |
1564 | |
1565 | assert_eq!(image.rows_mut().count(), 0); |
1566 | assert_eq!(image.pixels_mut().count(), 0); |
1567 | assert_eq!(image.rows().count(), 0); |
1568 | assert_eq!(image.pixels().count(), 0); |
1569 | } |
1570 | |
1571 | #[test] |
1572 | fn pixels_on_large_buffer() { |
1573 | let mut image = RgbImage::from_raw(1, 1, vec![0; 6]).unwrap(); |
1574 | |
1575 | assert_eq!(image.pixels().count(), 1); |
1576 | assert_eq!(image.enumerate_pixels().count(), 1); |
1577 | assert_eq!(image.pixels_mut().count(), 1); |
1578 | assert_eq!(image.enumerate_pixels_mut().count(), 1); |
1579 | |
1580 | assert_eq!(image.rows().count(), 1); |
1581 | assert_eq!(image.rows_mut().count(), 1); |
1582 | } |
1583 | |
1584 | #[test] |
1585 | fn default() { |
1586 | let image = ImageBuffer::<Rgb<u8>, Vec<u8>>::default(); |
1587 | assert_eq!(image.dimensions(), (0, 0)); |
1588 | } |
1589 | |
1590 | #[test] |
1591 | #[rustfmt::skip] |
1592 | fn test_image_buffer_copy_within_oob() { |
1593 | let mut image: GrayImage = ImageBuffer::from_raw(4, 4, vec![0u8; 16]).unwrap(); |
1594 | assert!(!image.copy_within(Rect { x: 0, y: 0, width: 5, height: 4 }, 0, 0)); |
1595 | assert!(!image.copy_within(Rect { x: 0, y: 0, width: 4, height: 5 }, 0, 0)); |
1596 | assert!(!image.copy_within(Rect { x: 1, y: 0, width: 4, height: 4 }, 0, 0)); |
1597 | assert!(!image.copy_within(Rect { x: 0, y: 0, width: 4, height: 4 }, 1, 0)); |
1598 | assert!(!image.copy_within(Rect { x: 0, y: 1, width: 4, height: 4 }, 0, 0)); |
1599 | assert!(!image.copy_within(Rect { x: 0, y: 0, width: 4, height: 4 }, 0, 1)); |
1600 | assert!(!image.copy_within(Rect { x: 1, y: 1, width: 4, height: 4 }, 0, 0)); |
1601 | } |
1602 | |
1603 | #[test] |
1604 | fn test_image_buffer_copy_within_tl() { |
1605 | let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; |
1606 | let expected = [0, 1, 2, 3, 4, 0, 1, 2, 8, 4, 5, 6, 12, 8, 9, 10]; |
1607 | let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap(); |
1608 | assert!(image.copy_within( |
1609 | Rect { |
1610 | x: 0, |
1611 | y: 0, |
1612 | width: 3, |
1613 | height: 3 |
1614 | }, |
1615 | 1, |
1616 | 1 |
1617 | )); |
1618 | assert_eq!(&image.into_raw(), &expected); |
1619 | } |
1620 | |
1621 | #[test] |
1622 | fn test_image_buffer_copy_within_tr() { |
1623 | let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; |
1624 | let expected = [0, 1, 2, 3, 1, 2, 3, 7, 5, 6, 7, 11, 9, 10, 11, 15]; |
1625 | let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap(); |
1626 | assert!(image.copy_within( |
1627 | Rect { |
1628 | x: 1, |
1629 | y: 0, |
1630 | width: 3, |
1631 | height: 3 |
1632 | }, |
1633 | 0, |
1634 | 1 |
1635 | )); |
1636 | assert_eq!(&image.into_raw(), &expected); |
1637 | } |
1638 | |
1639 | #[test] |
1640 | fn test_image_buffer_copy_within_bl() { |
1641 | let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; |
1642 | let expected = [0, 4, 5, 6, 4, 8, 9, 10, 8, 12, 13, 14, 12, 13, 14, 15]; |
1643 | let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap(); |
1644 | assert!(image.copy_within( |
1645 | Rect { |
1646 | x: 0, |
1647 | y: 1, |
1648 | width: 3, |
1649 | height: 3 |
1650 | }, |
1651 | 1, |
1652 | 0 |
1653 | )); |
1654 | assert_eq!(&image.into_raw(), &expected); |
1655 | } |
1656 | |
1657 | #[test] |
1658 | fn test_image_buffer_copy_within_br() { |
1659 | let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; |
1660 | let expected = [5, 6, 7, 3, 9, 10, 11, 7, 13, 14, 15, 11, 12, 13, 14, 15]; |
1661 | let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap(); |
1662 | assert!(image.copy_within( |
1663 | Rect { |
1664 | x: 1, |
1665 | y: 1, |
1666 | width: 3, |
1667 | height: 3 |
1668 | }, |
1669 | 0, |
1670 | 0 |
1671 | )); |
1672 | assert_eq!(&image.into_raw(), &expected); |
1673 | } |
1674 | |
1675 | #[test] |
1676 | #[cfg(feature = "png")] |
1677 | fn write_to_with_large_buffer() { |
1678 | // A buffer of 1 pixel, padded to 4 bytes as would be common in, e.g. BMP. |
1679 | let img: GrayImage = ImageBuffer::from_raw(1, 1, vec![0u8; 4]).unwrap(); |
1680 | let mut buffer = std::io::Cursor::new(vec![]); |
1681 | assert!(img.write_to(&mut buffer, ImageOutputFormat::Png).is_ok()); |
1682 | } |
1683 | |
1684 | #[test] |
1685 | fn exact_size_iter_size_hint() { |
1686 | // The docs for `std::iter::ExactSizeIterator` requires that the implementation of |
1687 | // `size_hint` on the iterator returns the same value as the `len` implementation. |
1688 | |
1689 | // This test should work for any size image. |
1690 | const N: u32 = 10; |
1691 | |
1692 | let mut image = RgbImage::from_raw(N, N, vec![0; (N * N * 3) as usize]).unwrap(); |
1693 | |
1694 | let iter = image.pixels(); |
1695 | let exact_len = ExactSizeIterator::len(&iter); |
1696 | assert_eq!(iter.size_hint(), (exact_len, Some(exact_len))); |
1697 | |
1698 | let iter = image.pixels_mut(); |
1699 | let exact_len = ExactSizeIterator::len(&iter); |
1700 | assert_eq!(iter.size_hint(), (exact_len, Some(exact_len))); |
1701 | |
1702 | let iter = image.rows(); |
1703 | let exact_len = ExactSizeIterator::len(&iter); |
1704 | assert_eq!(iter.size_hint(), (exact_len, Some(exact_len))); |
1705 | |
1706 | let iter = image.rows_mut(); |
1707 | let exact_len = ExactSizeIterator::len(&iter); |
1708 | assert_eq!(iter.size_hint(), (exact_len, Some(exact_len))); |
1709 | |
1710 | let iter = image.enumerate_pixels(); |
1711 | let exact_len = ExactSizeIterator::len(&iter); |
1712 | assert_eq!(iter.size_hint(), (exact_len, Some(exact_len))); |
1713 | |
1714 | let iter = image.enumerate_rows(); |
1715 | let exact_len = ExactSizeIterator::len(&iter); |
1716 | assert_eq!(iter.size_hint(), (exact_len, Some(exact_len))); |
1717 | |
1718 | let iter = image.enumerate_pixels_mut(); |
1719 | let exact_len = ExactSizeIterator::len(&iter); |
1720 | assert_eq!(iter.size_hint(), (exact_len, Some(exact_len))); |
1721 | |
1722 | let iter = image.enumerate_rows_mut(); |
1723 | let exact_len = ExactSizeIterator::len(&iter); |
1724 | assert_eq!(iter.size_hint(), (exact_len, Some(exact_len))); |
1725 | } |
1726 | } |
1727 | |
1728 | #[cfg(test)] |
1729 | #[cfg(feature = "benchmarks")] |
1730 | mod benchmarks { |
1731 | use super::{ConvertBuffer, GrayImage, ImageBuffer, Pixel, RgbImage}; |
1732 | |
1733 | #[bench] |
1734 | fn conversion(b: &mut test::Bencher) { |
1735 | let mut a: RgbImage = ImageBuffer::new(1000, 1000); |
1736 | for p in a.pixels_mut() { |
1737 | let rgb = p.channels_mut(); |
1738 | rgb[0] = 255; |
1739 | rgb[1] = 23; |
1740 | rgb[2] = 42; |
1741 | } |
1742 | assert!(a.data[0] != 0); |
1743 | b.iter(|| { |
1744 | let b: GrayImage = a.convert(); |
1745 | assert!(0 != b.data[0]); |
1746 | assert!(a.data[0] != b.data[0]); |
1747 | test::black_box(b); |
1748 | }); |
1749 | b.bytes = 1000 * 1000 * 3 |
1750 | } |
1751 | |
1752 | #[bench] |
1753 | fn image_access_row_by_row(b: &mut test::Bencher) { |
1754 | let mut a: RgbImage = ImageBuffer::new(1000, 1000); |
1755 | for p in a.pixels_mut() { |
1756 | let rgb = p.channels_mut(); |
1757 | rgb[0] = 255; |
1758 | rgb[1] = 23; |
1759 | rgb[2] = 42; |
1760 | } |
1761 | |
1762 | b.iter(move || { |
1763 | let image: &RgbImage = test::black_box(&a); |
1764 | let mut sum: usize = 0; |
1765 | for y in 0..1000 { |
1766 | for x in 0..1000 { |
1767 | let pixel = image.get_pixel(x, y); |
1768 | sum = sum.wrapping_add(pixel[0] as usize); |
1769 | sum = sum.wrapping_add(pixel[1] as usize); |
1770 | sum = sum.wrapping_add(pixel[2] as usize); |
1771 | } |
1772 | } |
1773 | test::black_box(sum) |
1774 | }); |
1775 | |
1776 | b.bytes = 1000 * 1000 * 3; |
1777 | } |
1778 | |
1779 | #[bench] |
1780 | fn image_access_col_by_col(b: &mut test::Bencher) { |
1781 | let mut a: RgbImage = ImageBuffer::new(1000, 1000); |
1782 | for p in a.pixels_mut() { |
1783 | let rgb = p.channels_mut(); |
1784 | rgb[0] = 255; |
1785 | rgb[1] = 23; |
1786 | rgb[2] = 42; |
1787 | } |
1788 | |
1789 | b.iter(move || { |
1790 | let image: &RgbImage = test::black_box(&a); |
1791 | let mut sum: usize = 0; |
1792 | for x in 0..1000 { |
1793 | for y in 0..1000 { |
1794 | let pixel = image.get_pixel(x, y); |
1795 | sum = sum.wrapping_add(pixel[0] as usize); |
1796 | sum = sum.wrapping_add(pixel[1] as usize); |
1797 | sum = sum.wrapping_add(pixel[2] as usize); |
1798 | } |
1799 | } |
1800 | test::black_box(sum) |
1801 | }); |
1802 | |
1803 | b.bytes = 1000 * 1000 * 3; |
1804 | } |
1805 | } |
1806 |