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
435impl FromPrimitive<f32> for u8 {
440 fn from_primitive(float: f32) -> Self {
441 let inner = (float.clamp(0.0, 1.0) * u8::MAX as f32).round();
442 NumCast::from(inner).unwrap()
443 }
444}
445
446impl FromPrimitive<f32> for u16 {
447 fn from_primitive(float: f32) -> Self {
448 let inner = (float.clamp(0.0, 1.0) * u16::MAX as f32).round();
449 NumCast::from(inner).unwrap()
450 }
451}
452
453impl FromPrimitive<u16> for u8 {
456 fn from_primitive(c16: u16) -> Self {
457 fn from(c: impl Into<u32>) -> u32 {
458 c.into()
459 }
460 NumCast::from((from(c16) + 128) / 257).unwrap()
467 }
468}
469
470impl FromPrimitive<u16> for f32 {
471 fn from_primitive(int: u16) -> Self {
472 (int as f32 / u16::MAX as f32).clamp(0.0, 1.0)
473 }
474}
475
476impl FromPrimitive<u8> for f32 {
479 fn from_primitive(int: u8) -> Self {
480 (int as f32 / u8::MAX as f32).clamp(0.0, 1.0)
481 }
482}
483
484impl FromPrimitive<u8> for u16 {
485 fn from_primitive(c8: u8) -> Self {
486 let x = c8.to_u64().unwrap();
487 NumCast::from((x << 8) | x).unwrap()
488 }
489}
490
491pub trait FromColor<Other> {
493 #[allow(clippy::wrong_self_convention)]
495 fn from_color(&mut self, _: &Other);
496}
497
498pub(crate) trait IntoColor<Other> {
502 #[allow(clippy::wrong_self_convention)]
504 fn into_color(&self) -> Other;
505}
506
507impl<O, S> IntoColor<O> for S
508where
509 O: Pixel + FromColor<S>,
510{
511 #[allow(clippy::wrong_self_convention)]
512 fn into_color(&self) -> O {
513 #[allow(deprecated)]
516 let mut pix = O::from_channels(Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero());
517 pix.from_color(self);
518 pix
519 }
520}
521
522const SRGB_LUMA: [u32; 3] = [2126, 7152, 722];
524const SRGB_LUMA_DIV: u32 = 10000;
525
526#[inline]
527fn rgb_to_luma<T: Primitive + Enlargeable>(rgb: &[T]) -> T {
528 let l = <T::Larger as NumCast>::from(SRGB_LUMA[0]).unwrap() * rgb[0].to_larger()
529 + <T::Larger as NumCast>::from(SRGB_LUMA[1]).unwrap() * rgb[1].to_larger()
530 + <T::Larger as NumCast>::from(SRGB_LUMA[2]).unwrap() * rgb[2].to_larger();
531 T::clamp_from(l / <T::Larger as NumCast>::from(SRGB_LUMA_DIV).unwrap())
532}
533
534impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for Luma<T>
536where
537 T: FromPrimitive<S>,
538{
539 fn from_color(&mut self, other: &Luma<S>) {
540 let own = self.channels_mut();
541 let other = other.channels();
542 own[0] = T::from_primitive(other[0]);
543 }
544}
545
546impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for Luma<T>
547where
548 T: FromPrimitive<S>,
549{
550 fn from_color(&mut self, other: &LumaA<S>) {
551 self.channels_mut()[0] = T::from_primitive(other.channels()[0]);
552 }
553}
554
555impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgb<S>> for Luma<T>
556where
557 T: FromPrimitive<S>,
558{
559 fn from_color(&mut self, other: &Rgb<S>) {
560 let gray = self.channels_mut();
561 let rgb = other.channels();
562 gray[0] = T::from_primitive(rgb_to_luma(rgb));
563 }
564}
565
566impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgba<S>> for Luma<T>
567where
568 T: FromPrimitive<S>,
569{
570 fn from_color(&mut self, other: &Rgba<S>) {
571 let gray = self.channels_mut();
572 let rgb = other.channels();
573 let l = rgb_to_luma(rgb);
574 gray[0] = T::from_primitive(l);
575 }
576}
577
578impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for LumaA<T>
581where
582 T: FromPrimitive<S>,
583{
584 fn from_color(&mut self, other: &LumaA<S>) {
585 let own = self.channels_mut();
586 let other = other.channels();
587 own[0] = T::from_primitive(other[0]);
588 own[1] = T::from_primitive(other[1]);
589 }
590}
591
592impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgb<S>> for LumaA<T>
593where
594 T: FromPrimitive<S>,
595{
596 fn from_color(&mut self, other: &Rgb<S>) {
597 let gray_a = self.channels_mut();
598 let rgb = other.channels();
599 gray_a[0] = T::from_primitive(rgb_to_luma(rgb));
600 gray_a[1] = T::DEFAULT_MAX_VALUE;
601 }
602}
603
604impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgba<S>> for LumaA<T>
605where
606 T: FromPrimitive<S>,
607{
608 fn from_color(&mut self, other: &Rgba<S>) {
609 let gray_a = self.channels_mut();
610 let rgba = other.channels();
611 gray_a[0] = T::from_primitive(rgb_to_luma(rgba));
612 gray_a[1] = T::from_primitive(rgba[3]);
613 }
614}
615
616impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for LumaA<T>
617where
618 T: FromPrimitive<S>,
619{
620 fn from_color(&mut self, other: &Luma<S>) {
621 let gray_a = self.channels_mut();
622 gray_a[0] = T::from_primitive(other.channels()[0]);
623 gray_a[1] = T::DEFAULT_MAX_VALUE;
624 }
625}
626
627impl<S: Primitive, T: Primitive> FromColor<Rgba<S>> for Rgba<T>
630where
631 T: FromPrimitive<S>,
632{
633 fn from_color(&mut self, other: &Rgba<S>) {
634 let own = &mut self.0;
635 let other = &other.0;
636 own[0] = T::from_primitive(other[0]);
637 own[1] = T::from_primitive(other[1]);
638 own[2] = T::from_primitive(other[2]);
639 own[3] = T::from_primitive(other[3]);
640 }
641}
642
643impl<S: Primitive, T: Primitive> FromColor<Rgb<S>> for Rgba<T>
644where
645 T: FromPrimitive<S>,
646{
647 fn from_color(&mut self, other: &Rgb<S>) {
648 let rgba = &mut self.0;
649 let rgb = &other.0;
650 rgba[0] = T::from_primitive(rgb[0]);
651 rgba[1] = T::from_primitive(rgb[1]);
652 rgba[2] = T::from_primitive(rgb[2]);
653 rgba[3] = T::DEFAULT_MAX_VALUE;
654 }
655}
656
657impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for Rgba<T>
658where
659 T: FromPrimitive<S>,
660{
661 fn from_color(&mut self, gray: &LumaA<S>) {
662 let rgba = &mut self.0;
663 let gray = &gray.0;
664 rgba[0] = T::from_primitive(gray[0]);
665 rgba[1] = T::from_primitive(gray[0]);
666 rgba[2] = T::from_primitive(gray[0]);
667 rgba[3] = T::from_primitive(gray[1]);
668 }
669}
670
671impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for Rgba<T>
672where
673 T: FromPrimitive<S>,
674{
675 fn from_color(&mut self, gray: &Luma<S>) {
676 let rgba = &mut self.0;
677 let gray = gray.0[0];
678 rgba[0] = T::from_primitive(gray);
679 rgba[1] = T::from_primitive(gray);
680 rgba[2] = T::from_primitive(gray);
681 rgba[3] = T::DEFAULT_MAX_VALUE;
682 }
683}
684
685impl<S: Primitive, T: Primitive> FromColor<Rgb<S>> for Rgb<T>
688where
689 T: FromPrimitive<S>,
690{
691 fn from_color(&mut self, other: &Rgb<S>) {
692 let own = &mut self.0;
693 let other = &other.0;
694 own[0] = T::from_primitive(other[0]);
695 own[1] = T::from_primitive(other[1]);
696 own[2] = T::from_primitive(other[2]);
697 }
698}
699
700impl<S: Primitive, T: Primitive> FromColor<Rgba<S>> for Rgb<T>
701where
702 T: FromPrimitive<S>,
703{
704 fn from_color(&mut self, other: &Rgba<S>) {
705 let rgb = &mut self.0;
706 let rgba = &other.0;
707 rgb[0] = T::from_primitive(rgba[0]);
708 rgb[1] = T::from_primitive(rgba[1]);
709 rgb[2] = T::from_primitive(rgba[2]);
710 }
711}
712
713impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for Rgb<T>
714where
715 T: FromPrimitive<S>,
716{
717 fn from_color(&mut self, other: &LumaA<S>) {
718 let rgb = &mut self.0;
719 let gray = other.0[0];
720 rgb[0] = T::from_primitive(gray);
721 rgb[1] = T::from_primitive(gray);
722 rgb[2] = T::from_primitive(gray);
723 }
724}
725
726impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for Rgb<T>
727where
728 T: FromPrimitive<S>,
729{
730 fn from_color(&mut self, other: &Luma<S>) {
731 let rgb = &mut self.0;
732 let gray = other.0[0];
733 rgb[0] = T::from_primitive(gray);
734 rgb[1] = T::from_primitive(gray);
735 rgb[2] = T::from_primitive(gray);
736 }
737}
738
739pub(crate) trait Blend {
741 fn blend(&mut self, other: &Self);
743}
744
745impl<T: Primitive> Blend for LumaA<T> {
746 fn blend(&mut self, other: &LumaA<T>) {
747 let max_t = T::DEFAULT_MAX_VALUE;
748 let max_t = max_t.to_f32().unwrap();
749 let (bg_luma, bg_a) = (self.0[0], self.0[1]);
750 let (fg_luma, fg_a) = (other.0[0], other.0[1]);
751
752 let (bg_luma, bg_a) = (
753 bg_luma.to_f32().unwrap() / max_t,
754 bg_a.to_f32().unwrap() / max_t,
755 );
756 let (fg_luma, fg_a) = (
757 fg_luma.to_f32().unwrap() / max_t,
758 fg_a.to_f32().unwrap() / max_t,
759 );
760
761 let alpha_final = bg_a + fg_a - bg_a * fg_a;
762 if alpha_final == 0.0 {
763 return;
764 };
765 let bg_luma_a = bg_luma * bg_a;
766 let fg_luma_a = fg_luma * fg_a;
767
768 let out_luma_a = fg_luma_a + bg_luma_a * (1.0 - fg_a);
769 let out_luma = out_luma_a / alpha_final;
770
771 *self = LumaA([
772 NumCast::from(max_t * out_luma).unwrap(),
773 NumCast::from(max_t * alpha_final).unwrap(),
774 ]);
775 }
776}
777
778impl<T: Primitive> Blend for Luma<T> {
779 fn blend(&mut self, other: &Luma<T>) {
780 *self = *other;
781 }
782}
783
784impl<T: Primitive> Blend for Rgba<T> {
785 fn blend(&mut self, other: &Rgba<T>) {
786 if other.0[3].is_zero() {
789 return;
790 }
791 if other.0[3] == T::DEFAULT_MAX_VALUE {
792 *self = *other;
793 return;
794 }
795
796 let max_t = T::DEFAULT_MAX_VALUE;
798 let max_t = max_t.to_f32().unwrap();
799 let (bg_r, bg_g, bg_b, bg_a) = (self.0[0], self.0[1], self.0[2], self.0[3]);
800 let (fg_r, fg_g, fg_b, fg_a) = (other.0[0], other.0[1], other.0[2], other.0[3]);
801 let (bg_r, bg_g, bg_b, bg_a) = (
802 bg_r.to_f32().unwrap() / max_t,
803 bg_g.to_f32().unwrap() / max_t,
804 bg_b.to_f32().unwrap() / max_t,
805 bg_a.to_f32().unwrap() / max_t,
806 );
807 let (fg_r, fg_g, fg_b, fg_a) = (
808 fg_r.to_f32().unwrap() / max_t,
809 fg_g.to_f32().unwrap() / max_t,
810 fg_b.to_f32().unwrap() / max_t,
811 fg_a.to_f32().unwrap() / max_t,
812 );
813
814 let alpha_final = bg_a + fg_a - bg_a * fg_a;
816 if alpha_final == 0.0 {
817 return;
818 };
819
820 let (bg_r_a, bg_g_a, bg_b_a) = (bg_r * bg_a, bg_g * bg_a, bg_b * bg_a);
822 let (fg_r_a, fg_g_a, fg_b_a) = (fg_r * fg_a, fg_g * fg_a, fg_b * fg_a);
823
824 let (out_r_a, out_g_a, out_b_a) = (
826 fg_r_a + bg_r_a * (1.0 - fg_a),
827 fg_g_a + bg_g_a * (1.0 - fg_a),
828 fg_b_a + bg_b_a * (1.0 - fg_a),
829 );
830
831 let (out_r, out_g, out_b) = (
833 out_r_a / alpha_final,
834 out_g_a / alpha_final,
835 out_b_a / alpha_final,
836 );
837
838 *self = Rgba([
840 NumCast::from(max_t * out_r).unwrap(),
841 NumCast::from(max_t * out_g).unwrap(),
842 NumCast::from(max_t * out_b).unwrap(),
843 NumCast::from(max_t * alpha_final).unwrap(),
844 ]);
845 }
846}
847
848impl<T: Primitive> Blend for Rgb<T> {
849 fn blend(&mut self, other: &Rgb<T>) {
850 *self = *other;
851 }
852}
853
854pub(crate) trait Invert {
856 fn invert(&mut self);
858}
859
860impl<T: Primitive> Invert for LumaA<T> {
861 fn invert(&mut self) {
862 let l = self.0;
863 let max = T::DEFAULT_MAX_VALUE;
864
865 *self = LumaA([max - l[0], l[1]]);
866 }
867}
868
869impl<T: Primitive> Invert for Luma<T> {
870 fn invert(&mut self) {
871 let l = self.0;
872
873 let max = T::DEFAULT_MAX_VALUE;
874 let l1 = max - l[0];
875
876 *self = Luma([l1]);
877 }
878}
879
880impl<T: Primitive> Invert for Rgba<T> {
881 fn invert(&mut self) {
882 let rgba = self.0;
883
884 let max = T::DEFAULT_MAX_VALUE;
885
886 *self = Rgba([max - rgba[0], max - rgba[1], max - rgba[2], rgba[3]]);
887 }
888}
889
890impl<T: Primitive> Invert for Rgb<T> {
891 fn invert(&mut self) {
892 let rgb = self.0;
893
894 let max = T::DEFAULT_MAX_VALUE;
895
896 let r1 = max - rgb[0];
897 let g1 = max - rgb[1];
898 let b1 = max - rgb[2];
899
900 *self = Rgb([r1, g1, b1]);
901 }
902}
903
904#[cfg(test)]
905mod tests {
906 use super::{Luma, LumaA, Pixel, Rgb, Rgba};
907
908 #[test]
909 fn test_apply_with_alpha_rgba() {
910 let mut rgba = Rgba([0, 0, 0, 0]);
911 rgba.apply_with_alpha(|s| s, |_| 0xFF);
912 assert_eq!(rgba, Rgba([0, 0, 0, 0xFF]));
913 }
914
915 #[test]
916 fn test_apply_with_alpha_rgb() {
917 let mut rgb = Rgb([0, 0, 0]);
918 rgb.apply_with_alpha(|s| s, |_| panic!("bug"));
919 assert_eq!(rgb, Rgb([0, 0, 0]));
920 }
921
922 #[test]
923 fn test_map_with_alpha_rgba() {
924 let rgba = Rgba([0, 0, 0, 0]).map_with_alpha(|s| s, |_| 0xFF);
925 assert_eq!(rgba, Rgba([0, 0, 0, 0xFF]));
926 }
927
928 #[test]
929 fn test_map_with_alpha_rgb() {
930 let rgb = Rgb([0, 0, 0]).map_with_alpha(|s| s, |_| panic!("bug"));
931 assert_eq!(rgb, Rgb([0, 0, 0]));
932 }
933
934 #[test]
935 fn test_blend_luma_alpha() {
936 let a = &mut LumaA([255_u8, 255]);
937 let b = LumaA([255_u8, 255]);
938 a.blend(&b);
939 assert_eq!(a.0[0], 255);
940 assert_eq!(a.0[1], 255);
941
942 let a = &mut LumaA([255_u8, 0]);
943 let b = LumaA([255_u8, 255]);
944 a.blend(&b);
945 assert_eq!(a.0[0], 255);
946 assert_eq!(a.0[1], 255);
947
948 let a = &mut LumaA([255_u8, 255]);
949 let b = LumaA([255_u8, 0]);
950 a.blend(&b);
951 assert_eq!(a.0[0], 255);
952 assert_eq!(a.0[1], 255);
953
954 let a = &mut LumaA([255_u8, 0]);
955 let b = LumaA([255_u8, 0]);
956 a.blend(&b);
957 assert_eq!(a.0[0], 255);
958 assert_eq!(a.0[1], 0);
959 }
960
961 #[test]
962 fn test_blend_rgba() {
963 let a = &mut Rgba([255_u8, 255, 255, 255]);
964 let b = Rgba([255_u8, 255, 255, 255]);
965 a.blend(&b);
966 assert_eq!(a.0, [255, 255, 255, 255]);
967
968 let a = &mut Rgba([255_u8, 255, 255, 0]);
969 let b = Rgba([255_u8, 255, 255, 255]);
970 a.blend(&b);
971 assert_eq!(a.0, [255, 255, 255, 255]);
972
973 let a = &mut Rgba([255_u8, 255, 255, 255]);
974 let b = Rgba([255_u8, 255, 255, 0]);
975 a.blend(&b);
976 assert_eq!(a.0, [255, 255, 255, 255]);
977
978 let a = &mut Rgba([255_u8, 255, 255, 0]);
979 let b = Rgba([255_u8, 255, 255, 0]);
980 a.blend(&b);
981 assert_eq!(a.0, [255, 255, 255, 0]);
982 }
983
984 #[test]
985 fn test_apply_without_alpha_rgba() {
986 let mut rgba = Rgba([0, 0, 0, 0]);
987 rgba.apply_without_alpha(|s| s + 1);
988 assert_eq!(rgba, Rgba([1, 1, 1, 0]));
989 }
990
991 #[test]
992 fn test_apply_without_alpha_rgb() {
993 let mut rgb = Rgb([0, 0, 0]);
994 rgb.apply_without_alpha(|s| s + 1);
995 assert_eq!(rgb, Rgb([1, 1, 1]));
996 }
997
998 #[test]
999 fn test_map_without_alpha_rgba() {
1000 let rgba = Rgba([0, 0, 0, 0]).map_without_alpha(|s| s + 1);
1001 assert_eq!(rgba, Rgba([1, 1, 1, 0]));
1002 }
1003
1004 #[test]
1005 fn test_map_without_alpha_rgb() {
1006 let rgb = Rgb([0, 0, 0]).map_without_alpha(|s| s + 1);
1007 assert_eq!(rgb, Rgb([1, 1, 1]));
1008 }
1009
1010 macro_rules! test_lossless_conversion {
1011 ($a:ty, $b:ty, $c:ty) => {
1012 let a: $a = [<$a as Pixel>::Subpixel::DEFAULT_MAX_VALUE >> 2;
1013 <$a as Pixel>::CHANNEL_COUNT as usize]
1014 .into();
1015 let b: $b = a.into_color();
1016 let c: $c = b.into_color();
1017 assert_eq!(a.channels(), c.channels());
1018 };
1019 }
1020
1021 #[test]
1022 fn test_lossless_conversions() {
1023 use super::IntoColor;
1024 use crate::traits::Primitive;
1025
1026 test_lossless_conversion!(Luma<u8>, Luma<u16>, Luma<u8>);
1027 test_lossless_conversion!(LumaA<u8>, LumaA<u16>, LumaA<u8>);
1028 test_lossless_conversion!(Rgb<u8>, Rgb<u16>, Rgb<u8>);
1029 test_lossless_conversion!(Rgba<u8>, Rgba<u16>, Rgba<u8>);
1030 }
1031
1032 #[test]
1033 fn accuracy_conversion() {
1034 use super::{Luma, Pixel, Rgb};
1035 let pixel = Rgb::from([13, 13, 13]);
1036 let Luma([luma]) = pixel.to_luma();
1037 assert_eq!(luma, 13);
1038 }
1039}