1use alloc::{vec, vec::Vec};
3use core::fmt;
4use core::marker::PhantomData;
5use core::ops::{Deref, DerefMut, Index, IndexMut, Range};
6use core::slice::{ChunksExact, ChunksExactMut};
7use num_traits::Zero;
8#[cfg(feature = "std")]
9use std::path::Path;
10
11use crate::color::{FromColor, FromPrimitive, Luma, LumaA, Rgb, Rgba};
12use crate::error::{
13 ImageResult, ParameterError, ParameterErrorKind, UnsupportedError, UnsupportedErrorKind,
14};
15use crate::flat::{FlatSamples, SampleLayout, ViewOfPixel};
16use crate::math::Rect;
17use crate::metadata::cicp::{CicpApplicable, CicpPixelCast, CicpRgb, ColorComponentForCicp};
18use crate::traits::{EncodableLayout, Pixel, PixelWithColorType};
19use crate::utils::expand_packed;
20use crate::{
21 metadata::{Cicp, CicpColorPrimaries, CicpTransferCharacteristics, CicpTransform},
22 write_buffer_with_format, ImageError,
23};
24#[cfg(feature = "std")]
25use crate::{save_buffer, save_buffer_with_format};
26use crate::{DynamicImage, GenericImage, GenericImageView, ImageEncoder, ImageFormat};
27
28pub struct Pixels<'a, P: Pixel + 'a>
30where
31 P::Subpixel: 'a,
32{
33 chunks: ChunksExact<'a, P::Subpixel>,
34}
35
36impl<'a, P: Pixel + 'a> Iterator for Pixels<'a, P>
37where
38 P::Subpixel: 'a,
39{
40 type Item = &'a P;
41
42 #[inline(always)]
43 fn next(&mut self) -> Option<&'a P> {
44 self.chunks.next().map(|v| <P as Pixel>::from_slice(v))
45 }
46
47 #[inline(always)]
48 fn size_hint(&self) -> (usize, Option<usize>) {
49 let len = self.len();
50 (len, Some(len))
51 }
52}
53
54impl<'a, P: Pixel + 'a> ExactSizeIterator for Pixels<'a, P>
55where
56 P::Subpixel: 'a,
57{
58 fn len(&self) -> usize {
59 self.chunks.len()
60 }
61}
62
63impl<'a, P: Pixel + 'a> DoubleEndedIterator for Pixels<'a, P>
64where
65 P::Subpixel: 'a,
66{
67 #[inline(always)]
68 fn next_back(&mut self) -> Option<&'a P> {
69 self.chunks.next_back().map(|v| <P as Pixel>::from_slice(v))
70 }
71}
72
73impl<P: Pixel> Clone for Pixels<'_, P> {
74 fn clone(&self) -> Self {
75 Pixels {
76 chunks: self.chunks.clone(),
77 }
78 }
79}
80
81impl<P: Pixel> fmt::Debug for Pixels<'_, P>
82where
83 P::Subpixel: fmt::Debug,
84{
85 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
86 f.debug_struct("Pixels")
87 .field("chunks", &self.chunks)
88 .finish()
89 }
90}
91
92pub struct PixelsMut<'a, P: Pixel + 'a>
94where
95 P::Subpixel: 'a,
96{
97 chunks: ChunksExactMut<'a, P::Subpixel>,
98}
99
100impl<'a, P: Pixel + 'a> Iterator for PixelsMut<'a, P>
101where
102 P::Subpixel: 'a,
103{
104 type Item = &'a mut P;
105
106 #[inline(always)]
107 fn next(&mut self) -> Option<&'a mut P> {
108 self.chunks.next().map(|v| <P as Pixel>::from_slice_mut(v))
109 }
110
111 #[inline(always)]
112 fn size_hint(&self) -> (usize, Option<usize>) {
113 let len = self.len();
114 (len, Some(len))
115 }
116}
117
118impl<'a, P: Pixel + 'a> ExactSizeIterator for PixelsMut<'a, P>
119where
120 P::Subpixel: 'a,
121{
122 fn len(&self) -> usize {
123 self.chunks.len()
124 }
125}
126
127impl<'a, P: Pixel + 'a> DoubleEndedIterator for PixelsMut<'a, P>
128where
129 P::Subpixel: 'a,
130{
131 #[inline(always)]
132 fn next_back(&mut self) -> Option<&'a mut P> {
133 self.chunks
134 .next_back()
135 .map(|v| <P as Pixel>::from_slice_mut(v))
136 }
137}
138
139impl<P: Pixel> fmt::Debug for PixelsMut<'_, P>
140where
141 P::Subpixel: fmt::Debug,
142{
143 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
144 f.debug_struct("PixelsMut")
145 .field("chunks", &self.chunks)
146 .finish()
147 }
148}
149
150pub struct Rows<'a, P: Pixel + 'a>
156where
157 <P as Pixel>::Subpixel: 'a,
158{
159 pixels: ChunksExact<'a, P::Subpixel>,
160}
161
162impl<'a, P: Pixel + 'a> Rows<'a, P> {
163 fn with_image(pixels: &'a [P::Subpixel], width: u32, height: u32) -> Self {
166 let row_len = (width as usize) * usize::from(<P as Pixel>::CHANNEL_COUNT);
167 if row_len == 0 {
168 Rows {
169 pixels: [].chunks_exact(1),
170 }
171 } else {
172 let pixels = pixels
173 .get(..row_len * height as usize)
174 .expect("Pixel buffer has too few subpixels");
175 Rows {
178 pixels: pixels.chunks_exact(row_len),
179 }
180 }
181 }
182}
183
184impl<'a, P: Pixel + 'a> Iterator for Rows<'a, P>
185where
186 P::Subpixel: 'a,
187{
188 type Item = Pixels<'a, P>;
189
190 #[inline(always)]
191 fn next(&mut self) -> Option<Pixels<'a, P>> {
192 let row = self.pixels.next()?;
193 Some(Pixels {
194 chunks: row.chunks_exact(<P as Pixel>::CHANNEL_COUNT as usize),
196 })
197 }
198
199 #[inline(always)]
200 fn size_hint(&self) -> (usize, Option<usize>) {
201 let len = self.len();
202 (len, Some(len))
203 }
204}
205
206impl<'a, P: Pixel + 'a> ExactSizeIterator for Rows<'a, P>
207where
208 P::Subpixel: 'a,
209{
210 fn len(&self) -> usize {
211 self.pixels.len()
212 }
213}
214
215impl<'a, P: Pixel + 'a> DoubleEndedIterator for Rows<'a, P>
216where
217 P::Subpixel: 'a,
218{
219 #[inline(always)]
220 fn next_back(&mut self) -> Option<Pixels<'a, P>> {
221 let row = self.pixels.next_back()?;
222 Some(Pixels {
223 chunks: row.chunks_exact(<P as Pixel>::CHANNEL_COUNT as usize),
225 })
226 }
227}
228
229impl<P: Pixel> Clone for Rows<'_, P> {
230 fn clone(&self) -> Self {
231 Rows {
232 pixels: self.pixels.clone(),
233 }
234 }
235}
236
237impl<P: Pixel> fmt::Debug for Rows<'_, P>
238where
239 P::Subpixel: fmt::Debug,
240{
241 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
242 f.debug_struct("Rows")
243 .field("pixels", &self.pixels)
244 .finish()
245 }
246}
247
248pub struct RowsMut<'a, P: Pixel + 'a>
254where
255 <P as Pixel>::Subpixel: 'a,
256{
257 pixels: ChunksExactMut<'a, P::Subpixel>,
258}
259
260impl<'a, P: Pixel + 'a> RowsMut<'a, P> {
261 fn with_image(pixels: &'a mut [P::Subpixel], width: u32, height: u32) -> Self {
264 let row_len = (width as usize) * usize::from(<P as Pixel>::CHANNEL_COUNT);
265 if row_len == 0 {
266 RowsMut {
267 pixels: [].chunks_exact_mut(1),
268 }
269 } else {
270 let pixels = pixels
271 .get_mut(..row_len * height as usize)
272 .expect("Pixel buffer has too few subpixels");
273 RowsMut {
276 pixels: pixels.chunks_exact_mut(row_len),
277 }
278 }
279 }
280}
281
282impl<'a, P: Pixel + 'a> Iterator for RowsMut<'a, P>
283where
284 P::Subpixel: 'a,
285{
286 type Item = PixelsMut<'a, P>;
287
288 #[inline(always)]
289 fn next(&mut self) -> Option<PixelsMut<'a, P>> {
290 let row = self.pixels.next()?;
291 Some(PixelsMut {
292 chunks: row.chunks_exact_mut(<P as Pixel>::CHANNEL_COUNT as usize),
294 })
295 }
296
297 #[inline(always)]
298 fn size_hint(&self) -> (usize, Option<usize>) {
299 let len = self.len();
300 (len, Some(len))
301 }
302}
303
304impl<'a, P: Pixel + 'a> ExactSizeIterator for RowsMut<'a, P>
305where
306 P::Subpixel: 'a,
307{
308 fn len(&self) -> usize {
309 self.pixels.len()
310 }
311}
312
313impl<'a, P: Pixel + 'a> DoubleEndedIterator for RowsMut<'a, P>
314where
315 P::Subpixel: 'a,
316{
317 #[inline(always)]
318 fn next_back(&mut self) -> Option<PixelsMut<'a, P>> {
319 let row = self.pixels.next_back()?;
320 Some(PixelsMut {
321 chunks: row.chunks_exact_mut(<P as Pixel>::CHANNEL_COUNT as usize),
323 })
324 }
325}
326
327impl<P: Pixel> fmt::Debug for RowsMut<'_, P>
328where
329 P::Subpixel: fmt::Debug,
330{
331 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
332 f.debug_struct("RowsMut")
333 .field("pixels", &self.pixels)
334 .finish()
335 }
336}
337
338pub struct EnumeratePixels<'a, P: Pixel + 'a>
340where
341 <P as Pixel>::Subpixel: 'a,
342{
343 pixels: Pixels<'a, P>,
344 x: u32,
345 y: u32,
346 width: u32,
347}
348
349impl<'a, P: Pixel + 'a> Iterator for EnumeratePixels<'a, P>
350where
351 P::Subpixel: 'a,
352{
353 type Item = (u32, u32, &'a P);
354
355 #[inline(always)]
356 fn next(&mut self) -> Option<(u32, u32, &'a P)> {
357 if self.x >= self.width {
358 self.x = 0;
359 self.y += 1;
360 }
361 let (x, y) = (self.x, self.y);
362 self.x += 1;
363 self.pixels.next().map(|p| (x, y, p))
364 }
365
366 #[inline(always)]
367 fn size_hint(&self) -> (usize, Option<usize>) {
368 let len = self.len();
369 (len, Some(len))
370 }
371}
372
373impl<'a, P: Pixel + 'a> ExactSizeIterator for EnumeratePixels<'a, P>
374where
375 P::Subpixel: 'a,
376{
377 fn len(&self) -> usize {
378 self.pixels.len()
379 }
380}
381
382impl<P: Pixel> Clone for EnumeratePixels<'_, P> {
383 fn clone(&self) -> Self {
384 EnumeratePixels {
385 pixels: self.pixels.clone(),
386 ..*self
387 }
388 }
389}
390
391impl<P: Pixel> fmt::Debug for EnumeratePixels<'_, P>
392where
393 P::Subpixel: fmt::Debug,
394{
395 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
396 f.debug_struct("EnumeratePixels")
397 .field("pixels", &self.pixels)
398 .field("x", &self.x)
399 .field("y", &self.y)
400 .field("width", &self.width)
401 .finish()
402 }
403}
404
405pub struct EnumerateRows<'a, P: Pixel + 'a>
407where
408 <P as Pixel>::Subpixel: 'a,
409{
410 rows: Rows<'a, P>,
411 y: u32,
412 width: u32,
413}
414
415impl<'a, P: Pixel + 'a> Iterator for EnumerateRows<'a, P>
416where
417 P::Subpixel: 'a,
418{
419 type Item = (u32, EnumeratePixels<'a, P>);
420
421 #[inline(always)]
422 fn next(&mut self) -> Option<(u32, EnumeratePixels<'a, P>)> {
423 let y = self.y;
424 self.y += 1;
425 self.rows.next().map(|r| {
426 (
427 y,
428 EnumeratePixels {
429 x: 0,
430 y,
431 width: self.width,
432 pixels: r,
433 },
434 )
435 })
436 }
437
438 #[inline(always)]
439 fn size_hint(&self) -> (usize, Option<usize>) {
440 let len = self.len();
441 (len, Some(len))
442 }
443}
444
445impl<'a, P: Pixel + 'a> ExactSizeIterator for EnumerateRows<'a, P>
446where
447 P::Subpixel: 'a,
448{
449 fn len(&self) -> usize {
450 self.rows.len()
451 }
452}
453
454impl<P: Pixel> Clone for EnumerateRows<'_, P> {
455 fn clone(&self) -> Self {
456 EnumerateRows {
457 rows: self.rows.clone(),
458 ..*self
459 }
460 }
461}
462
463impl<P: Pixel> fmt::Debug for EnumerateRows<'_, P>
464where
465 P::Subpixel: fmt::Debug,
466{
467 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
468 f.debug_struct("EnumerateRows")
469 .field("rows", &self.rows)
470 .field("y", &self.y)
471 .field("width", &self.width)
472 .finish()
473 }
474}
475
476pub struct EnumeratePixelsMut<'a, P: Pixel + 'a>
478where
479 <P as Pixel>::Subpixel: 'a,
480{
481 pixels: PixelsMut<'a, P>,
482 x: u32,
483 y: u32,
484 width: u32,
485}
486
487impl<'a, P: Pixel + 'a> Iterator for EnumeratePixelsMut<'a, P>
488where
489 P::Subpixel: 'a,
490{
491 type Item = (u32, u32, &'a mut P);
492
493 #[inline(always)]
494 fn next(&mut self) -> Option<(u32, u32, &'a mut P)> {
495 if self.x >= self.width {
496 self.x = 0;
497 self.y += 1;
498 }
499 let (x, y) = (self.x, self.y);
500 self.x += 1;
501 self.pixels.next().map(|p| (x, y, p))
502 }
503
504 #[inline(always)]
505 fn size_hint(&self) -> (usize, Option<usize>) {
506 let len = self.len();
507 (len, Some(len))
508 }
509}
510
511impl<'a, P: Pixel + 'a> ExactSizeIterator for EnumeratePixelsMut<'a, P>
512where
513 P::Subpixel: 'a,
514{
515 fn len(&self) -> usize {
516 self.pixels.len()
517 }
518}
519
520impl<P: Pixel> fmt::Debug for EnumeratePixelsMut<'_, P>
521where
522 P::Subpixel: fmt::Debug,
523{
524 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
525 f.debug_struct("EnumeratePixelsMut")
526 .field("pixels", &self.pixels)
527 .field("x", &self.x)
528 .field("y", &self.y)
529 .field("width", &self.width)
530 .finish()
531 }
532}
533
534pub struct EnumerateRowsMut<'a, P: Pixel + 'a>
536where
537 <P as Pixel>::Subpixel: 'a,
538{
539 rows: RowsMut<'a, P>,
540 y: u32,
541 width: u32,
542}
543
544impl<'a, P: Pixel + 'a> Iterator for EnumerateRowsMut<'a, P>
545where
546 P::Subpixel: 'a,
547{
548 type Item = (u32, EnumeratePixelsMut<'a, P>);
549
550 #[inline(always)]
551 fn next(&mut self) -> Option<(u32, EnumeratePixelsMut<'a, P>)> {
552 let y = self.y;
553 self.y += 1;
554 self.rows.next().map(|r| {
555 (
556 y,
557 EnumeratePixelsMut {
558 x: 0,
559 y,
560 width: self.width,
561 pixels: r,
562 },
563 )
564 })
565 }
566
567 #[inline(always)]
568 fn size_hint(&self) -> (usize, Option<usize>) {
569 let len = self.len();
570 (len, Some(len))
571 }
572}
573
574impl<'a, P: Pixel + 'a> ExactSizeIterator for EnumerateRowsMut<'a, P>
575where
576 P::Subpixel: 'a,
577{
578 fn len(&self) -> usize {
579 self.rows.len()
580 }
581}
582
583impl<P: Pixel> fmt::Debug for EnumerateRowsMut<'_, P>
584where
585 P::Subpixel: fmt::Debug,
586{
587 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
588 f.debug_struct("EnumerateRowsMut")
589 .field("rows", &self.rows)
590 .field("y", &self.y)
591 .field("width", &self.width)
592 .finish()
593 }
594}
595
596#[derive(Debug, Hash, PartialEq, Eq)]
665pub struct ImageBuffer<P: Pixel, Container> {
666 width: u32,
667 height: u32,
668 _phantom: PhantomData<P>,
669 color: CicpRgb,
670 data: Container,
671}
672
673impl<P, Container> ImageBuffer<P, Container>
675where
676 P: Pixel,
677 Container: Deref<Target = [P::Subpixel]>,
678{
679 pub fn from_raw(width: u32, height: u32, buf: Container) -> Option<ImageBuffer<P, Container>> {
685 if Self::check_image_fits(width, height, buf.len()) {
686 Some(ImageBuffer {
687 data: buf,
688 width,
689 height,
690 color: Cicp::SRGB.into_rgb(),
691 _phantom: PhantomData,
692 })
693 } else {
694 None
695 }
696 }
697
698 pub fn into_raw(self) -> Container {
700 self.data
701 }
702
703 pub fn as_raw(&self) -> &Container {
705 &self.data
706 }
707
708 pub fn dimensions(&self) -> (u32, u32) {
710 (self.width, self.height)
711 }
712
713 pub fn width(&self) -> u32 {
715 self.width
716 }
717
718 pub fn height(&self) -> u32 {
720 self.height
721 }
722
723 pub(crate) fn inner_pixels(&self) -> &[P::Subpixel] {
725 let len = Self::image_buffer_len(self.width, self.height).unwrap();
726 &self.data[..len]
727 }
728
729 pub fn pixels(&self) -> Pixels<'_, P> {
732 Pixels {
733 chunks: self
734 .inner_pixels()
735 .chunks_exact(<P as Pixel>::CHANNEL_COUNT as usize),
736 }
737 }
738
739 pub fn rows(&self) -> Rows<'_, P> {
745 Rows::with_image(&self.data, self.width, self.height)
746 }
747
748 pub fn enumerate_pixels(&self) -> EnumeratePixels<'_, P> {
754 EnumeratePixels {
755 pixels: self.pixels(),
756 x: 0,
757 y: 0,
758 width: self.width,
759 }
760 }
761
762 pub fn enumerate_rows(&self) -> EnumerateRows<'_, P> {
766 EnumerateRows {
767 rows: self.rows(),
768 y: 0,
769 width: self.width,
770 }
771 }
772
773 #[inline]
779 #[track_caller]
780 pub fn get_pixel(&self, x: u32, y: u32) -> &P {
781 match self.pixel_indices(x, y) {
782 None => panic!(
783 "Image index {:?} out of bounds {:?}",
784 (x, y),
785 (self.width, self.height)
786 ),
787 Some(pixel_indices) => <P as Pixel>::from_slice(&self.data[pixel_indices]),
788 }
789 }
790
791 pub fn get_pixel_checked(&self, x: u32, y: u32) -> Option<&P> {
794 if x >= self.width {
795 return None;
796 }
797 let num_channels = <P as Pixel>::CHANNEL_COUNT as usize;
798 let i = (y as usize)
799 .saturating_mul(self.width as usize)
800 .saturating_add(x as usize)
801 .saturating_mul(num_channels);
802
803 self.data
804 .get(i..i.checked_add(num_channels)?)
805 .map(|pixel_indices| <P as Pixel>::from_slice(pixel_indices))
806 }
807
808 fn check_image_fits(width: u32, height: u32, len: usize) -> bool {
814 let checked_len = Self::image_buffer_len(width, height);
815 checked_len.is_some_and(|min_len| min_len <= len)
816 }
817
818 fn image_buffer_len(width: u32, height: u32) -> Option<usize> {
819 Some(<P as Pixel>::CHANNEL_COUNT as usize)
820 .and_then(|size| size.checked_mul(width as usize))
821 .and_then(|size| size.checked_mul(height as usize))
822 }
823
824 #[inline(always)]
825 fn pixel_indices(&self, x: u32, y: u32) -> Option<Range<usize>> {
826 if x >= self.width || y >= self.height {
827 return None;
828 }
829
830 Some(self.pixel_indices_unchecked(x, y))
831 }
832
833 #[inline(always)]
834 fn pixel_indices_unchecked(&self, x: u32, y: u32) -> Range<usize> {
835 let no_channels = <P as Pixel>::CHANNEL_COUNT as usize;
836 let min_index = (y as usize * self.width as usize + x as usize) * no_channels;
838 min_index..min_index + no_channels
839 }
840
841 pub fn sample_layout(&self) -> SampleLayout {
843 SampleLayout::row_major_packed(<P as Pixel>::CHANNEL_COUNT, self.width, self.height)
845 }
846
847 pub fn into_flat_samples(self) -> FlatSamples<Container>
854 where
855 Container: AsRef<[P::Subpixel]>,
856 {
857 let layout = self.sample_layout();
859 FlatSamples {
860 samples: self.data,
861 layout,
862 color_hint: None, }
864 }
865
866 pub fn as_flat_samples(&self) -> FlatSamples<&[P::Subpixel]> {
870 let layout = self.sample_layout();
871 FlatSamples {
872 samples: self.data.as_ref(),
873 layout,
874 color_hint: None, }
876 }
877
878 pub fn as_flat_samples_mut(&mut self) -> FlatSamples<&mut [P::Subpixel]>
882 where
883 Container: AsMut<[P::Subpixel]>,
884 {
885 let layout = self.sample_layout();
886 FlatSamples {
887 samples: self.data.as_mut(),
888 layout,
889 color_hint: None, }
891 }
892}
893
894impl<P, Container> ImageBuffer<P, Container>
895where
896 P: Pixel,
897 Container: Deref<Target = [P::Subpixel]> + DerefMut,
898{
899 pub(crate) fn inner_pixels_mut(&mut self) -> &mut [P::Subpixel] {
901 let len = Self::image_buffer_len(self.width, self.height).unwrap();
902 &mut self.data[..len]
903 }
904
905 pub fn pixels_mut(&mut self) -> PixelsMut<'_, P> {
907 PixelsMut {
908 chunks: self
909 .inner_pixels_mut()
910 .chunks_exact_mut(<P as Pixel>::CHANNEL_COUNT as usize),
911 }
912 }
913
914 pub fn rows_mut(&mut self) -> RowsMut<'_, P> {
920 RowsMut::with_image(&mut self.data, self.width, self.height)
921 }
922
923 pub fn enumerate_pixels_mut(&mut self) -> EnumeratePixelsMut<'_, P> {
927 let width = self.width;
928 EnumeratePixelsMut {
929 pixels: self.pixels_mut(),
930 x: 0,
931 y: 0,
932 width,
933 }
934 }
935
936 pub fn enumerate_rows_mut(&mut self) -> EnumerateRowsMut<'_, P> {
940 let width = self.width;
941 EnumerateRowsMut {
942 rows: self.rows_mut(),
943 y: 0,
944 width,
945 }
946 }
947
948 #[inline]
954 #[track_caller]
955 pub fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut P {
956 match self.pixel_indices(x, y) {
957 None => panic!(
958 "Image index {:?} out of bounds {:?}",
959 (x, y),
960 (self.width, self.height)
961 ),
962 Some(pixel_indices) => <P as Pixel>::from_slice_mut(&mut self.data[pixel_indices]),
963 }
964 }
965
966 pub fn get_pixel_mut_checked(&mut self, x: u32, y: u32) -> Option<&mut P> {
969 if x >= self.width {
970 return None;
971 }
972 let num_channels = <P as Pixel>::CHANNEL_COUNT as usize;
973 let i = (y as usize)
974 .saturating_mul(self.width as usize)
975 .saturating_add(x as usize)
976 .saturating_mul(num_channels);
977
978 self.data
979 .get_mut(i..i.checked_add(num_channels)?)
980 .map(|pixel_indices| <P as Pixel>::from_slice_mut(pixel_indices))
981 }
982
983 #[inline]
989 #[track_caller]
990 pub fn put_pixel(&mut self, x: u32, y: u32, pixel: P) {
991 *self.get_pixel_mut(x, y) = pixel;
992 }
993}
994
995impl<P: Pixel, Container> ImageBuffer<P, Container> {
996 pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) {
1009 self.color.primaries = color;
1010 }
1011
1012 pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) {
1021 self.color.transfer = tf;
1022 }
1023
1024 pub fn color_space(&self) -> Cicp {
1026 self.color.into()
1027 }
1028
1029 pub fn set_color_space(&mut self, cicp: Cicp) -> ImageResult<()> {
1034 self.color = cicp.try_into_rgb()?;
1035 Ok(())
1036 }
1037
1038 pub(crate) fn set_rgb_color_space(&mut self, color: CicpRgb) {
1039 self.color = color;
1040 }
1041}
1042
1043impl<P, Container> ImageBuffer<P, Container>
1044where
1045 P: Pixel,
1046 [P::Subpixel]: EncodableLayout,
1047 Container: Deref<Target = [P::Subpixel]>,
1048{
1049 #[cfg(feature = "std")]
1053 pub fn save<Q>(&self, path: Q) -> ImageResult<()>
1054 where
1055 Q: AsRef<Path>,
1056 P: PixelWithColorType,
1057 {
1058 save_buffer(
1059 path,
1060 self.inner_pixels().as_bytes(),
1061 self.width(),
1062 self.height(),
1063 <P as PixelWithColorType>::COLOR_TYPE,
1064 )
1065 }
1066}
1067
1068impl<P, Container> ImageBuffer<P, Container>
1069where
1070 P: Pixel,
1071 [P::Subpixel]: EncodableLayout,
1072 Container: Deref<Target = [P::Subpixel]>,
1073{
1074 #[cfg(feature = "std")]
1080 pub fn save_with_format<Q>(&self, path: Q, format: ImageFormat) -> ImageResult<()>
1081 where
1082 Q: AsRef<Path>,
1083 P: PixelWithColorType,
1084 {
1085 save_buffer_with_format(
1087 path,
1088 self.inner_pixels().as_bytes(),
1089 self.width(),
1090 self.height(),
1091 <P as PixelWithColorType>::COLOR_TYPE,
1092 format,
1093 )
1094 }
1095}
1096
1097impl<P, Container> ImageBuffer<P, Container>
1098where
1099 P: Pixel,
1100 [P::Subpixel]: EncodableLayout,
1101 Container: Deref<Target = [P::Subpixel]>,
1102{
1103 pub fn write_to<W>(&self, writer: &mut W, format: ImageFormat) -> ImageResult<()>
1108 where
1109 W: no_std_io::io::Write + no_std_io::io::Seek,
1110 P: PixelWithColorType,
1111 {
1112 write_buffer_with_format(
1114 writer,
1115 self.inner_pixels().as_bytes(),
1116 self.width(),
1117 self.height(),
1118 <P as PixelWithColorType>::COLOR_TYPE,
1119 format,
1120 )
1121 }
1122}
1123
1124impl<P, Container> ImageBuffer<P, Container>
1125where
1126 P: Pixel,
1127 [P::Subpixel]: EncodableLayout,
1128 Container: Deref<Target = [P::Subpixel]>,
1129{
1130 pub fn write_with_encoder<E>(&self, encoder: E) -> ImageResult<()>
1132 where
1133 E: ImageEncoder,
1134 P: PixelWithColorType,
1135 {
1136 encoder.write_image(
1138 self.inner_pixels().as_bytes(),
1139 self.width(),
1140 self.height(),
1141 <P as PixelWithColorType>::COLOR_TYPE,
1142 )
1143 }
1144}
1145
1146impl<P, Container> Default for ImageBuffer<P, Container>
1147where
1148 P: Pixel,
1149 Container: Default,
1150{
1151 fn default() -> Self {
1152 Self {
1153 width: 0,
1154 height: 0,
1155 _phantom: PhantomData,
1156 color: Cicp::SRGB_LINEAR.into_rgb(),
1157 data: Default::default(),
1158 }
1159 }
1160}
1161
1162impl<P, Container> Deref for ImageBuffer<P, Container>
1163where
1164 P: Pixel,
1165 Container: Deref<Target = [P::Subpixel]>,
1166{
1167 type Target = [P::Subpixel];
1168
1169 fn deref(&self) -> &<Self as Deref>::Target {
1170 &self.data
1171 }
1172}
1173
1174impl<P, Container> DerefMut for ImageBuffer<P, Container>
1175where
1176 P: Pixel,
1177 Container: Deref<Target = [P::Subpixel]> + DerefMut,
1178{
1179 fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
1180 &mut self.data
1181 }
1182}
1183
1184impl<P, Container> Index<(u32, u32)> for ImageBuffer<P, Container>
1185where
1186 P: Pixel,
1187 Container: Deref<Target = [P::Subpixel]>,
1188{
1189 type Output = P;
1190
1191 fn index(&self, (x, y): (u32, u32)) -> &P {
1192 self.get_pixel(x, y)
1193 }
1194}
1195
1196impl<P, Container> IndexMut<(u32, u32)> for ImageBuffer<P, Container>
1197where
1198 P: Pixel,
1199 Container: Deref<Target = [P::Subpixel]> + DerefMut,
1200{
1201 fn index_mut(&mut self, (x, y): (u32, u32)) -> &mut P {
1202 self.get_pixel_mut(x, y)
1203 }
1204}
1205
1206impl<P, Container> Clone for ImageBuffer<P, Container>
1207where
1208 P: Pixel,
1209 Container: Deref<Target = [P::Subpixel]> + Clone,
1210{
1211 fn clone(&self) -> ImageBuffer<P, Container> {
1212 ImageBuffer {
1213 data: self.data.clone(),
1214 width: self.width,
1215 height: self.height,
1216 color: self.color,
1217 _phantom: PhantomData,
1218 }
1219 }
1220
1221 fn clone_from(&mut self, source: &Self) {
1222 self.data.clone_from(&source.data);
1223 self.width = source.width;
1224 self.height = source.height;
1225 self.color = source.color;
1226 }
1227}
1228
1229impl<P, Container> GenericImageView for ImageBuffer<P, Container>
1230where
1231 P: Pixel,
1232 Container: Deref<Target = [P::Subpixel]> + Deref,
1233{
1234 type Pixel = P;
1235
1236 fn dimensions(&self) -> (u32, u32) {
1237 self.dimensions()
1238 }
1239
1240 fn get_pixel(&self, x: u32, y: u32) -> P {
1241 *self.get_pixel(x, y)
1242 }
1243
1244 fn to_pixel_view(&self) -> Option<ViewOfPixel<'_, Self::Pixel>> {
1245 self.as_flat_samples().into_view().ok()
1246 }
1247
1248 #[inline(always)]
1250 unsafe fn unsafe_get_pixel(&self, x: u32, y: u32) -> P {
1251 let indices = self.pixel_indices_unchecked(x, y);
1252 *<P as Pixel>::from_slice(self.data.get_unchecked(indices))
1253 }
1254
1255 fn buffer_with_dimensions(&self, width: u32, height: u32) -> ImageBuffer<P, Vec<P::Subpixel>> {
1256 let mut buffer = ImageBuffer::new(width, height);
1257 buffer.copy_color_space_from(self);
1258 buffer
1259 }
1260}
1261
1262impl<P, Container> GenericImage for ImageBuffer<P, Container>
1263where
1264 P: Pixel,
1265 Container: Deref<Target = [P::Subpixel]> + DerefMut,
1266{
1267 fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut P {
1268 self.get_pixel_mut(x, y)
1269 }
1270
1271 fn put_pixel(&mut self, x: u32, y: u32, pixel: P) {
1272 *self.get_pixel_mut(x, y) = pixel;
1273 }
1274
1275 #[inline(always)]
1277 unsafe fn unsafe_put_pixel(&mut self, x: u32, y: u32, pixel: P) {
1278 let indices = self.pixel_indices_unchecked(x, y);
1279 let p = <P as Pixel>::from_slice_mut(self.data.get_unchecked_mut(indices));
1280 *p = pixel;
1281 }
1282
1283 fn blend_pixel(&mut self, x: u32, y: u32, p: P) {
1287 self.get_pixel_mut(x, y).blend(&p);
1288 }
1289
1290 fn copy_from_samples(
1291 &mut self,
1292 view: ViewOfPixel<'_, Self::Pixel>,
1293 x: u32,
1294 y: u32,
1295 ) -> ImageResult<()> {
1296 let (width, height) = view.dimensions();
1297 let pix_stride = usize::from(<Self::Pixel as Pixel>::CHANNEL_COUNT);
1298 Rect::from_image_at(&view, x, y).test_in_bounds(self)?;
1299
1300 if width == 0 || height == 0 || pix_stride == 0 {
1301 return Ok(());
1302 }
1303
1304 let row_len = width as usize * pix_stride;
1307 let img_sh = self.width as usize;
1308
1309 let (sw, sh) = view.strides_wh();
1310 let view_samples: &[_] = view.samples();
1311 let inner = self.inner_pixels_mut();
1312
1313 let img_pixel_indices_unchecked =
1314 |x: u32, y: u32| (y as usize * img_sh + x as usize) * pix_stride;
1315
1316 if sw == pix_stride {
1318 for j in 0..height {
1319 let start = img_pixel_indices_unchecked(x, j + y);
1320 let img_row = &mut inner[start..][..row_len];
1321 let view_row = &view_samples[j as usize * sh..][..row_len];
1322 img_row.copy_from_slice(view_row);
1323 }
1324
1325 return Ok(());
1326 }
1327
1328 for j in 0..height {
1330 let img_start = img_pixel_indices_unchecked(x, j + y);
1331 let img_row = &mut inner[img_start..][..row_len];
1332 let pixels = img_row.chunks_exact_mut(pix_stride);
1333
1334 let view_start = j as usize * sh;
1335
1336 for (i, sp) in pixels.enumerate() {
1337 let view_pixel = &view_samples[i * sw + view_start..][..pix_stride];
1338 sp.copy_from_slice(view_pixel);
1339 }
1340 }
1341
1342 Ok(())
1343 }
1344
1345 fn copy_within(&mut self, source: Rect, x: u32, y: u32) -> bool {
1346 let Rect {
1347 x: sx,
1348 y: sy,
1349 width,
1350 height,
1351 } = source;
1352 let dx = x;
1353 let dy = y;
1354 assert!(sx < self.width() && dx < self.width());
1355 assert!(sy < self.height() && dy < self.height());
1356 if self.width() - dx.max(sx) < width || self.height() - dy.max(sy) < height {
1357 return false;
1358 }
1359
1360 if sy < dy {
1361 for y in (0..height).rev() {
1362 let sy = sy + y;
1363 let dy = dy + y;
1364 let Range { start, .. } = self.pixel_indices_unchecked(sx, sy);
1365 let Range { end, .. } = self.pixel_indices_unchecked(sx + width - 1, sy);
1366 let dst = self.pixel_indices_unchecked(dx, dy).start;
1367 self.data.copy_within(start..end, dst);
1368 }
1369 } else {
1370 for y in 0..height {
1371 let sy = sy + y;
1372 let dy = dy + y;
1373 let Range { start, .. } = self.pixel_indices_unchecked(sx, sy);
1374 let Range { end, .. } = self.pixel_indices_unchecked(sx + width - 1, sy);
1375 let dst = self.pixel_indices_unchecked(dx, dy).start;
1376 self.data.copy_within(start..end, dst);
1377 }
1378 }
1379 true
1380 }
1381}
1382
1383impl<P: Pixel> ImageBuffer<P, Vec<P::Subpixel>> {
1390 #[must_use]
1400 pub fn new(width: u32, height: u32) -> ImageBuffer<P, Vec<P::Subpixel>> {
1401 let size = Self::image_buffer_len(width, height)
1402 .expect("Buffer length in `ImageBuffer::new` overflows usize");
1403 ImageBuffer {
1404 data: vec![Zero::zero(); size],
1405 width,
1406 height,
1407 color: Cicp::SRGB.into_rgb(),
1408 _phantom: PhantomData,
1409 }
1410 }
1411
1412 pub fn from_pixel(width: u32, height: u32, pixel: P) -> ImageBuffer<P, Vec<P::Subpixel>> {
1418 let mut buf = ImageBuffer::new(width, height);
1419 for p in buf.pixels_mut() {
1420 *p = pixel;
1421 }
1422 buf
1423 }
1424
1425 pub fn from_fn<F>(width: u32, height: u32, mut f: F) -> ImageBuffer<P, Vec<P::Subpixel>>
1433 where
1434 F: FnMut(u32, u32) -> P,
1435 {
1436 let mut buf = ImageBuffer::new(width, height);
1437 for (x, y, p) in buf.enumerate_pixels_mut() {
1438 *p = f(x, y);
1439 }
1440 buf
1441 }
1442
1443 #[must_use]
1446 pub fn from_vec(
1447 width: u32,
1448 height: u32,
1449 buf: Vec<P::Subpixel>,
1450 ) -> Option<ImageBuffer<P, Vec<P::Subpixel>>> {
1451 ImageBuffer::from_raw(width, height, buf)
1452 }
1453
1454 #[must_use]
1457 pub fn into_vec(self) -> Vec<P::Subpixel> {
1458 self.into_raw()
1459 }
1460
1461 pub(crate) fn copy_color_space_from<O: Pixel, C>(&mut self, other: &ImageBuffer<O, C>) {
1467 self.color = other.color;
1468 }
1469}
1470
1471impl<S, Container> ImageBuffer<Rgb<S>, Container>
1472where
1473 Rgb<S>: PixelWithColorType<Subpixel = S>,
1474 Container: DerefMut<Target = [S]>,
1475{
1476 pub fn from_raw_bgr(width: u32, height: u32, container: Container) -> Option<Self> {
1478 let mut img = Self::from_raw(width, height, container)?;
1479
1480 for pix in img.pixels_mut() {
1481 pix.0.reverse();
1482 }
1483
1484 Some(img)
1485 }
1486
1487 pub fn into_raw_bgr(mut self) -> Container {
1489 for pix in self.pixels_mut() {
1490 pix.0.reverse();
1491 }
1492
1493 self.into_raw()
1494 }
1495}
1496
1497impl<S, Container> ImageBuffer<Rgba<S>, Container>
1498where
1499 Rgba<S>: PixelWithColorType<Subpixel = S>,
1500 Container: DerefMut<Target = [S]>,
1501{
1502 pub fn from_raw_bgra(width: u32, height: u32, container: Container) -> Option<Self> {
1504 let mut img = Self::from_raw(width, height, container)?;
1505
1506 for pix in img.pixels_mut() {
1507 pix.0[..3].reverse();
1508 }
1509
1510 Some(img)
1511 }
1512
1513 pub fn into_raw_bgra(mut self) -> Container {
1515 for pix in self.pixels_mut() {
1516 pix.0[..3].reverse();
1517 }
1518
1519 self.into_raw()
1520 }
1521}
1522
1523pub trait ConvertBuffer<T> {
1525 fn convert(&self) -> T;
1530}
1531
1532impl GrayImage {
1534 #[must_use]
1538 pub fn expand_palette(
1539 self,
1540 palette: &[(u8, u8, u8)],
1541 transparent_idx: Option<u8>,
1542 ) -> RgbaImage {
1543 let (width, height) = self.dimensions();
1544 let mut data = self.into_raw();
1545 let entries = data.len();
1546 data.resize(entries.checked_mul(4).unwrap(), 0);
1547 let mut buffer = ImageBuffer::from_vec(width, height, data).unwrap();
1548 expand_packed(&mut buffer, 4, 8, |idx, pixel| {
1549 let (r, g, b) = palette[idx as usize];
1550 let a = if let Some(t_idx) = transparent_idx {
1551 if t_idx == idx {
1552 0
1553 } else {
1554 255
1555 }
1556 } else {
1557 255
1558 };
1559 pixel[0] = r;
1560 pixel[1] = g;
1561 pixel[2] = b;
1562 pixel[3] = a;
1563 });
1564 buffer
1565 }
1566}
1567
1568impl<Container, FromType: Pixel, ToType: Pixel>
1576 ConvertBuffer<ImageBuffer<ToType, Vec<ToType::Subpixel>>> for ImageBuffer<FromType, Container>
1577where
1578 Container: Deref<Target = [FromType::Subpixel]>,
1579 ToType: FromColor<FromType>,
1580{
1581 fn convert(&self) -> ImageBuffer<ToType, Vec<ToType::Subpixel>> {
1595 let mut buffer: ImageBuffer<ToType, Vec<ToType::Subpixel>> =
1596 ImageBuffer::new(self.width, self.height);
1597 buffer.copy_color_space_from(self);
1598 for (to, from) in buffer.pixels_mut().zip(self.pixels()) {
1599 to.from_color(from);
1600 }
1601 buffer
1602 }
1603}
1604
1605#[non_exhaustive]
1607#[derive(Default)]
1608pub struct ConvertColorOptions {
1609 pub(crate) transform: Option<CicpTransform>,
1615 pub(crate) _auto_traits: PhantomData<alloc::rc::Rc<()>>,
1620}
1621
1622impl ConvertColorOptions {
1623 pub(crate) fn as_transform(
1624 &mut self,
1625 from_color: Cicp,
1626 into_color: Cicp,
1627 ) -> Result<&CicpTransform, ImageError> {
1628 if let Some(tr) = &self.transform {
1629 tr.check_applicable(from_color, into_color)?;
1630 }
1631
1632 if self.transform.is_none() {
1633 self.transform = CicpTransform::new(from_color, into_color);
1634 }
1635
1636 self.transform.as_ref().ok_or_else(|| {
1637 ImageError::Unsupported(UnsupportedError::from_format_and_kind(
1638 crate::error::ImageFormatHint::Unknown,
1639 UnsupportedErrorKind::ColorspaceCicp(if from_color.qualify_stability() {
1641 into_color
1642 } else {
1643 from_color
1644 }),
1645 ))
1646 })
1647 }
1648
1649 pub(crate) fn as_transform_fn<FromType, IntoType>(
1650 &mut self,
1651 from_color: Cicp,
1652 into_color: Cicp,
1653 ) -> Result<&'_ CicpApplicable<'_, FromType::Subpixel>, ImageError>
1654 where
1655 FromType: PixelWithColorType,
1656 IntoType: PixelWithColorType,
1657 {
1658 Ok(self
1659 .as_transform(from_color, into_color)?
1660 .supported_transform_fn::<FromType, IntoType>())
1661 }
1662}
1663
1664impl<C, SelfPixel: Pixel> ImageBuffer<SelfPixel, C>
1665where
1666 SelfPixel: PixelWithColorType,
1667 C: Deref<Target = [SelfPixel::Subpixel]> + DerefMut,
1668{
1669 pub(crate) fn cast_in_color_space<IntoPixel>(
1680 &self,
1681 ) -> ImageBuffer<IntoPixel, Vec<IntoPixel::Subpixel>>
1682 where
1683 SelfPixel: Pixel,
1684 IntoPixel: Pixel,
1685 IntoPixel: CicpPixelCast<SelfPixel>,
1686 SelfPixel::Subpixel: ColorComponentForCicp,
1687 IntoPixel::Subpixel: ColorComponentForCicp + FromPrimitive<SelfPixel::Subpixel>,
1688 {
1689 let vec = self
1690 .color
1691 .cast_pixels::<SelfPixel, IntoPixel>(self.inner_pixels(), &|| [0.2126, 0.7152, 0.0722]);
1692 let mut buffer = ImageBuffer::from_vec(self.width, self.height, vec)
1693 .expect("cast_pixels returned the right number of pixels");
1694 buffer.copy_color_space_from(self);
1695 buffer
1696 }
1697
1698 pub fn copy_from_color_space<FromType, D>(
1712 &mut self,
1713 from: &ImageBuffer<FromType, D>,
1714 mut options: ConvertColorOptions,
1715 ) -> ImageResult<()>
1716 where
1717 FromType: Pixel<Subpixel = SelfPixel::Subpixel> + PixelWithColorType,
1718 D: Deref<Target = [SelfPixel::Subpixel]>,
1719 {
1720 if self.dimensions() != from.dimensions() {
1721 return Err(ImageError::Parameter(ParameterError::from_kind(
1722 ParameterErrorKind::DimensionMismatch,
1723 )));
1724 }
1725
1726 let transform = options
1727 .as_transform_fn::<FromType, SelfPixel>(from.color_space(), self.color_space())?;
1728
1729 let from = from.inner_pixels();
1730 let into = self.inner_pixels_mut();
1731
1732 debug_assert_eq!(
1733 from.len() / usize::from(FromType::CHANNEL_COUNT),
1734 into.len() / usize::from(SelfPixel::CHANNEL_COUNT),
1735 "Diverging pixel count despite same size",
1736 );
1737
1738 transform(from, into);
1739
1740 Ok(())
1741 }
1742
1743 pub fn to_color_space<IntoType>(
1751 &self,
1752 color: Cicp,
1753 mut options: ConvertColorOptions,
1754 ) -> Result<ImageBuffer<IntoType, Vec<SelfPixel::Subpixel>>, ImageError>
1755 where
1756 IntoType: Pixel<Subpixel = SelfPixel::Subpixel> + PixelWithColorType,
1757 {
1758 let transform =
1759 options.as_transform_fn::<SelfPixel, IntoType>(self.color_space(), color)?;
1760
1761 let (width, height) = self.dimensions();
1762 let mut target = ImageBuffer::new(width, height);
1763
1764 let from = self.inner_pixels();
1765 let into = target.inner_pixels_mut();
1766
1767 transform(from, into);
1768
1769 Ok(target)
1770 }
1771
1772 pub fn apply_color_space(
1774 &mut self,
1775 color: Cicp,
1776 mut options: ConvertColorOptions,
1777 ) -> ImageResult<()> {
1778 if self.color_space() == color {
1779 return Ok(());
1780 }
1781
1782 let transform =
1783 options.as_transform_fn::<SelfPixel, SelfPixel>(self.color_space(), color)?;
1784
1785 let mut scratch = [<SelfPixel::Subpixel as crate::Primitive>::DEFAULT_MIN_VALUE; 1200];
1786 let chunk_len = scratch.len() / usize::from(<SelfPixel as Pixel>::CHANNEL_COUNT)
1787 * usize::from(<SelfPixel as Pixel>::CHANNEL_COUNT);
1788
1789 for chunk in self.data.chunks_mut(chunk_len) {
1790 let scratch = &mut scratch[..chunk.len()];
1791 scratch.copy_from_slice(chunk);
1792 transform(scratch, chunk);
1793 }
1794
1795 self.color = color.into_rgb();
1796
1797 Ok(())
1798 }
1799}
1800
1801pub type RgbImage = ImageBuffer<Rgb<u8>, Vec<u8>>;
1803pub type RgbaImage = ImageBuffer<Rgba<u8>, Vec<u8>>;
1805pub type GrayImage = ImageBuffer<Luma<u8>, Vec<u8>>;
1807pub type GrayAlphaImage = ImageBuffer<LumaA<u8>, Vec<u8>>;
1809pub(crate) type Rgb16Image = ImageBuffer<Rgb<u16>, Vec<u16>>;
1811pub(crate) type Rgba16Image = ImageBuffer<Rgba<u16>, Vec<u16>>;
1813pub(crate) type Gray16Image = ImageBuffer<Luma<u16>, Vec<u16>>;
1815pub(crate) type GrayAlpha16Image = ImageBuffer<LumaA<u16>, Vec<u16>>;
1817
1818pub type Rgb32FImage = ImageBuffer<Rgb<f32>, Vec<f32>>;
1821
1822pub type Rgba32FImage = ImageBuffer<Rgba<f32>, Vec<f32>>;
1825
1826impl From<DynamicImage> for RgbImage {
1827 fn from(value: DynamicImage) -> Self {
1828 value.into_rgb8()
1829 }
1830}
1831
1832impl From<DynamicImage> for RgbaImage {
1833 fn from(value: DynamicImage) -> Self {
1834 value.into_rgba8()
1835 }
1836}
1837
1838impl From<DynamicImage> for GrayImage {
1839 fn from(value: DynamicImage) -> Self {
1840 value.into_luma8()
1841 }
1842}
1843
1844impl From<DynamicImage> for GrayAlphaImage {
1845 fn from(value: DynamicImage) -> Self {
1846 value.into_luma_alpha8()
1847 }
1848}
1849
1850impl From<DynamicImage> for Rgb16Image {
1851 fn from(value: DynamicImage) -> Self {
1852 value.into_rgb16()
1853 }
1854}
1855
1856impl From<DynamicImage> for Rgba16Image {
1857 fn from(value: DynamicImage) -> Self {
1858 value.into_rgba16()
1859 }
1860}
1861
1862impl From<DynamicImage> for Gray16Image {
1863 fn from(value: DynamicImage) -> Self {
1864 value.into_luma16()
1865 }
1866}
1867
1868impl From<DynamicImage> for GrayAlpha16Image {
1869 fn from(value: DynamicImage) -> Self {
1870 value.into_luma_alpha16()
1871 }
1872}
1873
1874impl From<DynamicImage> for Rgba32FImage {
1875 fn from(value: DynamicImage) -> Self {
1876 value.into_rgba32f()
1877 }
1878}
1879
1880#[cfg(test)]
1881mod test {
1882 use super::{GrayImage, ImageBuffer, RgbImage};
1883 use crate::math::Rect;
1884 use crate::metadata::Cicp;
1885 use crate::metadata::CicpTransform;
1886 use crate::ImageFormat;
1887 use crate::{GenericImage as _, GenericImageView as _};
1888 use crate::{Luma, LumaA, Pixel, Rgb, Rgba};
1889 use num_traits::Zero;
1890
1891 #[test]
1892 fn slice_buffer() {
1894 let data = [0; 9];
1895 let buf: ImageBuffer<Luma<u8>, _> = ImageBuffer::from_raw(3, 3, &data[..]).unwrap();
1896 assert_eq!(&*buf, &data[..]);
1897 }
1898
1899 macro_rules! new_buffer_zero_test {
1900 ($test_name:ident, $pxt:ty) => {
1901 #[test]
1902 fn $test_name() {
1903 let buffer = ImageBuffer::<$pxt, Vec<<$pxt as Pixel>::Subpixel>>::new(2, 2);
1904 assert!(buffer
1905 .iter()
1906 .all(|p| *p == <$pxt as Pixel>::Subpixel::zero()));
1907 }
1908 };
1909 }
1910
1911 new_buffer_zero_test!(luma_u8_zero_test, Luma<u8>);
1912 new_buffer_zero_test!(luma_u16_zero_test, Luma<u16>);
1913 new_buffer_zero_test!(luma_f32_zero_test, Luma<f32>);
1914 new_buffer_zero_test!(luma_a_u8_zero_test, LumaA<u8>);
1915 new_buffer_zero_test!(luma_a_u16_zero_test, LumaA<u16>);
1916 new_buffer_zero_test!(luma_a_f32_zero_test, LumaA<f32>);
1917 new_buffer_zero_test!(rgb_u8_zero_test, Rgb<u8>);
1918 new_buffer_zero_test!(rgb_u16_zero_test, Rgb<u16>);
1919 new_buffer_zero_test!(rgb_f32_zero_test, Rgb<f32>);
1920 new_buffer_zero_test!(rgb_a_u8_zero_test, Rgba<u8>);
1921 new_buffer_zero_test!(rgb_a_u16_zero_test, Rgba<u16>);
1922 new_buffer_zero_test!(rgb_a_f32_zero_test, Rgba<f32>);
1923
1924 #[test]
1925 fn get_pixel() {
1926 let mut a: RgbImage = ImageBuffer::new(10, 10);
1927 {
1928 let b = a.get_mut(3 * 10).unwrap();
1929 *b = 255;
1930 }
1931 assert_eq!(a.get_pixel(0, 1)[0], 255);
1932 }
1933
1934 #[test]
1935 fn get_pixel_checked() {
1936 let mut a: RgbImage = ImageBuffer::new(10, 10);
1937 a.get_pixel_mut_checked(0, 1).unwrap()[0] = 255;
1938
1939 assert_eq!(a.get_pixel_checked(0, 1), Some(&Rgb([255, 0, 0])));
1940 assert_eq!(a.get_pixel_checked(0, 1).unwrap(), a.get_pixel(0, 1));
1941 assert_eq!(a.get_pixel_checked(10, 0), None);
1942 assert_eq!(a.get_pixel_checked(0, 10), None);
1943 assert_eq!(a.get_pixel_mut_checked(10, 0), None);
1944 assert_eq!(a.get_pixel_mut_checked(0, 10), None);
1945
1946 const WHITE: Rgb<u8> = Rgb([255_u8, 255, 255]);
1948 let mut a = RgbImage::new(2, 1);
1949 a.put_pixel(1, 0, WHITE);
1950
1951 assert_eq!(a.get_pixel_checked(1, 0), Some(&WHITE));
1952 assert_eq!(a.get_pixel_checked(1, 0).unwrap(), a.get_pixel(1, 0));
1953 }
1954
1955 #[test]
1956 fn mut_iter() {
1957 let mut a: RgbImage = ImageBuffer::new(10, 10);
1958 {
1959 let val = a.pixels_mut().next().unwrap();
1960 *val = Rgb([42, 0, 0]);
1961 }
1962 assert_eq!(a.data[0], 42);
1963 }
1964
1965 #[test]
1966 fn zero_width_zero_height() {
1967 let mut image = RgbImage::new(0, 0);
1968
1969 assert_eq!(image.rows_mut().count(), 0);
1970 assert_eq!(image.pixels_mut().count(), 0);
1971 assert_eq!(image.rows().count(), 0);
1972 assert_eq!(image.pixels().count(), 0);
1973 }
1974
1975 #[test]
1976 fn zero_width_nonzero_height() {
1977 let mut image = RgbImage::new(0, 2);
1978
1979 assert_eq!(image.rows_mut().count(), 0);
1980 assert_eq!(image.pixels_mut().count(), 0);
1981 assert_eq!(image.rows().count(), 0);
1982 assert_eq!(image.pixels().count(), 0);
1983 }
1984
1985 #[test]
1986 fn nonzero_width_zero_height() {
1987 let mut image = RgbImage::new(2, 0);
1988
1989 assert_eq!(image.rows_mut().count(), 0);
1990 assert_eq!(image.pixels_mut().count(), 0);
1991 assert_eq!(image.rows().count(), 0);
1992 assert_eq!(image.pixels().count(), 0);
1993 }
1994
1995 #[test]
1996 fn pixels_on_large_buffer() {
1997 let mut image = RgbImage::from_raw(1, 1, vec![0; 6]).unwrap();
1998
1999 assert_eq!(image.pixels().count(), 1);
2000 assert_eq!(image.enumerate_pixels().count(), 1);
2001 assert_eq!(image.pixels_mut().count(), 1);
2002 assert_eq!(image.enumerate_pixels_mut().count(), 1);
2003
2004 assert_eq!(image.rows().count(), 1);
2005 assert_eq!(image.rows_mut().count(), 1);
2006 }
2007
2008 #[test]
2009 fn default() {
2010 let image = ImageBuffer::<Rgb<u8>, Vec<u8>>::default();
2011 assert_eq!(image.dimensions(), (0, 0));
2012 }
2013
2014 #[test]
2015 #[rustfmt::skip]
2016 fn test_image_buffer_copy_within_oob() {
2017 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, vec![0u8; 16]).unwrap();
2018 assert!(!image.copy_within(Rect { x: 0, y: 0, width: 5, height: 4 }, 0, 0));
2019 assert!(!image.copy_within(Rect { x: 0, y: 0, width: 4, height: 5 }, 0, 0));
2020 assert!(!image.copy_within(Rect { x: 1, y: 0, width: 4, height: 4 }, 0, 0));
2021 assert!(!image.copy_within(Rect { x: 0, y: 0, width: 4, height: 4 }, 1, 0));
2022 assert!(!image.copy_within(Rect { x: 0, y: 1, width: 4, height: 4 }, 0, 0));
2023 assert!(!image.copy_within(Rect { x: 0, y: 0, width: 4, height: 4 }, 0, 1));
2024 assert!(!image.copy_within(Rect { x: 1, y: 1, width: 4, height: 4 }, 0, 0));
2025 }
2026
2027 #[test]
2028 fn test_image_buffer_copy_within_tl() {
2029 let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
2030 let expected = [0, 1, 2, 3, 4, 0, 1, 2, 8, 4, 5, 6, 12, 8, 9, 10];
2031 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
2032 assert!(image.copy_within(
2033 Rect {
2034 x: 0,
2035 y: 0,
2036 width: 3,
2037 height: 3
2038 },
2039 1,
2040 1
2041 ));
2042 assert_eq!(&image.into_raw(), &expected);
2043 }
2044
2045 #[test]
2046 fn test_image_buffer_copy_within_tr() {
2047 let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
2048 let expected = [0, 1, 2, 3, 1, 2, 3, 7, 5, 6, 7, 11, 9, 10, 11, 15];
2049 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
2050 assert!(image.copy_within(
2051 Rect {
2052 x: 1,
2053 y: 0,
2054 width: 3,
2055 height: 3
2056 },
2057 0,
2058 1
2059 ));
2060 assert_eq!(&image.into_raw(), &expected);
2061 }
2062
2063 #[test]
2064 fn test_image_buffer_copy_within_bl() {
2065 let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
2066 let expected = [0, 4, 5, 6, 4, 8, 9, 10, 8, 12, 13, 14, 12, 13, 14, 15];
2067 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
2068 assert!(image.copy_within(
2069 Rect {
2070 x: 0,
2071 y: 1,
2072 width: 3,
2073 height: 3
2074 },
2075 1,
2076 0
2077 ));
2078 assert_eq!(&image.into_raw(), &expected);
2079 }
2080
2081 #[test]
2082 fn test_image_buffer_copy_within_br() {
2083 let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
2084 let expected = [5, 6, 7, 3, 9, 10, 11, 7, 13, 14, 15, 11, 12, 13, 14, 15];
2085 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
2086 assert!(image.copy_within(
2087 Rect {
2088 x: 1,
2089 y: 1,
2090 width: 3,
2091 height: 3
2092 },
2093 0,
2094 0
2095 ));
2096 assert_eq!(&image.into_raw(), &expected);
2097 }
2098
2099 #[test]
2100 #[cfg(feature = "png")]
2101 fn write_to_with_large_buffer() {
2102 let img: GrayImage = ImageBuffer::from_raw(1, 1, vec![0u8; 4]).unwrap();
2105 let mut buffer = no_std_io::io::Cursor::new(vec![]);
2106 assert!(img.write_to(&mut buffer, ImageFormat::Png).is_ok());
2107 }
2108
2109 #[test]
2110 fn exact_size_iter_size_hint() {
2111 const N: u32 = 10;
2116
2117 let mut image = RgbImage::from_raw(N, N, vec![0; (N * N * 3) as usize]).unwrap();
2118
2119 let iter = image.pixels();
2120 let exact_len = ExactSizeIterator::len(&iter);
2121 assert_eq!(iter.size_hint(), (exact_len, Some(exact_len)));
2122
2123 let iter = image.pixels_mut();
2124 let exact_len = ExactSizeIterator::len(&iter);
2125 assert_eq!(iter.size_hint(), (exact_len, Some(exact_len)));
2126
2127 let iter = image.rows();
2128 let exact_len = ExactSizeIterator::len(&iter);
2129 assert_eq!(iter.size_hint(), (exact_len, Some(exact_len)));
2130
2131 let iter = image.rows_mut();
2132 let exact_len = ExactSizeIterator::len(&iter);
2133 assert_eq!(iter.size_hint(), (exact_len, Some(exact_len)));
2134
2135 let iter = image.enumerate_pixels();
2136 let exact_len = ExactSizeIterator::len(&iter);
2137 assert_eq!(iter.size_hint(), (exact_len, Some(exact_len)));
2138
2139 let iter = image.enumerate_rows();
2140 let exact_len = ExactSizeIterator::len(&iter);
2141 assert_eq!(iter.size_hint(), (exact_len, Some(exact_len)));
2142
2143 let iter = image.enumerate_pixels_mut();
2144 let exact_len = ExactSizeIterator::len(&iter);
2145 assert_eq!(iter.size_hint(), (exact_len, Some(exact_len)));
2146
2147 let iter = image.enumerate_rows_mut();
2148 let exact_len = ExactSizeIterator::len(&iter);
2149 assert_eq!(iter.size_hint(), (exact_len, Some(exact_len)));
2150 }
2151
2152 #[test]
2153 fn color_conversion() {
2154 let mut source = ImageBuffer::from_fn(128, 128, |_, _| Rgb([255, 0, 0]));
2155 let mut target = ImageBuffer::from_fn(128, 128, |_, _| Rgba(Default::default()));
2156
2157 source.set_rgb_primaries(Cicp::SRGB.primaries);
2158 source.set_transfer_function(Cicp::SRGB.transfer);
2159
2160 target.set_rgb_primaries(Cicp::DISPLAY_P3.primaries);
2161 target.set_transfer_function(Cicp::DISPLAY_P3.transfer);
2162
2163 let result = target.copy_from_color_space(&source, Default::default());
2164
2165 assert!(result.is_ok(), "{result:?}");
2166 assert_eq!(target[(0, 0)], Rgba([234u8, 51, 35, 255]));
2167 }
2168
2169 #[test]
2170 fn gray_conversions() {
2171 let mut source = ImageBuffer::from_fn(128, 128, |_, _| Luma([255u8]));
2172 let mut target = ImageBuffer::from_fn(128, 128, |_, _| Rgba(Default::default()));
2173
2174 source.set_rgb_primaries(Cicp::SRGB.primaries);
2175 source.set_transfer_function(Cicp::SRGB.transfer);
2176
2177 target.set_rgb_primaries(Cicp::SRGB.primaries);
2178 target.set_transfer_function(Cicp::SRGB.transfer);
2179
2180 let result = target.copy_from_color_space(&source, Default::default());
2181
2182 assert!(result.is_ok(), "{result:?}");
2183 assert_eq!(target[(0, 0)], Rgba([u8::MAX; 4]));
2184 }
2185
2186 #[test]
2187 fn rgb_to_gray_conversion() {
2188 let mut source = ImageBuffer::from_fn(128, 128, |_, _| Rgb([128u8; 3]));
2189 let mut target = ImageBuffer::from_fn(128, 128, |_, _| Luma(Default::default()));
2190
2191 source.set_rgb_primaries(Cicp::SRGB.primaries);
2192 source.set_transfer_function(Cicp::SRGB.transfer);
2193
2194 target.set_rgb_primaries(Cicp::SRGB.primaries);
2195 target.set_transfer_function(Cicp::SRGB.transfer);
2196
2197 let result = target.copy_from_color_space(&source, Default::default());
2198
2199 assert!(result.is_ok(), "{result:?}");
2200 assert_eq!(target[(0, 0)], Luma([128u8]));
2201 }
2202
2203 #[test]
2204 fn apply_color() {
2205 let mut buffer = ImageBuffer::from_fn(128, 128, |_, _| Rgb([255u8, 0, 0]));
2206
2207 buffer.set_rgb_primaries(Cicp::SRGB.primaries);
2208 buffer.set_transfer_function(Cicp::SRGB.transfer);
2209
2210 buffer
2211 .apply_color_space(Cicp::DISPLAY_P3, Default::default())
2212 .expect("supported transform");
2213
2214 buffer.pixels().for_each(|&p| {
2215 assert_eq!(p, Rgb([234u8, 51, 35]));
2216 });
2217 }
2218
2219 #[test]
2220 fn to_color() {
2221 let mut source = ImageBuffer::from_fn(128, 128, |_, _| Rgba([255u8, 0, 0, 255]));
2222 source.set_rgb_primaries(Cicp::SRGB.primaries);
2223 source.set_transfer_function(Cicp::SRGB.transfer);
2224
2225 let target = source
2226 .to_color_space::<Rgb<u8>>(Cicp::DISPLAY_P3, Default::default())
2227 .expect("supported transform");
2228
2229 assert_eq!(target[(0, 0)], Rgb([234u8, 51, 35]));
2230 }
2231
2232 #[test]
2233 fn transformation_mismatch() {
2234 let mut source = ImageBuffer::from_fn(128, 128, |_, _| Luma([255u8]));
2235 let mut target = ImageBuffer::from_fn(128, 128, |_, _| Rgba(Default::default()));
2236
2237 source.set_color_space(Cicp::SRGB).unwrap();
2238 target.set_color_space(Cicp::DISPLAY_P3).unwrap();
2239
2240 let options = super::ConvertColorOptions {
2241 transform: CicpTransform::new(Cicp::SRGB, Cicp::SRGB),
2242 ..super::ConvertColorOptions::default()
2243 };
2244
2245 let result = target.copy_from_color_space(&source, options);
2246 assert!(matches!(result, Err(crate::ImageError::Parameter(_))));
2247 }
2248
2249 #[test]
2251 fn copy_from_subimage_to_middle() {
2252 let mut source = RgbImage::new(16, 16);
2253 let mut target = RgbImage::new(16, 16);
2254
2255 source.put_pixel(8, 8, Rgb([255, 8, 8]));
2256 source.put_pixel(9, 8, Rgb([255, 9, 8]));
2257 source.put_pixel(9, 9, Rgb([255, 9, 9]));
2258
2259 let view = source.view(8, 8, 2, 2);
2260 assert!(target.copy_from(&*view, 4, 4).is_ok());
2261
2262 assert_eq!(*target.get_pixel(4, 4), Rgb([255, 8, 8]));
2264 assert_eq!(*target.get_pixel(5, 4), Rgb([255, 9, 8]));
2265 assert_eq!(*target.get_pixel(5, 5), Rgb([255, 9, 9]));
2266
2267 assert_eq!(
2269 target.iter().copied().map(usize::from).sum::<usize>(),
2270 3 * (255 + 8 + 9)
2271 );
2272 }
2273
2274 #[test]
2275 fn copy_from_band() {
2276 let source = RgbImage::from_fn(16, 8, |x, y| Rgb([x as u8, y as u8, 0]));
2277 let mut target = RgbImage::new(16, 16);
2278
2279 assert!(target.copy_from(&source, 0, 4).is_ok());
2280
2281 let lhs = source.chunks_exact(48);
2282 let rhs = target.chunks_exact(48).skip(4).take(8);
2283
2284 assert!(lhs.eq(rhs));
2285 }
2286
2287 #[test]
2288 fn copy_from_pixel() {
2289 let bg = Rgb([255, 0, 128]);
2290 let samples = crate::flat::FlatSamples::with_monocolor(&bg, 4, 4);
2291 let source = samples.as_view().unwrap();
2292
2293 let mut target = RgbImage::new(16, 16);
2294 assert!(target.copy_from(&source, 4, 4).is_ok());
2295
2296 for i in 4..8 {
2297 for j in 4..8 {
2298 assert_eq!(*target.get_pixel(i, j), bg);
2299 }
2300 }
2301
2302 assert_eq!(
2303 target.iter().copied().map(usize::from).sum::<usize>(),
2304 16 * (255 + 128)
2305 );
2306 }
2307
2308 #[test]
2309 fn copy_from_strided() {
2310 #[rustfmt::skip]
2311 let sample_data = [
2312 1, 0xff, 0, 0, 2, 0xff,
2313 3, 0xff, 0, 0, 4, 0xff
2314 ];
2315
2316 let samples = crate::flat::FlatSamples {
2317 samples: &sample_data,
2318 layout: crate::flat::SampleLayout {
2319 channels: 2,
2320 channel_stride: 1,
2321 width: 2,
2322 width_stride: 4,
2323 height: 2,
2324 height_stride: 6,
2325 },
2326 color_hint: None,
2327 };
2328
2329 let source = samples.as_view::<LumaA<u8>>().unwrap();
2330 let mut target = crate::GrayAlphaImage::new(16, 16);
2331 assert!(target.copy_from(&source, 4, 4).is_ok());
2332
2333 assert_eq!(*target.get_pixel(4, 4), LumaA([1, 0xff]));
2334 assert_eq!(*target.get_pixel(5, 4), LumaA([2, 0xff]));
2335 assert_eq!(*target.get_pixel(4, 5), LumaA([3, 0xff]));
2336 assert_eq!(*target.get_pixel(5, 5), LumaA([4, 0xff]));
2337
2338 assert_eq!(
2339 target.iter().copied().map(usize::from).sum::<usize>(),
2340 sample_data.iter().copied().map(usize::from).sum::<usize>(),
2341 );
2342 }
2343
2344 #[test]
2345 fn copy_from_strided_subimage() {
2346 #[rustfmt::skip]
2347 let sample_data = [
2348 1, 0xff, 0, 0, 2, 0xff,
2349 3, 0xff, 0, 0, 4, 0xff
2350 ];
2351
2352 let samples = crate::flat::FlatSamples {
2353 samples: &sample_data,
2354 layout: crate::flat::SampleLayout {
2355 channels: 2,
2356 channel_stride: 1,
2357 width: 2,
2358 width_stride: 4,
2359 height: 2,
2360 height_stride: 6,
2361 },
2362 color_hint: None,
2363 };
2364
2365 let view = samples.as_view::<LumaA<u8>>().unwrap();
2366 let source = view.view(1, 0, 1, 2);
2367
2368 let mut target = crate::GrayAlphaImage::new(16, 16);
2369 assert!(target.copy_from(&*source, 4, 4).is_ok());
2370
2371 assert_eq!(*target.get_pixel(4, 4), LumaA([2, 0xff]));
2372 assert_eq!(*target.get_pixel(4, 5), LumaA([4, 0xff]));
2373
2374 assert_eq!(
2375 target.iter().copied().map(usize::from).sum::<usize>(),
2376 2usize + 0xff + 4 + 0xff
2377 );
2378 }
2379
2380 #[test]
2381 fn copy_from_subimage_subimage() {
2382 let mut source = RgbImage::new(16, 16);
2383 let mut target = RgbImage::new(16, 16);
2384
2385 source.put_pixel(8, 8, Rgb([255, 8, 8]));
2386 source.put_pixel(9, 8, Rgb([255, 9, 8]));
2387 source.put_pixel(9, 9, Rgb([255, 9, 9]));
2388
2389 let view = source.view(8, 8, 2, 2);
2390 let view = view.view(1, 0, 1, 1);
2391 assert!(target.copy_from(&*view, 4, 4).is_ok());
2392
2393 assert_eq!(*target.get_pixel(4, 4), Rgb([255, 9, 8]));
2395
2396 assert_eq!(
2398 target.iter().copied().map(usize::from).sum::<usize>(),
2399 255 + 9 + 8
2400 );
2401 }
2402}
2403
2404#[cfg(test)]
2405#[cfg(feature = "benchmarks")]
2406mod benchmarks {
2407 use super::{ConvertBuffer, GrayImage, ImageBuffer, Pixel, RgbImage};
2408
2409 #[bench]
2410 fn conversion(b: &mut test::Bencher) {
2411 let mut a: RgbImage = ImageBuffer::new(1000, 1000);
2412 for p in a.pixels_mut() {
2413 let rgb = p.channels_mut();
2414 rgb[0] = 255;
2415 rgb[1] = 23;
2416 rgb[2] = 42;
2417 }
2418
2419 assert!(a.data[0] != 0);
2420 b.iter(|| {
2421 let b: GrayImage = a.convert();
2422 assert!(0 != b.data[0]);
2423 assert!(a.data[0] != b.data[0]);
2424 test::black_box(b);
2425 });
2426 b.bytes = 1000 * 1000 * 3;
2427 }
2428
2429 #[bench]
2430 fn image_access_row_by_row(b: &mut test::Bencher) {
2431 let mut a: RgbImage = ImageBuffer::new(1000, 1000);
2432 for p in a.pixels_mut() {
2433 let rgb = p.channels_mut();
2434 rgb[0] = 255;
2435 rgb[1] = 23;
2436 rgb[2] = 42;
2437 }
2438
2439 b.iter(move || {
2440 let image: &RgbImage = test::black_box(&a);
2441 let mut sum: usize = 0;
2442 for y in 0..1000 {
2443 for x in 0..1000 {
2444 let pixel = image.get_pixel(x, y);
2445 sum = sum.wrapping_add(pixel[0] as usize);
2446 sum = sum.wrapping_add(pixel[1] as usize);
2447 sum = sum.wrapping_add(pixel[2] as usize);
2448 }
2449 }
2450 test::black_box(sum)
2451 });
2452
2453 b.bytes = 1000 * 1000 * 3;
2454 }
2455
2456 #[bench]
2457 fn image_access_col_by_col(b: &mut test::Bencher) {
2458 let mut a: RgbImage = ImageBuffer::new(1000, 1000);
2459 for p in a.pixels_mut() {
2460 let rgb = p.channels_mut();
2461 rgb[0] = 255;
2462 rgb[1] = 23;
2463 rgb[2] = 42;
2464 }
2465
2466 b.iter(move || {
2467 let image: &RgbImage = test::black_box(&a);
2468 let mut sum: usize = 0;
2469 for x in 0..1000 {
2470 for y in 0..1000 {
2471 let pixel = image.get_pixel(x, y);
2472 sum = sum.wrapping_add(pixel[0] as usize);
2473 sum = sum.wrapping_add(pixel[1] as usize);
2474 sum = sum.wrapping_add(pixel[2] as usize);
2475 }
2476 }
2477 test::black_box(sum)
2478 });
2479
2480 b.bytes = 1000 * 1000 * 3;
2481 }
2482}