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