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};
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 where
867 Container: AsRef<[P::Subpixel]>,
868 {
869 let layout = self.sample_layout();
870 FlatSamples {
871 samples: self.data.as_ref(),
872 layout,
873 color_hint: None, }
875 }
876
877 pub fn as_flat_samples_mut(&mut self) -> FlatSamples<&mut [P::Subpixel]>
881 where
882 Container: AsMut<[P::Subpixel]>,
883 {
884 let layout = self.sample_layout();
885 FlatSamples {
886 samples: self.data.as_mut(),
887 layout,
888 color_hint: None, }
890 }
891}
892
893impl<P, Container> ImageBuffer<P, Container>
894where
895 P: Pixel,
896 Container: Deref<Target = [P::Subpixel]> + DerefMut,
897{
898 pub(crate) fn inner_pixels_mut(&mut self) -> &mut [P::Subpixel] {
900 let len = Self::image_buffer_len(self.width, self.height).unwrap();
901 &mut self.data[..len]
902 }
903
904 pub fn pixels_mut(&mut self) -> PixelsMut<'_, P> {
906 PixelsMut {
907 chunks: self
908 .inner_pixels_mut()
909 .chunks_exact_mut(<P as Pixel>::CHANNEL_COUNT as usize),
910 }
911 }
912
913 pub fn rows_mut(&mut self) -> RowsMut<'_, P> {
919 RowsMut::with_image(&mut self.data, self.width, self.height)
920 }
921
922 pub fn enumerate_pixels_mut(&mut self) -> EnumeratePixelsMut<'_, P> {
926 let width = self.width;
927 EnumeratePixelsMut {
928 pixels: self.pixels_mut(),
929 x: 0,
930 y: 0,
931 width,
932 }
933 }
934
935 pub fn enumerate_rows_mut(&mut self) -> EnumerateRowsMut<'_, P> {
939 let width = self.width;
940 EnumerateRowsMut {
941 rows: self.rows_mut(),
942 y: 0,
943 width,
944 }
945 }
946
947 #[inline]
953 #[track_caller]
954 pub fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut P {
955 match self.pixel_indices(x, y) {
956 None => panic!(
957 "Image index {:?} out of bounds {:?}",
958 (x, y),
959 (self.width, self.height)
960 ),
961 Some(pixel_indices) => <P as Pixel>::from_slice_mut(&mut self.data[pixel_indices]),
962 }
963 }
964
965 pub fn get_pixel_mut_checked(&mut self, x: u32, y: u32) -> Option<&mut P> {
968 if x >= self.width {
969 return None;
970 }
971 let num_channels = <P as Pixel>::CHANNEL_COUNT as usize;
972 let i = (y as usize)
973 .saturating_mul(self.width as usize)
974 .saturating_add(x as usize)
975 .saturating_mul(num_channels);
976
977 self.data
978 .get_mut(i..i.checked_add(num_channels)?)
979 .map(|pixel_indices| <P as Pixel>::from_slice_mut(pixel_indices))
980 }
981
982 #[inline]
988 #[track_caller]
989 pub fn put_pixel(&mut self, x: u32, y: u32, pixel: P) {
990 *self.get_pixel_mut(x, y) = pixel;
991 }
992}
993
994impl<P: Pixel, Container> ImageBuffer<P, Container> {
995 pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) {
1008 self.color.primaries = color;
1009 }
1010
1011 pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) {
1020 self.color.transfer = tf;
1021 }
1022
1023 pub fn color_space(&self) -> Cicp {
1025 self.color.into()
1026 }
1027
1028 pub fn set_color_space(&mut self, cicp: Cicp) -> ImageResult<()> {
1033 self.color = cicp.try_into_rgb()?;
1034 Ok(())
1035 }
1036
1037 pub(crate) fn set_rgb_color_space(&mut self, color: CicpRgb) {
1038 self.color = color;
1039 }
1040}
1041
1042impl<P, Container> ImageBuffer<P, Container>
1043where
1044 P: Pixel,
1045 [P::Subpixel]: EncodableLayout,
1046 Container: Deref<Target = [P::Subpixel]>,
1047{
1048 pub fn save<Q>(&self, path: Q) -> ImageResult<()>
1052 where
1053 Q: AsRef<Path>,
1054 P: PixelWithColorType,
1055 {
1056 save_buffer(
1057 path,
1058 self.inner_pixels().as_bytes(),
1059 self.width(),
1060 self.height(),
1061 <P as PixelWithColorType>::COLOR_TYPE,
1062 )
1063 }
1064}
1065
1066impl<P, Container> ImageBuffer<P, Container>
1067where
1068 P: Pixel,
1069 [P::Subpixel]: EncodableLayout,
1070 Container: Deref<Target = [P::Subpixel]>,
1071{
1072 pub fn save_with_format<Q>(&self, path: Q, format: ImageFormat) -> ImageResult<()>
1078 where
1079 Q: AsRef<Path>,
1080 P: PixelWithColorType,
1081 {
1082 save_buffer_with_format(
1084 path,
1085 self.inner_pixels().as_bytes(),
1086 self.width(),
1087 self.height(),
1088 <P as PixelWithColorType>::COLOR_TYPE,
1089 format,
1090 )
1091 }
1092}
1093
1094impl<P, Container> ImageBuffer<P, Container>
1095where
1096 P: Pixel,
1097 [P::Subpixel]: EncodableLayout,
1098 Container: Deref<Target = [P::Subpixel]>,
1099{
1100 pub fn write_to<W>(&self, writer: &mut W, format: ImageFormat) -> ImageResult<()>
1105 where
1106 W: std::io::Write + std::io::Seek,
1107 P: PixelWithColorType,
1108 {
1109 write_buffer_with_format(
1111 writer,
1112 self.inner_pixels().as_bytes(),
1113 self.width(),
1114 self.height(),
1115 <P as PixelWithColorType>::COLOR_TYPE,
1116 format,
1117 )
1118 }
1119}
1120
1121impl<P, Container> ImageBuffer<P, Container>
1122where
1123 P: Pixel,
1124 [P::Subpixel]: EncodableLayout,
1125 Container: Deref<Target = [P::Subpixel]>,
1126{
1127 pub fn write_with_encoder<E>(&self, encoder: E) -> ImageResult<()>
1129 where
1130 E: ImageEncoder,
1131 P: PixelWithColorType,
1132 {
1133 encoder.write_image(
1135 self.inner_pixels().as_bytes(),
1136 self.width(),
1137 self.height(),
1138 <P as PixelWithColorType>::COLOR_TYPE,
1139 )
1140 }
1141}
1142
1143impl<P, Container> Default for ImageBuffer<P, Container>
1144where
1145 P: Pixel,
1146 Container: Default,
1147{
1148 fn default() -> Self {
1149 Self {
1150 width: 0,
1151 height: 0,
1152 _phantom: PhantomData,
1153 color: Cicp::SRGB_LINEAR.into_rgb(),
1154 data: Default::default(),
1155 }
1156 }
1157}
1158
1159impl<P, Container> Deref for ImageBuffer<P, Container>
1160where
1161 P: Pixel,
1162 Container: Deref<Target = [P::Subpixel]>,
1163{
1164 type Target = [P::Subpixel];
1165
1166 fn deref(&self) -> &<Self as Deref>::Target {
1167 &self.data
1168 }
1169}
1170
1171impl<P, Container> DerefMut for ImageBuffer<P, Container>
1172where
1173 P: Pixel,
1174 Container: Deref<Target = [P::Subpixel]> + DerefMut,
1175{
1176 fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
1177 &mut self.data
1178 }
1179}
1180
1181impl<P, Container> Index<(u32, u32)> for ImageBuffer<P, Container>
1182where
1183 P: Pixel,
1184 Container: Deref<Target = [P::Subpixel]>,
1185{
1186 type Output = P;
1187
1188 fn index(&self, (x, y): (u32, u32)) -> &P {
1189 self.get_pixel(x, y)
1190 }
1191}
1192
1193impl<P, Container> IndexMut<(u32, u32)> for ImageBuffer<P, Container>
1194where
1195 P: Pixel,
1196 Container: Deref<Target = [P::Subpixel]> + DerefMut,
1197{
1198 fn index_mut(&mut self, (x, y): (u32, u32)) -> &mut P {
1199 self.get_pixel_mut(x, y)
1200 }
1201}
1202
1203impl<P, Container> Clone for ImageBuffer<P, Container>
1204where
1205 P: Pixel,
1206 Container: Deref<Target = [P::Subpixel]> + Clone,
1207{
1208 fn clone(&self) -> ImageBuffer<P, Container> {
1209 ImageBuffer {
1210 data: self.data.clone(),
1211 width: self.width,
1212 height: self.height,
1213 color: self.color,
1214 _phantom: PhantomData,
1215 }
1216 }
1217
1218 fn clone_from(&mut self, source: &Self) {
1219 self.data.clone_from(&source.data);
1220 self.width = source.width;
1221 self.height = source.height;
1222 self.color = source.color;
1223 }
1224}
1225
1226impl<P, Container> GenericImageView for ImageBuffer<P, Container>
1227where
1228 P: Pixel,
1229 Container: Deref<Target = [P::Subpixel]> + Deref,
1230{
1231 type Pixel = P;
1232
1233 fn dimensions(&self) -> (u32, u32) {
1234 self.dimensions()
1235 }
1236
1237 fn get_pixel(&self, x: u32, y: u32) -> P {
1238 *self.get_pixel(x, y)
1239 }
1240
1241 #[inline(always)]
1243 unsafe fn unsafe_get_pixel(&self, x: u32, y: u32) -> P {
1244 let indices = self.pixel_indices_unchecked(x, y);
1245 *<P as Pixel>::from_slice(self.data.get_unchecked(indices))
1246 }
1247
1248 fn buffer_with_dimensions(&self, width: u32, height: u32) -> ImageBuffer<P, Vec<P::Subpixel>> {
1249 let mut buffer = ImageBuffer::new(width, height);
1250 buffer.copy_color_space_from(self);
1251 buffer
1252 }
1253}
1254
1255impl<P, Container> GenericImage for ImageBuffer<P, Container>
1256where
1257 P: Pixel,
1258 Container: Deref<Target = [P::Subpixel]> + DerefMut,
1259{
1260 fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut P {
1261 self.get_pixel_mut(x, y)
1262 }
1263
1264 fn put_pixel(&mut self, x: u32, y: u32, pixel: P) {
1265 *self.get_pixel_mut(x, y) = pixel;
1266 }
1267
1268 #[inline(always)]
1270 unsafe fn unsafe_put_pixel(&mut self, x: u32, y: u32, pixel: P) {
1271 let indices = self.pixel_indices_unchecked(x, y);
1272 let p = <P as Pixel>::from_slice_mut(self.data.get_unchecked_mut(indices));
1273 *p = pixel;
1274 }
1275
1276 fn blend_pixel(&mut self, x: u32, y: u32, p: P) {
1280 self.get_pixel_mut(x, y).blend(&p);
1281 }
1282
1283 fn copy_within(&mut self, source: Rect, x: u32, y: u32) -> bool {
1284 let Rect {
1285 x: sx,
1286 y: sy,
1287 width,
1288 height,
1289 } = source;
1290 let dx = x;
1291 let dy = y;
1292 assert!(sx < self.width() && dx < self.width());
1293 assert!(sy < self.height() && dy < self.height());
1294 if self.width() - dx.max(sx) < width || self.height() - dy.max(sy) < height {
1295 return false;
1296 }
1297
1298 if sy < dy {
1299 for y in (0..height).rev() {
1300 let sy = sy + y;
1301 let dy = dy + y;
1302 let Range { start, .. } = self.pixel_indices_unchecked(sx, sy);
1303 let Range { end, .. } = self.pixel_indices_unchecked(sx + width - 1, sy);
1304 let dst = self.pixel_indices_unchecked(dx, dy).start;
1305 self.data.copy_within(start..end, dst);
1306 }
1307 } else {
1308 for y in 0..height {
1309 let sy = sy + y;
1310 let dy = dy + y;
1311 let Range { start, .. } = self.pixel_indices_unchecked(sx, sy);
1312 let Range { end, .. } = self.pixel_indices_unchecked(sx + width - 1, sy);
1313 let dst = self.pixel_indices_unchecked(dx, dy).start;
1314 self.data.copy_within(start..end, dst);
1315 }
1316 }
1317 true
1318 }
1319}
1320
1321impl<P: Pixel> ImageBuffer<P, Vec<P::Subpixel>> {
1328 #[must_use]
1338 pub fn new(width: u32, height: u32) -> ImageBuffer<P, Vec<P::Subpixel>> {
1339 let size = Self::image_buffer_len(width, height)
1340 .expect("Buffer length in `ImageBuffer::new` overflows usize");
1341 ImageBuffer {
1342 data: vec![Zero::zero(); size],
1343 width,
1344 height,
1345 color: Cicp::SRGB.into_rgb(),
1346 _phantom: PhantomData,
1347 }
1348 }
1349
1350 pub fn from_pixel(width: u32, height: u32, pixel: P) -> ImageBuffer<P, Vec<P::Subpixel>> {
1356 let mut buf = ImageBuffer::new(width, height);
1357 for p in buf.pixels_mut() {
1358 *p = pixel;
1359 }
1360 buf
1361 }
1362
1363 pub fn from_fn<F>(width: u32, height: u32, mut f: F) -> ImageBuffer<P, Vec<P::Subpixel>>
1371 where
1372 F: FnMut(u32, u32) -> P,
1373 {
1374 let mut buf = ImageBuffer::new(width, height);
1375 for (x, y, p) in buf.enumerate_pixels_mut() {
1376 *p = f(x, y);
1377 }
1378 buf
1379 }
1380
1381 #[must_use]
1384 pub fn from_vec(
1385 width: u32,
1386 height: u32,
1387 buf: Vec<P::Subpixel>,
1388 ) -> Option<ImageBuffer<P, Vec<P::Subpixel>>> {
1389 ImageBuffer::from_raw(width, height, buf)
1390 }
1391
1392 #[must_use]
1395 pub fn into_vec(self) -> Vec<P::Subpixel> {
1396 self.into_raw()
1397 }
1398
1399 pub(crate) fn copy_color_space_from<O: Pixel, C>(&mut self, other: &ImageBuffer<O, C>) {
1405 self.color = other.color;
1406 }
1407}
1408
1409pub trait ConvertBuffer<T> {
1411 fn convert(&self) -> T;
1416}
1417
1418impl GrayImage {
1420 #[must_use]
1424 pub fn expand_palette(
1425 self,
1426 palette: &[(u8, u8, u8)],
1427 transparent_idx: Option<u8>,
1428 ) -> RgbaImage {
1429 let (width, height) = self.dimensions();
1430 let mut data = self.into_raw();
1431 let entries = data.len();
1432 data.resize(entries.checked_mul(4).unwrap(), 0);
1433 let mut buffer = ImageBuffer::from_vec(width, height, data).unwrap();
1434 expand_packed(&mut buffer, 4, 8, |idx, pixel| {
1435 let (r, g, b) = palette[idx as usize];
1436 let a = if let Some(t_idx) = transparent_idx {
1437 if t_idx == idx {
1438 0
1439 } else {
1440 255
1441 }
1442 } else {
1443 255
1444 };
1445 pixel[0] = r;
1446 pixel[1] = g;
1447 pixel[2] = b;
1448 pixel[3] = a;
1449 });
1450 buffer
1451 }
1452}
1453
1454impl<Container, FromType: Pixel, ToType: Pixel>
1462 ConvertBuffer<ImageBuffer<ToType, Vec<ToType::Subpixel>>> for ImageBuffer<FromType, Container>
1463where
1464 Container: Deref<Target = [FromType::Subpixel]>,
1465 ToType: FromColor<FromType>,
1466{
1467 fn convert(&self) -> ImageBuffer<ToType, Vec<ToType::Subpixel>> {
1481 let mut buffer: ImageBuffer<ToType, Vec<ToType::Subpixel>> =
1482 ImageBuffer::new(self.width, self.height);
1483 buffer.copy_color_space_from(self);
1484 for (to, from) in buffer.pixels_mut().zip(self.pixels()) {
1485 to.from_color(from);
1486 }
1487 buffer
1488 }
1489}
1490
1491#[non_exhaustive]
1493#[derive(Default)]
1494pub struct ConvertColorOptions {
1495 pub(crate) transform: Option<CicpTransform>,
1501 pub(crate) _auto_traits: PhantomData<std::rc::Rc<()>>,
1506}
1507
1508impl ConvertColorOptions {
1509 pub(crate) fn as_transform(
1510 &mut self,
1511 from_color: Cicp,
1512 into_color: Cicp,
1513 ) -> Result<&CicpTransform, ImageError> {
1514 if let Some(tr) = &self.transform {
1515 tr.check_applicable(from_color, into_color)?;
1516 }
1517
1518 if self.transform.is_none() {
1519 self.transform = CicpTransform::new(from_color, into_color);
1520 }
1521
1522 self.transform.as_ref().ok_or_else(|| {
1523 ImageError::Unsupported(UnsupportedError::from_format_and_kind(
1524 crate::error::ImageFormatHint::Unknown,
1525 UnsupportedErrorKind::ColorspaceCicp(if from_color.qualify_stability() {
1527 into_color
1528 } else {
1529 from_color
1530 }),
1531 ))
1532 })
1533 }
1534
1535 pub(crate) fn as_transform_fn<FromType, IntoType>(
1536 &mut self,
1537 from_color: Cicp,
1538 into_color: Cicp,
1539 ) -> Result<&'_ CicpApplicable<'_, FromType::Subpixel>, ImageError>
1540 where
1541 FromType: PixelWithColorType,
1542 IntoType: PixelWithColorType,
1543 {
1544 Ok(self
1545 .as_transform(from_color, into_color)?
1546 .supported_transform_fn::<FromType, IntoType>())
1547 }
1548}
1549
1550impl<C, SelfPixel: Pixel> ImageBuffer<SelfPixel, C>
1551where
1552 SelfPixel: PixelWithColorType,
1553 C: Deref<Target = [SelfPixel::Subpixel]> + DerefMut,
1554{
1555 pub(crate) fn cast_in_color_space<IntoPixel>(
1566 &self,
1567 ) -> ImageBuffer<IntoPixel, Vec<IntoPixel::Subpixel>>
1568 where
1569 SelfPixel: Pixel,
1570 IntoPixel: Pixel,
1571 IntoPixel: CicpPixelCast<SelfPixel>,
1572 SelfPixel::Subpixel: ColorComponentForCicp,
1573 IntoPixel::Subpixel: ColorComponentForCicp + FromPrimitive<SelfPixel::Subpixel>,
1574 {
1575 let vec = self
1576 .color
1577 .cast_pixels::<SelfPixel, IntoPixel>(self.inner_pixels(), &|| [0.2126, 0.7152, 0.0722]);
1578 let mut buffer = ImageBuffer::from_vec(self.width, self.height, vec)
1579 .expect("cast_pixels returned the right number of pixels");
1580 buffer.copy_color_space_from(self);
1581 buffer
1582 }
1583
1584 pub fn copy_from_color_space<FromType, D>(
1598 &mut self,
1599 from: &ImageBuffer<FromType, D>,
1600 mut options: ConvertColorOptions,
1601 ) -> ImageResult<()>
1602 where
1603 FromType: Pixel<Subpixel = SelfPixel::Subpixel> + PixelWithColorType,
1604 D: Deref<Target = [SelfPixel::Subpixel]>,
1605 {
1606 if self.dimensions() != from.dimensions() {
1607 return Err(ImageError::Parameter(ParameterError::from_kind(
1608 ParameterErrorKind::DimensionMismatch,
1609 )));
1610 }
1611
1612 let transform = options
1613 .as_transform_fn::<FromType, SelfPixel>(from.color_space(), self.color_space())?;
1614
1615 let from = from.inner_pixels();
1616 let into = self.inner_pixels_mut();
1617
1618 debug_assert_eq!(
1619 from.len() / usize::from(FromType::CHANNEL_COUNT),
1620 into.len() / usize::from(SelfPixel::CHANNEL_COUNT),
1621 "Diverging pixel count despite same size",
1622 );
1623
1624 transform(from, into);
1625
1626 Ok(())
1627 }
1628
1629 pub fn to_color_space<IntoType>(
1637 &self,
1638 color: Cicp,
1639 mut options: ConvertColorOptions,
1640 ) -> Result<ImageBuffer<IntoType, Vec<SelfPixel::Subpixel>>, ImageError>
1641 where
1642 IntoType: Pixel<Subpixel = SelfPixel::Subpixel> + PixelWithColorType,
1643 {
1644 let transform =
1645 options.as_transform_fn::<SelfPixel, IntoType>(self.color_space(), color)?;
1646
1647 let (width, height) = self.dimensions();
1648 let mut target = ImageBuffer::new(width, height);
1649
1650 let from = self.inner_pixels();
1651 let into = target.inner_pixels_mut();
1652
1653 transform(from, into);
1654
1655 Ok(target)
1656 }
1657
1658 pub fn apply_color_space(
1660 &mut self,
1661 color: Cicp,
1662 mut options: ConvertColorOptions,
1663 ) -> ImageResult<()> {
1664 if self.color_space() == color {
1665 return Ok(());
1666 }
1667
1668 let transform =
1669 options.as_transform_fn::<SelfPixel, SelfPixel>(self.color_space(), color)?;
1670
1671 let mut scratch = [<SelfPixel::Subpixel as crate::Primitive>::DEFAULT_MIN_VALUE; 1200];
1672 let chunk_len = scratch.len() / usize::from(<SelfPixel as Pixel>::CHANNEL_COUNT)
1673 * usize::from(<SelfPixel as Pixel>::CHANNEL_COUNT);
1674
1675 for chunk in self.data.chunks_mut(chunk_len) {
1676 let scratch = &mut scratch[..chunk.len()];
1677 scratch.copy_from_slice(chunk);
1678 transform(scratch, chunk);
1679 }
1680
1681 self.color = color.into_rgb();
1682
1683 Ok(())
1684 }
1685}
1686
1687pub type RgbImage = ImageBuffer<Rgb<u8>, Vec<u8>>;
1689pub type RgbaImage = ImageBuffer<Rgba<u8>, Vec<u8>>;
1691pub type GrayImage = ImageBuffer<Luma<u8>, Vec<u8>>;
1693pub type GrayAlphaImage = ImageBuffer<LumaA<u8>, Vec<u8>>;
1695pub(crate) type Rgb16Image = ImageBuffer<Rgb<u16>, Vec<u16>>;
1697pub(crate) type Rgba16Image = ImageBuffer<Rgba<u16>, Vec<u16>>;
1699pub(crate) type Gray16Image = ImageBuffer<Luma<u16>, Vec<u16>>;
1701pub(crate) type GrayAlpha16Image = ImageBuffer<LumaA<u16>, Vec<u16>>;
1703
1704pub type Rgb32FImage = ImageBuffer<Rgb<f32>, Vec<f32>>;
1707
1708pub type Rgba32FImage = ImageBuffer<Rgba<f32>, Vec<f32>>;
1711
1712impl From<DynamicImage> for RgbImage {
1713 fn from(value: DynamicImage) -> Self {
1714 value.into_rgb8()
1715 }
1716}
1717
1718impl From<DynamicImage> for RgbaImage {
1719 fn from(value: DynamicImage) -> Self {
1720 value.into_rgba8()
1721 }
1722}
1723
1724impl From<DynamicImage> for GrayImage {
1725 fn from(value: DynamicImage) -> Self {
1726 value.into_luma8()
1727 }
1728}
1729
1730impl From<DynamicImage> for GrayAlphaImage {
1731 fn from(value: DynamicImage) -> Self {
1732 value.into_luma_alpha8()
1733 }
1734}
1735
1736impl From<DynamicImage> for Rgb16Image {
1737 fn from(value: DynamicImage) -> Self {
1738 value.into_rgb16()
1739 }
1740}
1741
1742impl From<DynamicImage> for Rgba16Image {
1743 fn from(value: DynamicImage) -> Self {
1744 value.into_rgba16()
1745 }
1746}
1747
1748impl From<DynamicImage> for Gray16Image {
1749 fn from(value: DynamicImage) -> Self {
1750 value.into_luma16()
1751 }
1752}
1753
1754impl From<DynamicImage> for GrayAlpha16Image {
1755 fn from(value: DynamicImage) -> Self {
1756 value.into_luma_alpha16()
1757 }
1758}
1759
1760impl From<DynamicImage> for Rgba32FImage {
1761 fn from(value: DynamicImage) -> Self {
1762 value.into_rgba32f()
1763 }
1764}
1765
1766#[cfg(test)]
1767mod test {
1768 use super::{GrayImage, ImageBuffer, RgbImage};
1769 use crate::math::Rect;
1770 use crate::metadata::Cicp;
1771 use crate::metadata::CicpTransform;
1772 use crate::GenericImage as _;
1773 use crate::ImageFormat;
1774 use crate::{Luma, LumaA, Pixel, Rgb, Rgba};
1775 use num_traits::Zero;
1776
1777 #[test]
1778 fn slice_buffer() {
1780 let data = [0; 9];
1781 let buf: ImageBuffer<Luma<u8>, _> = ImageBuffer::from_raw(3, 3, &data[..]).unwrap();
1782 assert_eq!(&*buf, &data[..]);
1783 }
1784
1785 macro_rules! new_buffer_zero_test {
1786 ($test_name:ident, $pxt:ty) => {
1787 #[test]
1788 fn $test_name() {
1789 let buffer = ImageBuffer::<$pxt, Vec<<$pxt as Pixel>::Subpixel>>::new(2, 2);
1790 assert!(buffer
1791 .iter()
1792 .all(|p| *p == <$pxt as Pixel>::Subpixel::zero()));
1793 }
1794 };
1795 }
1796
1797 new_buffer_zero_test!(luma_u8_zero_test, Luma<u8>);
1798 new_buffer_zero_test!(luma_u16_zero_test, Luma<u16>);
1799 new_buffer_zero_test!(luma_f32_zero_test, Luma<f32>);
1800 new_buffer_zero_test!(luma_a_u8_zero_test, LumaA<u8>);
1801 new_buffer_zero_test!(luma_a_u16_zero_test, LumaA<u16>);
1802 new_buffer_zero_test!(luma_a_f32_zero_test, LumaA<f32>);
1803 new_buffer_zero_test!(rgb_u8_zero_test, Rgb<u8>);
1804 new_buffer_zero_test!(rgb_u16_zero_test, Rgb<u16>);
1805 new_buffer_zero_test!(rgb_f32_zero_test, Rgb<f32>);
1806 new_buffer_zero_test!(rgb_a_u8_zero_test, Rgba<u8>);
1807 new_buffer_zero_test!(rgb_a_u16_zero_test, Rgba<u16>);
1808 new_buffer_zero_test!(rgb_a_f32_zero_test, Rgba<f32>);
1809
1810 #[test]
1811 fn get_pixel() {
1812 let mut a: RgbImage = ImageBuffer::new(10, 10);
1813 {
1814 let b = a.get_mut(3 * 10).unwrap();
1815 *b = 255;
1816 }
1817 assert_eq!(a.get_pixel(0, 1)[0], 255);
1818 }
1819
1820 #[test]
1821 fn get_pixel_checked() {
1822 let mut a: RgbImage = ImageBuffer::new(10, 10);
1823 a.get_pixel_mut_checked(0, 1).unwrap()[0] = 255;
1824
1825 assert_eq!(a.get_pixel_checked(0, 1), Some(&Rgb([255, 0, 0])));
1826 assert_eq!(a.get_pixel_checked(0, 1).unwrap(), a.get_pixel(0, 1));
1827 assert_eq!(a.get_pixel_checked(10, 0), None);
1828 assert_eq!(a.get_pixel_checked(0, 10), None);
1829 assert_eq!(a.get_pixel_mut_checked(10, 0), None);
1830 assert_eq!(a.get_pixel_mut_checked(0, 10), None);
1831
1832 const WHITE: Rgb<u8> = Rgb([255_u8, 255, 255]);
1834 let mut a = RgbImage::new(2, 1);
1835 a.put_pixel(1, 0, WHITE);
1836
1837 assert_eq!(a.get_pixel_checked(1, 0), Some(&WHITE));
1838 assert_eq!(a.get_pixel_checked(1, 0).unwrap(), a.get_pixel(1, 0));
1839 }
1840
1841 #[test]
1842 fn mut_iter() {
1843 let mut a: RgbImage = ImageBuffer::new(10, 10);
1844 {
1845 let val = a.pixels_mut().next().unwrap();
1846 *val = Rgb([42, 0, 0]);
1847 }
1848 assert_eq!(a.data[0], 42);
1849 }
1850
1851 #[test]
1852 fn zero_width_zero_height() {
1853 let mut image = RgbImage::new(0, 0);
1854
1855 assert_eq!(image.rows_mut().count(), 0);
1856 assert_eq!(image.pixels_mut().count(), 0);
1857 assert_eq!(image.rows().count(), 0);
1858 assert_eq!(image.pixels().count(), 0);
1859 }
1860
1861 #[test]
1862 fn zero_width_nonzero_height() {
1863 let mut image = RgbImage::new(0, 2);
1864
1865 assert_eq!(image.rows_mut().count(), 0);
1866 assert_eq!(image.pixels_mut().count(), 0);
1867 assert_eq!(image.rows().count(), 0);
1868 assert_eq!(image.pixels().count(), 0);
1869 }
1870
1871 #[test]
1872 fn nonzero_width_zero_height() {
1873 let mut image = RgbImage::new(2, 0);
1874
1875 assert_eq!(image.rows_mut().count(), 0);
1876 assert_eq!(image.pixels_mut().count(), 0);
1877 assert_eq!(image.rows().count(), 0);
1878 assert_eq!(image.pixels().count(), 0);
1879 }
1880
1881 #[test]
1882 fn pixels_on_large_buffer() {
1883 let mut image = RgbImage::from_raw(1, 1, vec![0; 6]).unwrap();
1884
1885 assert_eq!(image.pixels().count(), 1);
1886 assert_eq!(image.enumerate_pixels().count(), 1);
1887 assert_eq!(image.pixels_mut().count(), 1);
1888 assert_eq!(image.enumerate_pixels_mut().count(), 1);
1889
1890 assert_eq!(image.rows().count(), 1);
1891 assert_eq!(image.rows_mut().count(), 1);
1892 }
1893
1894 #[test]
1895 fn default() {
1896 let image = ImageBuffer::<Rgb<u8>, Vec<u8>>::default();
1897 assert_eq!(image.dimensions(), (0, 0));
1898 }
1899
1900 #[test]
1901 #[rustfmt::skip]
1902 fn test_image_buffer_copy_within_oob() {
1903 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, vec![0u8; 16]).unwrap();
1904 assert!(!image.copy_within(Rect { x: 0, y: 0, width: 5, height: 4 }, 0, 0));
1905 assert!(!image.copy_within(Rect { x: 0, y: 0, width: 4, height: 5 }, 0, 0));
1906 assert!(!image.copy_within(Rect { x: 1, y: 0, width: 4, height: 4 }, 0, 0));
1907 assert!(!image.copy_within(Rect { x: 0, y: 0, width: 4, height: 4 }, 1, 0));
1908 assert!(!image.copy_within(Rect { x: 0, y: 1, width: 4, height: 4 }, 0, 0));
1909 assert!(!image.copy_within(Rect { x: 0, y: 0, width: 4, height: 4 }, 0, 1));
1910 assert!(!image.copy_within(Rect { x: 1, y: 1, width: 4, height: 4 }, 0, 0));
1911 }
1912
1913 #[test]
1914 fn test_image_buffer_copy_within_tl() {
1915 let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
1916 let expected = [0, 1, 2, 3, 4, 0, 1, 2, 8, 4, 5, 6, 12, 8, 9, 10];
1917 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
1918 assert!(image.copy_within(
1919 Rect {
1920 x: 0,
1921 y: 0,
1922 width: 3,
1923 height: 3
1924 },
1925 1,
1926 1
1927 ));
1928 assert_eq!(&image.into_raw(), &expected);
1929 }
1930
1931 #[test]
1932 fn test_image_buffer_copy_within_tr() {
1933 let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
1934 let expected = [0, 1, 2, 3, 1, 2, 3, 7, 5, 6, 7, 11, 9, 10, 11, 15];
1935 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
1936 assert!(image.copy_within(
1937 Rect {
1938 x: 1,
1939 y: 0,
1940 width: 3,
1941 height: 3
1942 },
1943 0,
1944 1
1945 ));
1946 assert_eq!(&image.into_raw(), &expected);
1947 }
1948
1949 #[test]
1950 fn test_image_buffer_copy_within_bl() {
1951 let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
1952 let expected = [0, 4, 5, 6, 4, 8, 9, 10, 8, 12, 13, 14, 12, 13, 14, 15];
1953 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
1954 assert!(image.copy_within(
1955 Rect {
1956 x: 0,
1957 y: 1,
1958 width: 3,
1959 height: 3
1960 },
1961 1,
1962 0
1963 ));
1964 assert_eq!(&image.into_raw(), &expected);
1965 }
1966
1967 #[test]
1968 fn test_image_buffer_copy_within_br() {
1969 let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
1970 let expected = [5, 6, 7, 3, 9, 10, 11, 7, 13, 14, 15, 11, 12, 13, 14, 15];
1971 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
1972 assert!(image.copy_within(
1973 Rect {
1974 x: 1,
1975 y: 1,
1976 width: 3,
1977 height: 3
1978 },
1979 0,
1980 0
1981 ));
1982 assert_eq!(&image.into_raw(), &expected);
1983 }
1984
1985 #[test]
1986 #[cfg(feature = "png")]
1987 fn write_to_with_large_buffer() {
1988 let img: GrayImage = ImageBuffer::from_raw(1, 1, vec![0u8; 4]).unwrap();
1991 let mut buffer = std::io::Cursor::new(vec![]);
1992 assert!(img.write_to(&mut buffer, ImageFormat::Png).is_ok());
1993 }
1994
1995 #[test]
1996 fn exact_size_iter_size_hint() {
1997 const N: u32 = 10;
2002
2003 let mut image = RgbImage::from_raw(N, N, vec![0; (N * N * 3) as usize]).unwrap();
2004
2005 let iter = image.pixels();
2006 let exact_len = ExactSizeIterator::len(&iter);
2007 assert_eq!(iter.size_hint(), (exact_len, Some(exact_len)));
2008
2009 let iter = image.pixels_mut();
2010 let exact_len = ExactSizeIterator::len(&iter);
2011 assert_eq!(iter.size_hint(), (exact_len, Some(exact_len)));
2012
2013 let iter = image.rows();
2014 let exact_len = ExactSizeIterator::len(&iter);
2015 assert_eq!(iter.size_hint(), (exact_len, Some(exact_len)));
2016
2017 let iter = image.rows_mut();
2018 let exact_len = ExactSizeIterator::len(&iter);
2019 assert_eq!(iter.size_hint(), (exact_len, Some(exact_len)));
2020
2021 let iter = image.enumerate_pixels();
2022 let exact_len = ExactSizeIterator::len(&iter);
2023 assert_eq!(iter.size_hint(), (exact_len, Some(exact_len)));
2024
2025 let iter = image.enumerate_rows();
2026 let exact_len = ExactSizeIterator::len(&iter);
2027 assert_eq!(iter.size_hint(), (exact_len, Some(exact_len)));
2028
2029 let iter = image.enumerate_pixels_mut();
2030 let exact_len = ExactSizeIterator::len(&iter);
2031 assert_eq!(iter.size_hint(), (exact_len, Some(exact_len)));
2032
2033 let iter = image.enumerate_rows_mut();
2034 let exact_len = ExactSizeIterator::len(&iter);
2035 assert_eq!(iter.size_hint(), (exact_len, Some(exact_len)));
2036 }
2037
2038 #[test]
2039 fn color_conversion() {
2040 let mut source = ImageBuffer::from_fn(128, 128, |_, _| Rgb([255, 0, 0]));
2041 let mut target = ImageBuffer::from_fn(128, 128, |_, _| Rgba(Default::default()));
2042
2043 source.set_rgb_primaries(Cicp::SRGB.primaries);
2044 source.set_transfer_function(Cicp::SRGB.transfer);
2045
2046 target.set_rgb_primaries(Cicp::DISPLAY_P3.primaries);
2047 target.set_transfer_function(Cicp::DISPLAY_P3.transfer);
2048
2049 let result = target.copy_from_color_space(&source, Default::default());
2050
2051 assert!(result.is_ok(), "{result:?}");
2052 assert_eq!(target[(0, 0)], Rgba([234u8, 51, 35, 255]));
2053 }
2054
2055 #[test]
2056 fn gray_conversions() {
2057 let mut source = ImageBuffer::from_fn(128, 128, |_, _| Luma([255u8]));
2058 let mut target = ImageBuffer::from_fn(128, 128, |_, _| Rgba(Default::default()));
2059
2060 source.set_rgb_primaries(Cicp::SRGB.primaries);
2061 source.set_transfer_function(Cicp::SRGB.transfer);
2062
2063 target.set_rgb_primaries(Cicp::SRGB.primaries);
2064 target.set_transfer_function(Cicp::SRGB.transfer);
2065
2066 let result = target.copy_from_color_space(&source, Default::default());
2067
2068 assert!(result.is_ok(), "{result:?}");
2069 assert_eq!(target[(0, 0)], Rgba([u8::MAX; 4]));
2070 }
2071
2072 #[test]
2073 fn rgb_to_gray_conversion() {
2074 let mut source = ImageBuffer::from_fn(128, 128, |_, _| Rgb([128u8; 3]));
2075 let mut target = ImageBuffer::from_fn(128, 128, |_, _| Luma(Default::default()));
2076
2077 source.set_rgb_primaries(Cicp::SRGB.primaries);
2078 source.set_transfer_function(Cicp::SRGB.transfer);
2079
2080 target.set_rgb_primaries(Cicp::SRGB.primaries);
2081 target.set_transfer_function(Cicp::SRGB.transfer);
2082
2083 let result = target.copy_from_color_space(&source, Default::default());
2084
2085 assert!(result.is_ok(), "{result:?}");
2086 assert_eq!(target[(0, 0)], Luma([128u8]));
2087 }
2088
2089 #[test]
2090 fn apply_color() {
2091 let mut buffer = ImageBuffer::from_fn(128, 128, |_, _| Rgb([255u8, 0, 0]));
2092
2093 buffer.set_rgb_primaries(Cicp::SRGB.primaries);
2094 buffer.set_transfer_function(Cicp::SRGB.transfer);
2095
2096 buffer
2097 .apply_color_space(Cicp::DISPLAY_P3, Default::default())
2098 .expect("supported transform");
2099
2100 buffer.pixels().for_each(|&p| {
2101 assert_eq!(p, Rgb([234u8, 51, 35]));
2102 });
2103 }
2104
2105 #[test]
2106 fn to_color() {
2107 let mut source = ImageBuffer::from_fn(128, 128, |_, _| Rgba([255u8, 0, 0, 255]));
2108 source.set_rgb_primaries(Cicp::SRGB.primaries);
2109 source.set_transfer_function(Cicp::SRGB.transfer);
2110
2111 let target = source
2112 .to_color_space::<Rgb<u8>>(Cicp::DISPLAY_P3, Default::default())
2113 .expect("supported transform");
2114
2115 assert_eq!(target[(0, 0)], Rgb([234u8, 51, 35]));
2116 }
2117
2118 #[test]
2119 fn transformation_mismatch() {
2120 let mut source = ImageBuffer::from_fn(128, 128, |_, _| Luma([255u8]));
2121 let mut target = ImageBuffer::from_fn(128, 128, |_, _| Rgba(Default::default()));
2122
2123 source.set_color_space(Cicp::SRGB).unwrap();
2124 target.set_color_space(Cicp::DISPLAY_P3).unwrap();
2125
2126 let options = super::ConvertColorOptions {
2127 transform: CicpTransform::new(Cicp::SRGB, Cicp::SRGB),
2128 ..super::ConvertColorOptions::default()
2129 };
2130
2131 let result = target.copy_from_color_space(&source, options);
2132 assert!(matches!(result, Err(crate::ImageError::Parameter(_))));
2133 }
2134}
2135
2136#[cfg(test)]
2137#[cfg(feature = "benchmarks")]
2138mod benchmarks {
2139 use super::{ConvertBuffer, GrayImage, ImageBuffer, Pixel, RgbImage};
2140
2141 #[bench]
2142 fn conversion(b: &mut test::Bencher) {
2143 let mut a: RgbImage = ImageBuffer::new(1000, 1000);
2144 for p in a.pixels_mut() {
2145 let rgb = p.channels_mut();
2146 rgb[0] = 255;
2147 rgb[1] = 23;
2148 rgb[2] = 42;
2149 }
2150
2151 assert!(a.data[0] != 0);
2152 b.iter(|| {
2153 let b: GrayImage = a.convert();
2154 assert!(0 != b.data[0]);
2155 assert!(a.data[0] != b.data[0]);
2156 test::black_box(b);
2157 });
2158 b.bytes = 1000 * 1000 * 3;
2159 }
2160
2161 #[bench]
2162 fn image_access_row_by_row(b: &mut test::Bencher) {
2163 let mut a: RgbImage = ImageBuffer::new(1000, 1000);
2164 for p in a.pixels_mut() {
2165 let rgb = p.channels_mut();
2166 rgb[0] = 255;
2167 rgb[1] = 23;
2168 rgb[2] = 42;
2169 }
2170
2171 b.iter(move || {
2172 let image: &RgbImage = test::black_box(&a);
2173 let mut sum: usize = 0;
2174 for y in 0..1000 {
2175 for x in 0..1000 {
2176 let pixel = image.get_pixel(x, y);
2177 sum = sum.wrapping_add(pixel[0] as usize);
2178 sum = sum.wrapping_add(pixel[1] as usize);
2179 sum = sum.wrapping_add(pixel[2] as usize);
2180 }
2181 }
2182 test::black_box(sum)
2183 });
2184
2185 b.bytes = 1000 * 1000 * 3;
2186 }
2187
2188 #[bench]
2189 fn image_access_col_by_col(b: &mut test::Bencher) {
2190 let mut a: RgbImage = ImageBuffer::new(1000, 1000);
2191 for p in a.pixels_mut() {
2192 let rgb = p.channels_mut();
2193 rgb[0] = 255;
2194 rgb[1] = 23;
2195 rgb[2] = 42;
2196 }
2197
2198 b.iter(move || {
2199 let image: &RgbImage = test::black_box(&a);
2200 let mut sum: usize = 0;
2201 for x in 0..1000 {
2202 for y in 0..1000 {
2203 let pixel = image.get_pixel(x, y);
2204 sum = sum.wrapping_add(pixel[0] as usize);
2205 sum = sum.wrapping_add(pixel[1] as usize);
2206 sum = sum.wrapping_add(pixel[2] as usize);
2207 }
2208 }
2209 test::black_box(sum)
2210 });
2211
2212 b.bytes = 1000 * 1000 * 3;
2213 }
2214}