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