1use std::ops::{Index, IndexMut};
2
3use num_traits::{NumCast, ToPrimitive, Zero};
4
5use crate::traits::{Enlargeable, Pixel, Primitive};
6
7#[derive(Copy, PartialEq, Eq, Debug, Clone, Hash)]
9#[non_exhaustive]
10pub enum ColorType {
11 L8,
13 La8,
15 Rgb8,
17 Rgba8,
19
20 L16,
22 La16,
24 Rgb16,
26 Rgba16,
28
29 Rgb32F,
31 Rgba32F,
33}
34
35impl ColorType {
36 #[must_use]
38 pub fn bytes_per_pixel(self) -> u8 {
39 match self {
40 ColorType::L8 => 1,
41 ColorType::L16 | ColorType::La8 => 2,
42 ColorType::Rgb8 => 3,
43 ColorType::Rgba8 | ColorType::La16 => 4,
44 ColorType::Rgb16 => 6,
45 ColorType::Rgba16 => 8,
46 ColorType::Rgb32F => 3 * 4,
47 ColorType::Rgba32F => 4 * 4,
48 }
49 }
50
51 #[must_use]
53 pub fn has_alpha(self) -> bool {
54 use ColorType::*;
55 match self {
56 L8 | L16 | Rgb8 | Rgb16 | Rgb32F => false,
57 La8 | Rgba8 | La16 | Rgba16 | Rgba32F => true,
58 }
59 }
60
61 #[must_use]
63 pub fn has_color(self) -> bool {
64 use ColorType::*;
65 match self {
66 L8 | L16 | La8 | La16 => false,
67 Rgb8 | Rgb16 | Rgba8 | Rgba16 | Rgb32F | Rgba32F => true,
68 }
69 }
70
71 #[must_use]
74 pub fn bits_per_pixel(self) -> u16 {
75 <u16 as From<u8>>::from(self.bytes_per_pixel()) * 8
76 }
77
78 #[must_use]
80 pub fn channel_count(self) -> u8 {
81 let e: ExtendedColorType = self.into();
82 e.channel_count()
83 }
84}
85
86#[derive(Copy, PartialEq, Eq, Debug, Clone, Hash)]
95#[non_exhaustive]
96pub enum ExtendedColorType {
97 A8,
99 L1,
101 La1,
103 Rgb1,
105 Rgba1,
107 L2,
109 La2,
111 Rgb2,
113 Rgba2,
115 L4,
117 La4,
119 Rgb4,
121 Rgba4,
123 L8,
125 La8,
127 Rgb8,
129 Rgba8,
131 L16,
133 La16,
135 Rgb16,
137 Rgba16,
139 Bgr8,
141 Bgra8,
143
144 Rgb32F,
147 Rgba32F,
149
150 Cmyk8,
152
153 Unknown(u8),
157}
158
159impl ExtendedColorType {
160 #[must_use]
165 pub fn channel_count(self) -> u8 {
166 match self {
167 ExtendedColorType::A8
168 | ExtendedColorType::L1
169 | ExtendedColorType::L2
170 | ExtendedColorType::L4
171 | ExtendedColorType::L8
172 | ExtendedColorType::L16
173 | ExtendedColorType::Unknown(_) => 1,
174 ExtendedColorType::La1
175 | ExtendedColorType::La2
176 | ExtendedColorType::La4
177 | ExtendedColorType::La8
178 | ExtendedColorType::La16 => 2,
179 ExtendedColorType::Rgb1
180 | ExtendedColorType::Rgb2
181 | ExtendedColorType::Rgb4
182 | ExtendedColorType::Rgb8
183 | ExtendedColorType::Rgb16
184 | ExtendedColorType::Rgb32F
185 | ExtendedColorType::Bgr8 => 3,
186 ExtendedColorType::Rgba1
187 | ExtendedColorType::Rgba2
188 | ExtendedColorType::Rgba4
189 | ExtendedColorType::Rgba8
190 | ExtendedColorType::Rgba16
191 | ExtendedColorType::Rgba32F
192 | ExtendedColorType::Bgra8
193 | ExtendedColorType::Cmyk8 => 4,
194 }
195 }
196
197 #[must_use]
199 pub fn bits_per_pixel(&self) -> u16 {
200 match *self {
201 ExtendedColorType::A8 => 8,
202 ExtendedColorType::L1 => 1,
203 ExtendedColorType::La1 => 2,
204 ExtendedColorType::Rgb1 => 3,
205 ExtendedColorType::Rgba1 => 4,
206 ExtendedColorType::L2 => 2,
207 ExtendedColorType::La2 => 4,
208 ExtendedColorType::Rgb2 => 6,
209 ExtendedColorType::Rgba2 => 8,
210 ExtendedColorType::L4 => 4,
211 ExtendedColorType::La4 => 8,
212 ExtendedColorType::Rgb4 => 12,
213 ExtendedColorType::Rgba4 => 16,
214 ExtendedColorType::L8 => 8,
215 ExtendedColorType::La8 => 16,
216 ExtendedColorType::Rgb8 => 24,
217 ExtendedColorType::Rgba8 => 32,
218 ExtendedColorType::L16 => 16,
219 ExtendedColorType::La16 => 32,
220 ExtendedColorType::Rgb16 => 48,
221 ExtendedColorType::Rgba16 => 64,
222 ExtendedColorType::Rgb32F => 96,
223 ExtendedColorType::Rgba32F => 128,
224 ExtendedColorType::Bgr8 => 24,
225 ExtendedColorType::Bgra8 => 32,
226 ExtendedColorType::Cmyk8 => 32,
227 ExtendedColorType::Unknown(bpp) => bpp as u16,
228 }
229 }
230
231 pub(crate) fn buffer_size(self, width: u32, height: u32) -> u64 {
233 let bpp = self.bits_per_pixel() as u64;
234 let row_pitch = (width as u64 * bpp + 7) / 8;
235 row_pitch.saturating_mul(height as u64)
236 }
237}
238impl From<ColorType> for ExtendedColorType {
239 fn from(c: ColorType) -> Self {
240 match c {
241 ColorType::L8 => ExtendedColorType::L8,
242 ColorType::La8 => ExtendedColorType::La8,
243 ColorType::Rgb8 => ExtendedColorType::Rgb8,
244 ColorType::Rgba8 => ExtendedColorType::Rgba8,
245 ColorType::L16 => ExtendedColorType::L16,
246 ColorType::La16 => ExtendedColorType::La16,
247 ColorType::Rgb16 => ExtendedColorType::Rgb16,
248 ColorType::Rgba16 => ExtendedColorType::Rgba16,
249 ColorType::Rgb32F => ExtendedColorType::Rgb32F,
250 ColorType::Rgba32F => ExtendedColorType::Rgba32F,
251 }
252 }
253}
254
255macro_rules! define_colors {
256 {$(
257 $(#[$doc:meta])*
258 pub struct $ident:ident<T: $($bound:ident)*>([T; $channels:expr, $alphas:expr])
259 = $interpretation:literal;
260 )*} => {
261
262$( $(#[$doc])*
265#[derive(PartialEq, Eq, Clone, Debug, Copy, Hash)]
266#[repr(transparent)]
267#[allow(missing_docs)]
268pub struct $ident<T> (pub [T; $channels]);
269
270impl<T: $($bound+)*> Pixel for $ident<T> {
271 type Subpixel = T;
272
273 const CHANNEL_COUNT: u8 = $channels;
274
275 #[inline(always)]
276 fn channels(&self) -> &[T] {
277 &self.0
278 }
279
280 #[inline(always)]
281 fn channels_mut(&mut self) -> &mut [T] {
282 &mut self.0
283 }
284
285 const COLOR_MODEL: &'static str = $interpretation;
286
287 fn channels4(&self) -> (T, T, T, T) {
288 const CHANNELS: usize = $channels;
289 let mut channels = [T::DEFAULT_MAX_VALUE; 4];
290 channels[0..CHANNELS].copy_from_slice(&self.0);
291 (channels[0], channels[1], channels[2], channels[3])
292 }
293
294 fn from_channels(a: T, b: T, c: T, d: T,) -> $ident<T> {
295 const CHANNELS: usize = $channels;
296 *<$ident<T> as Pixel>::from_slice(&[a, b, c, d][..CHANNELS])
297 }
298
299 fn from_slice(slice: &[T]) -> &$ident<T> {
300 assert_eq!(slice.len(), $channels);
301 unsafe { &*(slice.as_ptr() as *const $ident<T>) }
302 }
303 fn from_slice_mut(slice: &mut [T]) -> &mut $ident<T> {
304 assert_eq!(slice.len(), $channels);
305 unsafe { &mut *(slice.as_mut_ptr() as *mut $ident<T>) }
306 }
307
308 fn to_rgb(&self) -> Rgb<T> {
309 let mut pix = Rgb([Zero::zero(), Zero::zero(), Zero::zero()]);
310 pix.from_color(self);
311 pix
312 }
313
314 fn to_rgba(&self) -> Rgba<T> {
315 let mut pix = Rgba([Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero()]);
316 pix.from_color(self);
317 pix
318 }
319
320 fn to_luma(&self) -> Luma<T> {
321 let mut pix = Luma([Zero::zero()]);
322 pix.from_color(self);
323 pix
324 }
325
326 fn to_luma_alpha(&self) -> LumaA<T> {
327 let mut pix = LumaA([Zero::zero(), Zero::zero()]);
328 pix.from_color(self);
329 pix
330 }
331
332 fn map<F>(& self, f: F) -> $ident<T> where F: FnMut(T) -> T {
333 let mut this = (*self).clone();
334 this.apply(f);
335 this
336 }
337
338 fn apply<F>(&mut self, mut f: F) where F: FnMut(T) -> T {
339 for v in &mut self.0 {
340 *v = f(*v)
341 }
342 }
343
344 fn map_with_alpha<F, G>(&self, f: F, g: G) -> $ident<T> where F: FnMut(T) -> T, G: FnMut(T) -> T {
345 let mut this = (*self).clone();
346 this.apply_with_alpha(f, g);
347 this
348 }
349
350 fn apply_with_alpha<F, G>(&mut self, mut f: F, mut g: G) where F: FnMut(T) -> T, G: FnMut(T) -> T {
351 const ALPHA: usize = $channels - $alphas;
352 for v in self.0[..ALPHA].iter_mut() {
353 *v = f(*v)
354 }
355 if let Some(v) = self.0.get_mut(ALPHA) {
358 *v = g(*v)
359 }
360 }
361
362 fn map2<F>(&self, other: &Self, f: F) -> $ident<T> where F: FnMut(T, T) -> T {
363 let mut this = (*self).clone();
364 this.apply2(other, f);
365 this
366 }
367
368 fn apply2<F>(&mut self, other: &$ident<T>, mut f: F) where F: FnMut(T, T) -> T {
369 for (a, &b) in self.0.iter_mut().zip(other.0.iter()) {
370 *a = f(*a, b)
371 }
372 }
373
374 fn invert(&mut self) {
375 Invert::invert(self)
376 }
377
378 fn blend(&mut self, other: &$ident<T>) {
379 Blend::blend(self, other)
380 }
381}
382
383impl<T> Index<usize> for $ident<T> {
384 type Output = T;
385 #[inline(always)]
386 fn index(&self, _index: usize) -> &T {
387 &self.0[_index]
388 }
389}
390
391impl<T> IndexMut<usize> for $ident<T> {
392 #[inline(always)]
393 fn index_mut(&mut self, _index: usize) -> &mut T {
394 &mut self.0[_index]
395 }
396}
397
398impl<T> From<[T; $channels]> for $ident<T> {
399 fn from(c: [T; $channels]) -> Self {
400 Self(c)
401 }
402}
403
404)* }
407}
408
409define_colors! {
410 pub struct Rgb<T: Primitive Enlargeable>([T; 3, 0]) = "RGB";
415 pub struct Luma<T: Primitive>([T; 1, 0]) = "Y";
417 pub struct Rgba<T: Primitive Enlargeable>([T; 4, 1]) = "RGBA";
419 pub struct LumaA<T: Primitive>([T; 2, 1]) = "YA";
421}
422
423pub trait FromPrimitive<Component> {
425 fn from_primitive(component: Component) -> Self;
427}
428
429impl<T: Primitive> FromPrimitive<T> for T {
430 fn from_primitive(sample: T) -> Self {
431 sample
432 }
433}
434
435#[inline]
443fn normalize_float(float: f32, max: f32) -> f32 {
444 #[allow(clippy::neg_cmp_op_on_partial_ord)]
445 let clamped = if !(float < 1.0) { 1.0 } else { float.max(0.0) };
446 (clamped * max).round()
447}
448
449impl FromPrimitive<f32> for u8 {
450 fn from_primitive(float: f32) -> Self {
451 NumCast::from(normalize_float(float, u8::MAX as f32)).unwrap()
452 }
453}
454
455impl FromPrimitive<f32> for u16 {
456 fn from_primitive(float: f32) -> Self {
457 NumCast::from(normalize_float(float, u16::MAX as f32)).unwrap()
458 }
459}
460
461impl FromPrimitive<u16> for u8 {
464 fn from_primitive(c16: u16) -> Self {
465 fn from(c: impl Into<u32>) -> u32 {
466 c.into()
467 }
468 NumCast::from((from(c16) + 128) / 257).unwrap()
475 }
476}
477
478impl FromPrimitive<u16> for f32 {
479 fn from_primitive(int: u16) -> Self {
480 (int as f32 / u16::MAX as f32).clamp(0.0, 1.0)
481 }
482}
483
484impl FromPrimitive<u8> for f32 {
487 fn from_primitive(int: u8) -> Self {
488 (int as f32 / u8::MAX as f32).clamp(0.0, 1.0)
489 }
490}
491
492impl FromPrimitive<u8> for u16 {
493 fn from_primitive(c8: u8) -> Self {
494 let x = c8.to_u64().unwrap();
495 NumCast::from((x << 8) | x).unwrap()
496 }
497}
498
499pub trait FromColor<Other> {
501 #[allow(clippy::wrong_self_convention)]
503 fn from_color(&mut self, _: &Other);
504}
505
506pub(crate) trait IntoColor<Other> {
510 #[allow(clippy::wrong_self_convention)]
512 fn into_color(&self) -> Other;
513}
514
515impl<O, S> IntoColor<O> for S
516where
517 O: Pixel + FromColor<S>,
518{
519 #[allow(clippy::wrong_self_convention)]
520 fn into_color(&self) -> O {
521 #[allow(deprecated)]
524 let mut pix = O::from_channels(Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero());
525 pix.from_color(self);
526 pix
527 }
528}
529
530const SRGB_LUMA: [u32; 3] = [2126, 7152, 722];
532const SRGB_LUMA_DIV: u32 = 10000;
533
534#[inline]
535fn rgb_to_luma<T: Primitive + Enlargeable>(rgb: &[T]) -> T {
536 let l = <T::Larger as NumCast>::from(SRGB_LUMA[0]).unwrap() * rgb[0].to_larger()
537 + <T::Larger as NumCast>::from(SRGB_LUMA[1]).unwrap() * rgb[1].to_larger()
538 + <T::Larger as NumCast>::from(SRGB_LUMA[2]).unwrap() * rgb[2].to_larger();
539 T::clamp_from(l / <T::Larger as NumCast>::from(SRGB_LUMA_DIV).unwrap())
540}
541
542impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for Luma<T>
544where
545 T: FromPrimitive<S>,
546{
547 fn from_color(&mut self, other: &Luma<S>) {
548 let own = self.channels_mut();
549 let other = other.channels();
550 own[0] = T::from_primitive(other[0]);
551 }
552}
553
554impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for Luma<T>
555where
556 T: FromPrimitive<S>,
557{
558 fn from_color(&mut self, other: &LumaA<S>) {
559 self.channels_mut()[0] = T::from_primitive(other.channels()[0]);
560 }
561}
562
563impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgb<S>> for Luma<T>
564where
565 T: FromPrimitive<S>,
566{
567 fn from_color(&mut self, other: &Rgb<S>) {
568 let gray = self.channels_mut();
569 let rgb = other.channels();
570 gray[0] = T::from_primitive(rgb_to_luma(rgb));
571 }
572}
573
574impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgba<S>> for Luma<T>
575where
576 T: FromPrimitive<S>,
577{
578 fn from_color(&mut self, other: &Rgba<S>) {
579 let gray = self.channels_mut();
580 let rgb = other.channels();
581 let l = rgb_to_luma(rgb);
582 gray[0] = T::from_primitive(l);
583 }
584}
585
586impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for LumaA<T>
589where
590 T: FromPrimitive<S>,
591{
592 fn from_color(&mut self, other: &LumaA<S>) {
593 let own = self.channels_mut();
594 let other = other.channels();
595 own[0] = T::from_primitive(other[0]);
596 own[1] = T::from_primitive(other[1]);
597 }
598}
599
600impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgb<S>> for LumaA<T>
601where
602 T: FromPrimitive<S>,
603{
604 fn from_color(&mut self, other: &Rgb<S>) {
605 let gray_a = self.channels_mut();
606 let rgb = other.channels();
607 gray_a[0] = T::from_primitive(rgb_to_luma(rgb));
608 gray_a[1] = T::DEFAULT_MAX_VALUE;
609 }
610}
611
612impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgba<S>> for LumaA<T>
613where
614 T: FromPrimitive<S>,
615{
616 fn from_color(&mut self, other: &Rgba<S>) {
617 let gray_a = self.channels_mut();
618 let rgba = other.channels();
619 gray_a[0] = T::from_primitive(rgb_to_luma(rgba));
620 gray_a[1] = T::from_primitive(rgba[3]);
621 }
622}
623
624impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for LumaA<T>
625where
626 T: FromPrimitive<S>,
627{
628 fn from_color(&mut self, other: &Luma<S>) {
629 let gray_a = self.channels_mut();
630 gray_a[0] = T::from_primitive(other.channels()[0]);
631 gray_a[1] = T::DEFAULT_MAX_VALUE;
632 }
633}
634
635impl<S: Primitive, T: Primitive> FromColor<Rgba<S>> for Rgba<T>
638where
639 T: FromPrimitive<S>,
640{
641 fn from_color(&mut self, other: &Rgba<S>) {
642 let own = &mut self.0;
643 let other = &other.0;
644 own[0] = T::from_primitive(other[0]);
645 own[1] = T::from_primitive(other[1]);
646 own[2] = T::from_primitive(other[2]);
647 own[3] = T::from_primitive(other[3]);
648 }
649}
650
651impl<S: Primitive, T: Primitive> FromColor<Rgb<S>> for Rgba<T>
652where
653 T: FromPrimitive<S>,
654{
655 fn from_color(&mut self, other: &Rgb<S>) {
656 let rgba = &mut self.0;
657 let rgb = &other.0;
658 rgba[0] = T::from_primitive(rgb[0]);
659 rgba[1] = T::from_primitive(rgb[1]);
660 rgba[2] = T::from_primitive(rgb[2]);
661 rgba[3] = T::DEFAULT_MAX_VALUE;
662 }
663}
664
665impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for Rgba<T>
666where
667 T: FromPrimitive<S>,
668{
669 fn from_color(&mut self, gray: &LumaA<S>) {
670 let rgba = &mut self.0;
671 let gray = &gray.0;
672 rgba[0] = T::from_primitive(gray[0]);
673 rgba[1] = T::from_primitive(gray[0]);
674 rgba[2] = T::from_primitive(gray[0]);
675 rgba[3] = T::from_primitive(gray[1]);
676 }
677}
678
679impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for Rgba<T>
680where
681 T: FromPrimitive<S>,
682{
683 fn from_color(&mut self, gray: &Luma<S>) {
684 let rgba = &mut self.0;
685 let gray = gray.0[0];
686 rgba[0] = T::from_primitive(gray);
687 rgba[1] = T::from_primitive(gray);
688 rgba[2] = T::from_primitive(gray);
689 rgba[3] = T::DEFAULT_MAX_VALUE;
690 }
691}
692
693impl<S: Primitive, T: Primitive> FromColor<Rgb<S>> for Rgb<T>
696where
697 T: FromPrimitive<S>,
698{
699 fn from_color(&mut self, other: &Rgb<S>) {
700 let own = &mut self.0;
701 let other = &other.0;
702 own[0] = T::from_primitive(other[0]);
703 own[1] = T::from_primitive(other[1]);
704 own[2] = T::from_primitive(other[2]);
705 }
706}
707
708impl<S: Primitive, T: Primitive> FromColor<Rgba<S>> for Rgb<T>
709where
710 T: FromPrimitive<S>,
711{
712 fn from_color(&mut self, other: &Rgba<S>) {
713 let rgb = &mut self.0;
714 let rgba = &other.0;
715 rgb[0] = T::from_primitive(rgba[0]);
716 rgb[1] = T::from_primitive(rgba[1]);
717 rgb[2] = T::from_primitive(rgba[2]);
718 }
719}
720
721impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for Rgb<T>
722where
723 T: FromPrimitive<S>,
724{
725 fn from_color(&mut self, other: &LumaA<S>) {
726 let rgb = &mut self.0;
727 let gray = other.0[0];
728 rgb[0] = T::from_primitive(gray);
729 rgb[1] = T::from_primitive(gray);
730 rgb[2] = T::from_primitive(gray);
731 }
732}
733
734impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for Rgb<T>
735where
736 T: FromPrimitive<S>,
737{
738 fn from_color(&mut self, other: &Luma<S>) {
739 let rgb = &mut self.0;
740 let gray = other.0[0];
741 rgb[0] = T::from_primitive(gray);
742 rgb[1] = T::from_primitive(gray);
743 rgb[2] = T::from_primitive(gray);
744 }
745}
746
747pub(crate) trait Blend {
749 fn blend(&mut self, other: &Self);
751}
752
753impl<T: Primitive> Blend for LumaA<T> {
754 fn blend(&mut self, other: &LumaA<T>) {
755 let max_t = T::DEFAULT_MAX_VALUE;
756 let max_t = max_t.to_f32().unwrap();
757 let (bg_luma, bg_a) = (self.0[0], self.0[1]);
758 let (fg_luma, fg_a) = (other.0[0], other.0[1]);
759
760 let (bg_luma, bg_a) = (
761 bg_luma.to_f32().unwrap() / max_t,
762 bg_a.to_f32().unwrap() / max_t,
763 );
764 let (fg_luma, fg_a) = (
765 fg_luma.to_f32().unwrap() / max_t,
766 fg_a.to_f32().unwrap() / max_t,
767 );
768
769 let alpha_final = bg_a + fg_a - bg_a * fg_a;
770 if alpha_final == 0.0 {
771 return;
772 };
773 let bg_luma_a = bg_luma * bg_a;
774 let fg_luma_a = fg_luma * fg_a;
775
776 let out_luma_a = fg_luma_a + bg_luma_a * (1.0 - fg_a);
777 let out_luma = out_luma_a / alpha_final;
778
779 *self = LumaA([
780 NumCast::from(max_t * out_luma).unwrap(),
781 NumCast::from(max_t * alpha_final).unwrap(),
782 ]);
783 }
784}
785
786impl<T: Primitive> Blend for Luma<T> {
787 fn blend(&mut self, other: &Luma<T>) {
788 *self = *other;
789 }
790}
791
792impl<T: Primitive> Blend for Rgba<T> {
793 fn blend(&mut self, other: &Rgba<T>) {
794 if other.0[3].is_zero() {
797 return;
798 }
799 if other.0[3] == T::DEFAULT_MAX_VALUE {
800 *self = *other;
801 return;
802 }
803
804 let max_t = T::DEFAULT_MAX_VALUE;
806 let max_t = max_t.to_f32().unwrap();
807 let (bg_r, bg_g, bg_b, bg_a) = (self.0[0], self.0[1], self.0[2], self.0[3]);
808 let (fg_r, fg_g, fg_b, fg_a) = (other.0[0], other.0[1], other.0[2], other.0[3]);
809 let (bg_r, bg_g, bg_b, bg_a) = (
810 bg_r.to_f32().unwrap() / max_t,
811 bg_g.to_f32().unwrap() / max_t,
812 bg_b.to_f32().unwrap() / max_t,
813 bg_a.to_f32().unwrap() / max_t,
814 );
815 let (fg_r, fg_g, fg_b, fg_a) = (
816 fg_r.to_f32().unwrap() / max_t,
817 fg_g.to_f32().unwrap() / max_t,
818 fg_b.to_f32().unwrap() / max_t,
819 fg_a.to_f32().unwrap() / max_t,
820 );
821
822 let alpha_final = bg_a + fg_a - bg_a * fg_a;
824 if alpha_final == 0.0 {
825 return;
826 };
827
828 let (bg_r_a, bg_g_a, bg_b_a) = (bg_r * bg_a, bg_g * bg_a, bg_b * bg_a);
830 let (fg_r_a, fg_g_a, fg_b_a) = (fg_r * fg_a, fg_g * fg_a, fg_b * fg_a);
831
832 let (out_r_a, out_g_a, out_b_a) = (
834 fg_r_a + bg_r_a * (1.0 - fg_a),
835 fg_g_a + bg_g_a * (1.0 - fg_a),
836 fg_b_a + bg_b_a * (1.0 - fg_a),
837 );
838
839 let (out_r, out_g, out_b) = (
841 out_r_a / alpha_final,
842 out_g_a / alpha_final,
843 out_b_a / alpha_final,
844 );
845
846 *self = Rgba([
848 NumCast::from(max_t * out_r).unwrap(),
849 NumCast::from(max_t * out_g).unwrap(),
850 NumCast::from(max_t * out_b).unwrap(),
851 NumCast::from(max_t * alpha_final).unwrap(),
852 ]);
853 }
854}
855
856impl<T: Primitive> Blend for Rgb<T> {
857 fn blend(&mut self, other: &Rgb<T>) {
858 *self = *other;
859 }
860}
861
862pub(crate) trait Invert {
864 fn invert(&mut self);
866}
867
868impl<T: Primitive> Invert for LumaA<T> {
869 fn invert(&mut self) {
870 let l = self.0;
871 let max = T::DEFAULT_MAX_VALUE;
872
873 *self = LumaA([max - l[0], l[1]]);
874 }
875}
876
877impl<T: Primitive> Invert for Luma<T> {
878 fn invert(&mut self) {
879 let l = self.0;
880
881 let max = T::DEFAULT_MAX_VALUE;
882 let l1 = max - l[0];
883
884 *self = Luma([l1]);
885 }
886}
887
888impl<T: Primitive> Invert for Rgba<T> {
889 fn invert(&mut self) {
890 let rgba = self.0;
891
892 let max = T::DEFAULT_MAX_VALUE;
893
894 *self = Rgba([max - rgba[0], max - rgba[1], max - rgba[2], rgba[3]]);
895 }
896}
897
898impl<T: Primitive> Invert for Rgb<T> {
899 fn invert(&mut self) {
900 let rgb = self.0;
901
902 let max = T::DEFAULT_MAX_VALUE;
903
904 let r1 = max - rgb[0];
905 let g1 = max - rgb[1];
906 let b1 = max - rgb[2];
907
908 *self = Rgb([r1, g1, b1]);
909 }
910}
911
912#[cfg(test)]
913mod tests {
914 use super::{Luma, LumaA, Pixel, Rgb, Rgba};
915
916 #[test]
917 fn test_apply_with_alpha_rgba() {
918 let mut rgba = Rgba([0, 0, 0, 0]);
919 rgba.apply_with_alpha(|s| s, |_| 0xFF);
920 assert_eq!(rgba, Rgba([0, 0, 0, 0xFF]));
921 }
922
923 #[test]
924 fn test_apply_with_alpha_rgb() {
925 let mut rgb = Rgb([0, 0, 0]);
926 rgb.apply_with_alpha(|s| s, |_| panic!("bug"));
927 assert_eq!(rgb, Rgb([0, 0, 0]));
928 }
929
930 #[test]
931 fn test_map_with_alpha_rgba() {
932 let rgba = Rgba([0, 0, 0, 0]).map_with_alpha(|s| s, |_| 0xFF);
933 assert_eq!(rgba, Rgba([0, 0, 0, 0xFF]));
934 }
935
936 #[test]
937 fn test_map_with_alpha_rgb() {
938 let rgb = Rgb([0, 0, 0]).map_with_alpha(|s| s, |_| panic!("bug"));
939 assert_eq!(rgb, Rgb([0, 0, 0]));
940 }
941
942 #[test]
943 fn test_blend_luma_alpha() {
944 let a = &mut LumaA([255_u8, 255]);
945 let b = LumaA([255_u8, 255]);
946 a.blend(&b);
947 assert_eq!(a.0[0], 255);
948 assert_eq!(a.0[1], 255);
949
950 let a = &mut LumaA([255_u8, 0]);
951 let b = LumaA([255_u8, 255]);
952 a.blend(&b);
953 assert_eq!(a.0[0], 255);
954 assert_eq!(a.0[1], 255);
955
956 let a = &mut LumaA([255_u8, 255]);
957 let b = LumaA([255_u8, 0]);
958 a.blend(&b);
959 assert_eq!(a.0[0], 255);
960 assert_eq!(a.0[1], 255);
961
962 let a = &mut LumaA([255_u8, 0]);
963 let b = LumaA([255_u8, 0]);
964 a.blend(&b);
965 assert_eq!(a.0[0], 255);
966 assert_eq!(a.0[1], 0);
967 }
968
969 #[test]
970 fn test_blend_rgba() {
971 let a = &mut Rgba([255_u8, 255, 255, 255]);
972 let b = Rgba([255_u8, 255, 255, 255]);
973 a.blend(&b);
974 assert_eq!(a.0, [255, 255, 255, 255]);
975
976 let a = &mut Rgba([255_u8, 255, 255, 0]);
977 let b = Rgba([255_u8, 255, 255, 255]);
978 a.blend(&b);
979 assert_eq!(a.0, [255, 255, 255, 255]);
980
981 let a = &mut Rgba([255_u8, 255, 255, 255]);
982 let b = Rgba([255_u8, 255, 255, 0]);
983 a.blend(&b);
984 assert_eq!(a.0, [255, 255, 255, 255]);
985
986 let a = &mut Rgba([255_u8, 255, 255, 0]);
987 let b = Rgba([255_u8, 255, 255, 0]);
988 a.blend(&b);
989 assert_eq!(a.0, [255, 255, 255, 0]);
990 }
991
992 #[test]
993 fn test_apply_without_alpha_rgba() {
994 let mut rgba = Rgba([0, 0, 0, 0]);
995 rgba.apply_without_alpha(|s| s + 1);
996 assert_eq!(rgba, Rgba([1, 1, 1, 0]));
997 }
998
999 #[test]
1000 fn test_apply_without_alpha_rgb() {
1001 let mut rgb = Rgb([0, 0, 0]);
1002 rgb.apply_without_alpha(|s| s + 1);
1003 assert_eq!(rgb, Rgb([1, 1, 1]));
1004 }
1005
1006 #[test]
1007 fn test_map_without_alpha_rgba() {
1008 let rgba = Rgba([0, 0, 0, 0]).map_without_alpha(|s| s + 1);
1009 assert_eq!(rgba, Rgba([1, 1, 1, 0]));
1010 }
1011
1012 #[test]
1013 fn test_map_without_alpha_rgb() {
1014 let rgb = Rgb([0, 0, 0]).map_without_alpha(|s| s + 1);
1015 assert_eq!(rgb, Rgb([1, 1, 1]));
1016 }
1017
1018 macro_rules! test_lossless_conversion {
1019 ($a:ty, $b:ty, $c:ty) => {
1020 let a: $a = [<$a as Pixel>::Subpixel::DEFAULT_MAX_VALUE >> 2;
1021 <$a as Pixel>::CHANNEL_COUNT as usize]
1022 .into();
1023 let b: $b = a.into_color();
1024 let c: $c = b.into_color();
1025 assert_eq!(a.channels(), c.channels());
1026 };
1027 }
1028
1029 #[test]
1030 fn test_lossless_conversions() {
1031 use super::IntoColor;
1032 use crate::traits::Primitive;
1033
1034 test_lossless_conversion!(Luma<u8>, Luma<u16>, Luma<u8>);
1035 test_lossless_conversion!(LumaA<u8>, LumaA<u16>, LumaA<u8>);
1036 test_lossless_conversion!(Rgb<u8>, Rgb<u16>, Rgb<u8>);
1037 test_lossless_conversion!(Rgba<u8>, Rgba<u16>, Rgba<u8>);
1038 }
1039
1040 #[test]
1041 fn accuracy_conversion() {
1042 use super::{Luma, Pixel, Rgb};
1043 let pixel = Rgb::from([13, 13, 13]);
1044 let Luma([luma]) = pixel.to_luma();
1045 assert_eq!(luma, 13);
1046 }
1047}