1use core::ops::{Index, IndexMut};
2
3#[cfg(not(feature = "std"))]
4use num_traits::float::FloatCore as _;
5use num_traits::{NumCast, ToPrimitive, Zero};
6
7use crate::{
8 error::TryFromExtendedColorError,
9 traits::{Enlargeable, Pixel, Primitive},
10};
11
12#[derive(Copy, PartialEq, Eq, Debug, Clone, Hash)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15#[non_exhaustive]
16pub enum ColorType {
17 L8,
19 La8,
21 Rgb8,
23 Rgba8,
25
26 L16,
28 La16,
30 Rgb16,
32 Rgba16,
34
35 Rgb32F,
37 Rgba32F,
39}
40
41impl ColorType {
42 #[must_use]
44 pub fn bytes_per_pixel(self) -> u8 {
45 match self {
46 ColorType::L8 => 1,
47 ColorType::L16 | ColorType::La8 => 2,
48 ColorType::Rgb8 => 3,
49 ColorType::Rgba8 | ColorType::La16 => 4,
50 ColorType::Rgb16 => 6,
51 ColorType::Rgba16 => 8,
52 ColorType::Rgb32F => 3 * 4,
53 ColorType::Rgba32F => 4 * 4,
54 }
55 }
56
57 #[must_use]
59 pub fn has_alpha(self) -> bool {
60 use ColorType::*;
61 match self {
62 L8 | L16 | Rgb8 | Rgb16 | Rgb32F => false,
63 La8 | Rgba8 | La16 | Rgba16 | Rgba32F => true,
64 }
65 }
66
67 #[must_use]
69 pub fn has_color(self) -> bool {
70 use ColorType::*;
71 match self {
72 L8 | L16 | La8 | La16 => false,
73 Rgb8 | Rgb16 | Rgba8 | Rgba16 | Rgb32F | Rgba32F => true,
74 }
75 }
76
77 #[must_use]
80 pub fn bits_per_pixel(self) -> u16 {
81 <u16 as From<u8>>::from(self.bytes_per_pixel()) * 8
82 }
83
84 #[must_use]
86 pub fn channel_count(self) -> u8 {
87 let e: ExtendedColorType = self.into();
88 e.channel_count()
89 }
90}
91
92#[derive(Copy, PartialEq, Eq, Debug, Clone, Hash)]
101#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
102#[non_exhaustive]
103pub enum ExtendedColorType {
104 A8,
106 L1,
108 La1,
110 Rgb1,
112 Rgba1,
114 L2,
116 La2,
118 Rgb2,
120 Rgba2,
122 L4,
124 La4,
126 Rgb4,
128 Rgba4,
130 Rgb5x1,
132 L8,
134 La8,
136 Rgb8,
138 Rgba8,
140 L16,
142 La16,
144 Rgb16,
146 Rgba16,
148 Bgr8,
150 Bgra8,
152
153 Rgb32F,
156 Rgba32F,
158
159 Cmyk8,
161 Cmyk16,
163
164 Unknown(u8),
168}
169
170impl ExtendedColorType {
171 #[must_use]
176 pub fn channel_count(self) -> u8 {
177 match self {
178 ExtendedColorType::A8
179 | ExtendedColorType::L1
180 | ExtendedColorType::L2
181 | ExtendedColorType::L4
182 | ExtendedColorType::L8
183 | ExtendedColorType::L16
184 | ExtendedColorType::Unknown(_) => 1,
185 ExtendedColorType::La1
186 | ExtendedColorType::La2
187 | ExtendedColorType::La4
188 | ExtendedColorType::La8
189 | ExtendedColorType::La16 => 2,
190 ExtendedColorType::Rgb1
191 | ExtendedColorType::Rgb2
192 | ExtendedColorType::Rgb4
193 | ExtendedColorType::Rgb5x1
194 | ExtendedColorType::Rgb8
195 | ExtendedColorType::Rgb16
196 | ExtendedColorType::Rgb32F
197 | ExtendedColorType::Bgr8 => 3,
198 ExtendedColorType::Rgba1
199 | ExtendedColorType::Rgba2
200 | ExtendedColorType::Rgba4
201 | ExtendedColorType::Rgba8
202 | ExtendedColorType::Rgba16
203 | ExtendedColorType::Rgba32F
204 | ExtendedColorType::Bgra8
205 | ExtendedColorType::Cmyk8
206 | ExtendedColorType::Cmyk16 => 4,
207 }
208 }
209
210 #[must_use]
212 pub fn bits_per_pixel(&self) -> u16 {
213 match *self {
214 ExtendedColorType::A8 => 8,
215 ExtendedColorType::L1 => 1,
216 ExtendedColorType::La1 => 2,
217 ExtendedColorType::Rgb1 => 3,
218 ExtendedColorType::Rgba1 => 4,
219 ExtendedColorType::L2 => 2,
220 ExtendedColorType::La2 => 4,
221 ExtendedColorType::Rgb2 => 6,
222 ExtendedColorType::Rgba2 => 8,
223 ExtendedColorType::L4 => 4,
224 ExtendedColorType::La4 => 8,
225 ExtendedColorType::Rgb4 => 12,
226 ExtendedColorType::Rgba4 => 16,
227 ExtendedColorType::Rgb5x1 => 16,
228 ExtendedColorType::L8 => 8,
229 ExtendedColorType::La8 => 16,
230 ExtendedColorType::Rgb8 => 24,
231 ExtendedColorType::Rgba8 => 32,
232 ExtendedColorType::L16 => 16,
233 ExtendedColorType::La16 => 32,
234 ExtendedColorType::Rgb16 => 48,
235 ExtendedColorType::Rgba16 => 64,
236 ExtendedColorType::Rgb32F => 96,
237 ExtendedColorType::Rgba32F => 128,
238 ExtendedColorType::Bgr8 => 24,
239 ExtendedColorType::Bgra8 => 32,
240 ExtendedColorType::Cmyk8 => 32,
241 ExtendedColorType::Cmyk16 => 64,
242 ExtendedColorType::Unknown(bpp) => bpp as u16,
243 }
244 }
245
246 pub fn color_type(&self) -> Option<ColorType> {
270 match *self {
271 ExtendedColorType::L8 => Some(ColorType::L8),
272 ExtendedColorType::La8 => Some(ColorType::La8),
273 ExtendedColorType::Rgb8 => Some(ColorType::Rgb8),
274 ExtendedColorType::Rgba8 => Some(ColorType::Rgba8),
275 ExtendedColorType::L16 => Some(ColorType::L16),
276 ExtendedColorType::La16 => Some(ColorType::La16),
277 ExtendedColorType::Rgb16 => Some(ColorType::Rgb16),
278 ExtendedColorType::Rgba16 => Some(ColorType::Rgba16),
279 ExtendedColorType::Rgb32F => Some(ColorType::Rgb32F),
280 ExtendedColorType::Rgba32F => Some(ColorType::Rgba32F),
281 _ => None,
282 }
283 }
284
285 #[cfg(any(
287 feature = "png",
288 feature = "jpeg",
289 feature = "gif",
290 feature = "tiff",
291 feature = "tga",
292 feature = "webp",
293 feature = "qoi",
294 feature = "exr",
295 feature = "avif",
296 feature = "bmp",
297 feature = "ico",
298 feature = "pnm"
299 ))]
300 pub(crate) fn buffer_size(self, width: u32, height: u32) -> u64 {
301 let bpp = self.bits_per_pixel() as u64;
302 let row_pitch = (width as u64 * bpp).div_ceil(8);
303 row_pitch.saturating_mul(height as u64)
304 }
305}
306
307impl From<ColorType> for ExtendedColorType {
308 fn from(c: ColorType) -> Self {
309 match c {
310 ColorType::L8 => ExtendedColorType::L8,
311 ColorType::La8 => ExtendedColorType::La8,
312 ColorType::Rgb8 => ExtendedColorType::Rgb8,
313 ColorType::Rgba8 => ExtendedColorType::Rgba8,
314 ColorType::L16 => ExtendedColorType::L16,
315 ColorType::La16 => ExtendedColorType::La16,
316 ColorType::Rgb16 => ExtendedColorType::Rgb16,
317 ColorType::Rgba16 => ExtendedColorType::Rgba16,
318 ColorType::Rgb32F => ExtendedColorType::Rgb32F,
319 ColorType::Rgba32F => ExtendedColorType::Rgba32F,
320 }
321 }
322}
323
324impl TryFrom<ExtendedColorType> for ColorType {
325 type Error = TryFromExtendedColorError;
326
327 fn try_from(value: ExtendedColorType) -> Result<ColorType, Self::Error> {
328 value
329 .color_type()
330 .ok_or(TryFromExtendedColorError { was: value })
331 }
332}
333
334macro_rules! define_colors {
335 {$(
336 $(#[$doc:meta])*
337 pub struct $ident:ident<T: $($bound:ident)*>([T; $channels:expr, $alphas:expr])
338 = $interpretation:literal;
339 )*} => {
340
341$( $(#[$doc])*
344#[derive(PartialEq, Eq, Clone, Debug, Copy, Hash)]
345#[repr(transparent)]
346#[allow(missing_docs)]
347pub struct $ident<T> (pub [T; $channels]);
348
349impl<T: $($bound+)*> Pixel for $ident<T> {
350 type Subpixel = T;
351
352 const CHANNEL_COUNT: u8 = $channels;
353
354 #[inline(always)]
355 fn channels(&self) -> &[T] {
356 &self.0
357 }
358
359 #[inline(always)]
360 fn channels_mut(&mut self) -> &mut [T] {
361 &mut self.0
362 }
363
364 const COLOR_MODEL: &'static str = $interpretation;
365
366 const HAS_ALPHA: bool = $alphas > 0;
367
368 #[inline]
369 fn alpha(&self) -> Self::Subpixel {
370 if Self::HAS_ALPHA {
371 *self.channels().last().unwrap()
373 } else {
374 Self::Subpixel::DEFAULT_MAX_VALUE
375 }
376 }
377
378 fn channels4(&self) -> (T, T, T, T) {
379 const CHANNELS: usize = $channels;
380 let mut channels = [T::DEFAULT_MAX_VALUE; 4];
381 channels[0..CHANNELS].copy_from_slice(&self.0);
382 (channels[0], channels[1], channels[2], channels[3])
383 }
384
385 fn from_channels(a: T, b: T, c: T, d: T,) -> $ident<T> {
386 const CHANNELS: usize = $channels;
387 *<$ident<T> as Pixel>::from_slice(&[a, b, c, d][..CHANNELS])
388 }
389
390 fn from_slice(slice: &[T]) -> &$ident<T> {
391 assert_eq!(slice.len(), $channels);
392 unsafe { &*(slice.as_ptr() as *const $ident<T>) }
393 }
394 fn from_slice_mut(slice: &mut [T]) -> &mut $ident<T> {
395 assert_eq!(slice.len(), $channels);
396 unsafe { &mut *(slice.as_mut_ptr() as *mut $ident<T>) }
397 }
398
399 fn to_rgb(&self) -> Rgb<T> {
400 let mut pix = Rgb([Zero::zero(), Zero::zero(), Zero::zero()]);
401 pix.from_color(self);
402 pix
403 }
404
405 fn to_rgba(&self) -> Rgba<T> {
406 let mut pix = Rgba([Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero()]);
407 pix.from_color(self);
408 pix
409 }
410
411 fn to_luma(&self) -> Luma<T> {
412 let mut pix = Luma([Zero::zero()]);
413 pix.from_color(self);
414 pix
415 }
416
417 fn to_luma_alpha(&self) -> LumaA<T> {
418 let mut pix = LumaA([Zero::zero(), Zero::zero()]);
419 pix.from_color(self);
420 pix
421 }
422
423 fn map<F>(& self, f: F) -> $ident<T> where F: FnMut(T) -> T {
424 let mut this = (*self).clone();
425 this.apply(f);
426 this
427 }
428
429 fn apply<F>(&mut self, mut f: F) where F: FnMut(T) -> T {
430 for v in &mut self.0 {
431 *v = f(*v)
432 }
433 }
434
435 fn map_with_alpha<F, G>(&self, f: F, g: G) -> $ident<T> where F: FnMut(T) -> T, G: FnMut(T) -> T {
436 let mut this = (*self).clone();
437 this.apply_with_alpha(f, g);
438 this
439 }
440
441 fn apply_with_alpha<F, G>(&mut self, mut f: F, mut g: G) where F: FnMut(T) -> T, G: FnMut(T) -> T {
442 const ALPHA: usize = $channels - $alphas;
443 for v in self.0[..ALPHA].iter_mut() {
444 *v = f(*v)
445 }
446 if let Some(v) = self.0.get_mut(ALPHA) {
449 *v = g(*v)
450 }
451 }
452
453 fn map2<F>(&self, other: &Self, f: F) -> $ident<T> where F: FnMut(T, T) -> T {
454 let mut this = (*self).clone();
455 this.apply2(other, f);
456 this
457 }
458
459 fn apply2<F>(&mut self, other: &$ident<T>, mut f: F) where F: FnMut(T, T) -> T {
460 for (a, &b) in self.0.iter_mut().zip(other.0.iter()) {
461 *a = f(*a, b)
462 }
463 }
464
465 fn invert(&mut self) {
466 Invert::invert(self)
467 }
468
469 fn blend(&mut self, other: &$ident<T>) {
470 Blend::blend(self, other)
471 }
472}
473
474impl<T> Index<usize> for $ident<T> {
475 type Output = T;
476 #[inline(always)]
477 fn index(&self, _index: usize) -> &T {
478 &self.0[_index]
479 }
480}
481
482impl<T> IndexMut<usize> for $ident<T> {
483 #[inline(always)]
484 fn index_mut(&mut self, _index: usize) -> &mut T {
485 &mut self.0[_index]
486 }
487}
488
489impl<T> From<[T; $channels]> for $ident<T> {
490 fn from(c: [T; $channels]) -> Self {
491 Self(c)
492 }
493}
494
495)* }
498}
499
500define_colors! {
501 pub struct Rgb<T: Primitive Enlargeable>([T; 3, 0]) = "RGB";
506 pub struct Luma<T: Primitive>([T; 1, 0]) = "Y";
508 pub struct Rgba<T: Primitive Enlargeable>([T; 4, 1]) = "RGBA";
510 pub struct LumaA<T: Primitive>([T; 2, 1]) = "YA";
512}
513
514pub trait FromPrimitive<Component> {
516 fn from_primitive(component: Component) -> Self;
518}
519
520impl<T: Primitive> FromPrimitive<T> for T {
521 fn from_primitive(sample: T) -> Self {
522 sample
523 }
524}
525
526#[inline]
534fn normalize_float(float: f32, max: f32) -> f32 {
535 #[allow(clippy::neg_cmp_op_on_partial_ord)]
536 let clamped = if !(float < 1.0) { 1.0 } else { float.max(0.0) };
537 (clamped * max).round()
538}
539
540impl FromPrimitive<f32> for u8 {
541 fn from_primitive(float: f32) -> Self {
542 NumCast::from(normalize_float(float, u8::MAX as f32)).unwrap()
543 }
544}
545
546impl FromPrimitive<f32> for u16 {
547 fn from_primitive(float: f32) -> Self {
548 NumCast::from(normalize_float(float, u16::MAX as f32)).unwrap()
549 }
550}
551
552impl FromPrimitive<u16> for u8 {
555 fn from_primitive(c16: u16) -> Self {
556 fn from(c: impl Into<u32>) -> u32 {
557 c.into()
558 }
559 NumCast::from((from(c16) + 128) / 257).unwrap()
566 }
567}
568
569impl FromPrimitive<u16> for f32 {
570 fn from_primitive(int: u16) -> Self {
571 (int as f32 / u16::MAX as f32).clamp(0.0, 1.0)
572 }
573}
574
575impl FromPrimitive<u8> for f32 {
578 fn from_primitive(int: u8) -> Self {
579 (int as f32 / u8::MAX as f32).clamp(0.0, 1.0)
580 }
581}
582
583impl FromPrimitive<u8> for u16 {
584 fn from_primitive(c8: u8) -> Self {
585 let x = c8.to_u64().unwrap();
586 NumCast::from((x << 8) | x).unwrap()
587 }
588}
589
590pub trait FromColor<Other> {
592 #[allow(clippy::wrong_self_convention)]
594 fn from_color(&mut self, _: &Other);
595}
596
597pub(crate) trait IntoColor<Other> {
601 #[allow(clippy::wrong_self_convention)]
603 fn into_color(&self) -> Other;
604}
605
606impl<O, S> IntoColor<O> for S
607where
608 O: Pixel + FromColor<S>,
609{
610 #[allow(clippy::wrong_self_convention)]
611 fn into_color(&self) -> O {
612 #[allow(deprecated)]
615 let mut pix = O::from_channels(Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero());
616 pix.from_color(self);
617 pix
618 }
619}
620
621const SRGB_LUMA: [u32; 3] = [2126, 7152, 722];
623const SRGB_LUMA_DIV: u32 = 10000;
624
625#[inline]
626fn rgb_to_luma<T: Primitive + Enlargeable>(rgb: &[T]) -> T {
627 let l = <T::Larger as NumCast>::from(SRGB_LUMA[0]).unwrap() * rgb[0].to_larger()
628 + <T::Larger as NumCast>::from(SRGB_LUMA[1]).unwrap() * rgb[1].to_larger()
629 + <T::Larger as NumCast>::from(SRGB_LUMA[2]).unwrap() * rgb[2].to_larger();
630 T::clamp_from(l / <T::Larger as NumCast>::from(SRGB_LUMA_DIV).unwrap())
631}
632
633impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for Luma<T>
635where
636 T: FromPrimitive<S>,
637{
638 fn from_color(&mut self, other: &Luma<S>) {
639 let own = self.channels_mut();
640 let other = other.channels();
641 own[0] = T::from_primitive(other[0]);
642 }
643}
644
645impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for Luma<T>
646where
647 T: FromPrimitive<S>,
648{
649 fn from_color(&mut self, other: &LumaA<S>) {
650 self.channels_mut()[0] = T::from_primitive(other.channels()[0]);
651 }
652}
653
654impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgb<S>> for Luma<T>
655where
656 T: FromPrimitive<S>,
657{
658 fn from_color(&mut self, other: &Rgb<S>) {
659 let gray = self.channels_mut();
660 let rgb = other.channels();
661 gray[0] = T::from_primitive(rgb_to_luma(rgb));
662 }
663}
664
665impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgba<S>> for Luma<T>
666where
667 T: FromPrimitive<S>,
668{
669 fn from_color(&mut self, other: &Rgba<S>) {
670 let gray = self.channels_mut();
671 let rgb = other.channels();
672 let l = rgb_to_luma(rgb);
673 gray[0] = T::from_primitive(l);
674 }
675}
676
677impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for LumaA<T>
680where
681 T: FromPrimitive<S>,
682{
683 fn from_color(&mut self, other: &LumaA<S>) {
684 let own = self.channels_mut();
685 let other = other.channels();
686 own[0] = T::from_primitive(other[0]);
687 own[1] = T::from_primitive(other[1]);
688 }
689}
690
691impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgb<S>> for LumaA<T>
692where
693 T: FromPrimitive<S>,
694{
695 fn from_color(&mut self, other: &Rgb<S>) {
696 let gray_a = self.channels_mut();
697 let rgb = other.channels();
698 gray_a[0] = T::from_primitive(rgb_to_luma(rgb));
699 gray_a[1] = T::DEFAULT_MAX_VALUE;
700 }
701}
702
703impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgba<S>> for LumaA<T>
704where
705 T: FromPrimitive<S>,
706{
707 fn from_color(&mut self, other: &Rgba<S>) {
708 let gray_a = self.channels_mut();
709 let rgba = other.channels();
710 gray_a[0] = T::from_primitive(rgb_to_luma(rgba));
711 gray_a[1] = T::from_primitive(rgba[3]);
712 }
713}
714
715impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for LumaA<T>
716where
717 T: FromPrimitive<S>,
718{
719 fn from_color(&mut self, other: &Luma<S>) {
720 let gray_a = self.channels_mut();
721 gray_a[0] = T::from_primitive(other.channels()[0]);
722 gray_a[1] = T::DEFAULT_MAX_VALUE;
723 }
724}
725
726impl<S: Primitive, T: Primitive> FromColor<Rgba<S>> for Rgba<T>
729where
730 T: FromPrimitive<S>,
731{
732 fn from_color(&mut self, other: &Rgba<S>) {
733 let own = &mut self.0;
734 let other = &other.0;
735 own[0] = T::from_primitive(other[0]);
736 own[1] = T::from_primitive(other[1]);
737 own[2] = T::from_primitive(other[2]);
738 own[3] = T::from_primitive(other[3]);
739 }
740}
741
742impl<S: Primitive, T: Primitive> FromColor<Rgb<S>> for Rgba<T>
743where
744 T: FromPrimitive<S>,
745{
746 fn from_color(&mut self, other: &Rgb<S>) {
747 let rgba = &mut self.0;
748 let rgb = &other.0;
749 rgba[0] = T::from_primitive(rgb[0]);
750 rgba[1] = T::from_primitive(rgb[1]);
751 rgba[2] = T::from_primitive(rgb[2]);
752 rgba[3] = T::DEFAULT_MAX_VALUE;
753 }
754}
755
756impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for Rgba<T>
757where
758 T: FromPrimitive<S>,
759{
760 fn from_color(&mut self, gray: &LumaA<S>) {
761 let rgba = &mut self.0;
762 let gray = &gray.0;
763 rgba[0] = T::from_primitive(gray[0]);
764 rgba[1] = T::from_primitive(gray[0]);
765 rgba[2] = T::from_primitive(gray[0]);
766 rgba[3] = T::from_primitive(gray[1]);
767 }
768}
769
770impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for Rgba<T>
771where
772 T: FromPrimitive<S>,
773{
774 fn from_color(&mut self, gray: &Luma<S>) {
775 let rgba = &mut self.0;
776 let gray = gray.0[0];
777 rgba[0] = T::from_primitive(gray);
778 rgba[1] = T::from_primitive(gray);
779 rgba[2] = T::from_primitive(gray);
780 rgba[3] = T::DEFAULT_MAX_VALUE;
781 }
782}
783
784impl<S: Primitive, T: Primitive> FromColor<Rgb<S>> for Rgb<T>
787where
788 T: FromPrimitive<S>,
789{
790 fn from_color(&mut self, other: &Rgb<S>) {
791 let own = &mut self.0;
792 let other = &other.0;
793 own[0] = T::from_primitive(other[0]);
794 own[1] = T::from_primitive(other[1]);
795 own[2] = T::from_primitive(other[2]);
796 }
797}
798
799impl<S: Primitive, T: Primitive> FromColor<Rgba<S>> for Rgb<T>
800where
801 T: FromPrimitive<S>,
802{
803 fn from_color(&mut self, other: &Rgba<S>) {
804 let rgb = &mut self.0;
805 let rgba = &other.0;
806 rgb[0] = T::from_primitive(rgba[0]);
807 rgb[1] = T::from_primitive(rgba[1]);
808 rgb[2] = T::from_primitive(rgba[2]);
809 }
810}
811
812impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for Rgb<T>
813where
814 T: FromPrimitive<S>,
815{
816 fn from_color(&mut self, other: &LumaA<S>) {
817 let rgb = &mut self.0;
818 let gray = other.0[0];
819 rgb[0] = T::from_primitive(gray);
820 rgb[1] = T::from_primitive(gray);
821 rgb[2] = T::from_primitive(gray);
822 }
823}
824
825impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for Rgb<T>
826where
827 T: FromPrimitive<S>,
828{
829 fn from_color(&mut self, other: &Luma<S>) {
830 let rgb = &mut self.0;
831 let gray = other.0[0];
832 rgb[0] = T::from_primitive(gray);
833 rgb[1] = T::from_primitive(gray);
834 rgb[2] = T::from_primitive(gray);
835 }
836}
837
838pub(crate) trait Blend {
840 fn blend(&mut self, other: &Self);
842}
843
844impl<T: Primitive> Blend for LumaA<T> {
845 fn blend(&mut self, other: &LumaA<T>) {
846 let max_t = T::DEFAULT_MAX_VALUE;
847 let max_t = max_t.to_f32().unwrap();
848 let (bg_luma, bg_a) = (self.0[0], self.0[1]);
849 let (fg_luma, fg_a) = (other.0[0], other.0[1]);
850
851 let (bg_luma, bg_a) = (
852 bg_luma.to_f32().unwrap() / max_t,
853 bg_a.to_f32().unwrap() / max_t,
854 );
855 let (fg_luma, fg_a) = (
856 fg_luma.to_f32().unwrap() / max_t,
857 fg_a.to_f32().unwrap() / max_t,
858 );
859
860 let alpha_final = bg_a + fg_a - bg_a * fg_a;
861 if alpha_final == 0.0 {
862 return;
863 };
864 let bg_luma_a = bg_luma * bg_a;
865 let fg_luma_a = fg_luma * fg_a;
866
867 let out_luma_a = fg_luma_a + bg_luma_a * (1.0 - fg_a);
868 let out_luma = out_luma_a / alpha_final;
869
870 *self = LumaA([
871 NumCast::from(max_t * out_luma).unwrap(),
872 NumCast::from(max_t * alpha_final).unwrap(),
873 ]);
874 }
875}
876
877impl<T: Primitive> Blend for Luma<T> {
878 fn blend(&mut self, other: &Luma<T>) {
879 *self = *other;
880 }
881}
882
883impl<T: Primitive> Blend for Rgba<T> {
884 fn blend(&mut self, other: &Rgba<T>) {
885 if other.0[3].is_zero() {
888 return;
889 }
890 if other.0[3] == T::DEFAULT_MAX_VALUE {
891 *self = *other;
892 return;
893 }
894
895 let max_t = T::DEFAULT_MAX_VALUE;
897 let max_t = max_t.to_f32().unwrap();
898 let (bg_r, bg_g, bg_b, bg_a) = (self.0[0], self.0[1], self.0[2], self.0[3]);
899 let (fg_r, fg_g, fg_b, fg_a) = (other.0[0], other.0[1], other.0[2], other.0[3]);
900 let (bg_r, bg_g, bg_b, bg_a) = (
901 bg_r.to_f32().unwrap() / max_t,
902 bg_g.to_f32().unwrap() / max_t,
903 bg_b.to_f32().unwrap() / max_t,
904 bg_a.to_f32().unwrap() / max_t,
905 );
906 let (fg_r, fg_g, fg_b, fg_a) = (
907 fg_r.to_f32().unwrap() / max_t,
908 fg_g.to_f32().unwrap() / max_t,
909 fg_b.to_f32().unwrap() / max_t,
910 fg_a.to_f32().unwrap() / max_t,
911 );
912
913 let alpha_final = bg_a + fg_a - bg_a * fg_a;
915 if alpha_final == 0.0 {
916 return;
917 };
918
919 let (bg_r_a, bg_g_a, bg_b_a) = (bg_r * bg_a, bg_g * bg_a, bg_b * bg_a);
921 let (fg_r_a, fg_g_a, fg_b_a) = (fg_r * fg_a, fg_g * fg_a, fg_b * fg_a);
922
923 let (out_r_a, out_g_a, out_b_a) = (
925 fg_r_a + bg_r_a * (1.0 - fg_a),
926 fg_g_a + bg_g_a * (1.0 - fg_a),
927 fg_b_a + bg_b_a * (1.0 - fg_a),
928 );
929
930 let (out_r, out_g, out_b) = (
932 out_r_a / alpha_final,
933 out_g_a / alpha_final,
934 out_b_a / alpha_final,
935 );
936
937 *self = Rgba([
939 NumCast::from(max_t * out_r).unwrap(),
940 NumCast::from(max_t * out_g).unwrap(),
941 NumCast::from(max_t * out_b).unwrap(),
942 NumCast::from(max_t * alpha_final).unwrap(),
943 ]);
944 }
945}
946
947impl<T: Primitive> Blend for Rgb<T> {
948 fn blend(&mut self, other: &Rgb<T>) {
949 *self = *other;
950 }
951}
952
953pub(crate) trait Invert {
955 fn invert(&mut self);
957}
958
959impl<T: Primitive> Invert for LumaA<T> {
960 fn invert(&mut self) {
961 let l = self.0;
962 let max = T::DEFAULT_MAX_VALUE;
963
964 *self = LumaA([max - l[0], l[1]]);
965 }
966}
967
968impl<T: Primitive> Invert for Luma<T> {
969 fn invert(&mut self) {
970 let l = self.0;
971
972 let max = T::DEFAULT_MAX_VALUE;
973 let l1 = max - l[0];
974
975 *self = Luma([l1]);
976 }
977}
978
979impl<T: Primitive> Invert for Rgba<T> {
980 fn invert(&mut self) {
981 let rgba = self.0;
982
983 let max = T::DEFAULT_MAX_VALUE;
984
985 *self = Rgba([max - rgba[0], max - rgba[1], max - rgba[2], rgba[3]]);
986 }
987}
988
989impl<T: Primitive> Invert for Rgb<T> {
990 fn invert(&mut self) {
991 let rgb = self.0;
992
993 let max = T::DEFAULT_MAX_VALUE;
994
995 let r1 = max - rgb[0];
996 let g1 = max - rgb[1];
997 let b1 = max - rgb[2];
998
999 *self = Rgb([r1, g1, b1]);
1000 }
1001}
1002
1003#[cfg(test)]
1004mod tests {
1005 use super::{Luma, LumaA, Pixel, Rgb, Rgba};
1006
1007 #[test]
1008 fn test_apply_with_alpha_rgba() {
1009 let mut rgba = Rgba([0, 0, 0, 0]);
1010 rgba.apply_with_alpha(|s| s, |_| 0xFF);
1011 assert_eq!(rgba, Rgba([0, 0, 0, 0xFF]));
1012 }
1013
1014 #[test]
1015 fn test_apply_with_alpha_rgb() {
1016 let mut rgb = Rgb([0, 0, 0]);
1017 rgb.apply_with_alpha(|s| s, |_| panic!("bug"));
1018 assert_eq!(rgb, Rgb([0, 0, 0]));
1019 }
1020
1021 #[test]
1022 fn test_map_with_alpha_rgba() {
1023 let rgba = Rgba([0, 0, 0, 0]).map_with_alpha(|s| s, |_| 0xFF);
1024 assert_eq!(rgba, Rgba([0, 0, 0, 0xFF]));
1025 }
1026
1027 #[test]
1028 fn test_map_with_alpha_rgb() {
1029 let rgb = Rgb([0, 0, 0]).map_with_alpha(|s| s, |_| panic!("bug"));
1030 assert_eq!(rgb, Rgb([0, 0, 0]));
1031 }
1032
1033 #[test]
1034 fn test_blend_luma_alpha() {
1035 let a = &mut LumaA([255_u8, 255]);
1036 let b = LumaA([255_u8, 255]);
1037 a.blend(&b);
1038 assert_eq!(a.0[0], 255);
1039 assert_eq!(a.0[1], 255);
1040
1041 let a = &mut LumaA([255_u8, 0]);
1042 let b = LumaA([255_u8, 255]);
1043 a.blend(&b);
1044 assert_eq!(a.0[0], 255);
1045 assert_eq!(a.0[1], 255);
1046
1047 let a = &mut LumaA([255_u8, 255]);
1048 let b = LumaA([255_u8, 0]);
1049 a.blend(&b);
1050 assert_eq!(a.0[0], 255);
1051 assert_eq!(a.0[1], 255);
1052
1053 let a = &mut LumaA([255_u8, 0]);
1054 let b = LumaA([255_u8, 0]);
1055 a.blend(&b);
1056 assert_eq!(a.0[0], 255);
1057 assert_eq!(a.0[1], 0);
1058 }
1059
1060 #[test]
1061 fn test_blend_rgba() {
1062 let a = &mut Rgba([255_u8, 255, 255, 255]);
1063 let b = Rgba([255_u8, 255, 255, 255]);
1064 a.blend(&b);
1065 assert_eq!(a.0, [255, 255, 255, 255]);
1066
1067 let a = &mut Rgba([255_u8, 255, 255, 0]);
1068 let b = Rgba([255_u8, 255, 255, 255]);
1069 a.blend(&b);
1070 assert_eq!(a.0, [255, 255, 255, 255]);
1071
1072 let a = &mut Rgba([255_u8, 255, 255, 255]);
1073 let b = Rgba([255_u8, 255, 255, 0]);
1074 a.blend(&b);
1075 assert_eq!(a.0, [255, 255, 255, 255]);
1076
1077 let a = &mut Rgba([255_u8, 255, 255, 0]);
1078 let b = Rgba([255_u8, 255, 255, 0]);
1079 a.blend(&b);
1080 assert_eq!(a.0, [255, 255, 255, 0]);
1081 }
1082
1083 #[test]
1084 fn test_apply_without_alpha_rgba() {
1085 let mut rgba = Rgba([0, 0, 0, 0]);
1086 rgba.apply_without_alpha(|s| s + 1);
1087 assert_eq!(rgba, Rgba([1, 1, 1, 0]));
1088 }
1089
1090 #[test]
1091 fn test_apply_without_alpha_rgb() {
1092 let mut rgb = Rgb([0, 0, 0]);
1093 rgb.apply_without_alpha(|s| s + 1);
1094 assert_eq!(rgb, Rgb([1, 1, 1]));
1095 }
1096
1097 #[test]
1098 fn test_map_without_alpha_rgba() {
1099 let rgba = Rgba([0, 0, 0, 0]).map_without_alpha(|s| s + 1);
1100 assert_eq!(rgba, Rgba([1, 1, 1, 0]));
1101 }
1102
1103 #[test]
1104 fn test_map_without_alpha_rgb() {
1105 let rgb = Rgb([0, 0, 0]).map_without_alpha(|s| s + 1);
1106 assert_eq!(rgb, Rgb([1, 1, 1]));
1107 }
1108
1109 macro_rules! test_lossless_conversion {
1110 ($a:ty, $b:ty, $c:ty) => {
1111 let a: $a = [<$a as Pixel>::Subpixel::DEFAULT_MAX_VALUE >> 2;
1112 <$a as Pixel>::CHANNEL_COUNT as usize]
1113 .into();
1114 let b: $b = a.into_color();
1115 let c: $c = b.into_color();
1116 assert_eq!(a.channels(), c.channels());
1117 };
1118 }
1119
1120 #[test]
1121 fn test_lossless_conversions() {
1122 use super::IntoColor;
1123 use crate::traits::Primitive;
1124
1125 test_lossless_conversion!(Luma<u8>, Luma<u16>, Luma<u8>);
1126 test_lossless_conversion!(LumaA<u8>, LumaA<u16>, LumaA<u8>);
1127 test_lossless_conversion!(Rgb<u8>, Rgb<u16>, Rgb<u8>);
1128 test_lossless_conversion!(Rgba<u8>, Rgba<u16>, Rgba<u8>);
1129 }
1130
1131 #[test]
1132 fn accuracy_conversion() {
1133 use super::{Luma, Pixel, Rgb};
1134 let pixel = Rgb::from([13, 13, 13]);
1135 let Luma([luma]) = pixel.to_luma();
1136 assert_eq!(luma, 13);
1137 }
1138}