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