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