1use std::ops::{Index, IndexMut};
2
3use num_traits::{NumCast, ToPrimitive, Zero};
4
5use crate::traits::{Enlargeable, Pixel, Primitive};
6
7/// An enumeration over supported color types and bit depths
8#[derive(Copy, PartialEq, Eq, Debug, Clone, Hash)]
9#[non_exhaustive]
10pub enum ColorType {
11 /// Pixel is 8-bit luminance
12 L8,
13 /// Pixel is 8-bit luminance with an alpha channel
14 La8,
15 /// Pixel contains 8-bit R, G and B channels
16 Rgb8,
17 /// Pixel is 8-bit RGB with an alpha channel
18 Rgba8,
19
20 /// Pixel is 16-bit luminance
21 L16,
22 /// Pixel is 16-bit luminance with an alpha channel
23 La16,
24 /// Pixel is 16-bit RGB
25 Rgb16,
26 /// Pixel is 16-bit RGBA
27 Rgba16,
28
29 /// Pixel is 32-bit float RGB
30 Rgb32F,
31 /// Pixel is 32-bit float RGBA
32 Rgba32F,
33}
34
35impl ColorType {
36 /// Returns the number of bytes contained in a pixel of `ColorType` ```c```
37 pub fn bytes_per_pixel(self) -> u8 {
38 match self {
39 ColorType::L8 => 1,
40 ColorType::L16 | ColorType::La8 => 2,
41 ColorType::Rgb8 => 3,
42 ColorType::Rgba8 | ColorType::La16 => 4,
43 ColorType::Rgb16 => 6,
44 ColorType::Rgba16 => 8,
45 ColorType::Rgb32F => 3 * 4,
46 ColorType::Rgba32F => 4 * 4,
47 }
48 }
49
50 /// Returns if there is an alpha channel.
51 pub fn has_alpha(self) -> bool {
52 use ColorType::*;
53 match self {
54 L8 | L16 | Rgb8 | Rgb16 | Rgb32F => false,
55 La8 | Rgba8 | La16 | Rgba16 | Rgba32F => true,
56 }
57 }
58
59 /// Returns false if the color scheme is grayscale, true otherwise.
60 pub fn has_color(self) -> bool {
61 use ColorType::*;
62 match self {
63 L8 | L16 | La8 | La16 => false,
64 Rgb8 | Rgb16 | Rgba8 | Rgba16 | Rgb32F | Rgba32F => true,
65 }
66 }
67
68 /// Returns the number of bits contained in a pixel of `ColorType` ```c``` (which will always be
69 /// a multiple of 8).
70 pub fn bits_per_pixel(self) -> u16 {
71 <u16 as From<u8>>::from(self.bytes_per_pixel()) * 8
72 }
73
74 /// Returns the number of color channels that make up this pixel
75 pub fn channel_count(self) -> u8 {
76 let e: ExtendedColorType = self.into();
77 e.channel_count()
78 }
79}
80
81/// An enumeration of color types encountered in image formats.
82///
83/// This is not exhaustive over all existing image formats but should be granular enough to allow
84/// round tripping of decoding and encoding as much as possible. The variants will be extended as
85/// necessary to enable this.
86///
87/// Another purpose is to advise users of a rough estimate of the accuracy and effort of the
88/// decoding from and encoding to such an image format.
89#[derive(Copy, PartialEq, Eq, Debug, Clone, Hash)]
90#[non_exhaustive]
91pub enum ExtendedColorType {
92 /// Pixel is 8-bit alpha
93 A8,
94 /// Pixel is 1-bit luminance
95 L1,
96 /// Pixel is 1-bit luminance with an alpha channel
97 La1,
98 /// Pixel contains 1-bit R, G and B channels
99 Rgb1,
100 /// Pixel is 1-bit RGB with an alpha channel
101 Rgba1,
102 /// Pixel is 2-bit luminance
103 L2,
104 /// Pixel is 2-bit luminance with an alpha channel
105 La2,
106 /// Pixel contains 2-bit R, G and B channels
107 Rgb2,
108 /// Pixel is 2-bit RGB with an alpha channel
109 Rgba2,
110 /// Pixel is 4-bit luminance
111 L4,
112 /// Pixel is 4-bit luminance with an alpha channel
113 La4,
114 /// Pixel contains 4-bit R, G and B channels
115 Rgb4,
116 /// Pixel is 4-bit RGB with an alpha channel
117 Rgba4,
118 /// Pixel is 8-bit luminance
119 L8,
120 /// Pixel is 8-bit luminance with an alpha channel
121 La8,
122 /// Pixel contains 8-bit R, G and B channels
123 Rgb8,
124 /// Pixel is 8-bit RGB with an alpha channel
125 Rgba8,
126 /// Pixel is 16-bit luminance
127 L16,
128 /// Pixel is 16-bit luminance with an alpha channel
129 La16,
130 /// Pixel contains 16-bit R, G and B channels
131 Rgb16,
132 /// Pixel is 16-bit RGB with an alpha channel
133 Rgba16,
134 /// Pixel contains 8-bit B, G and R channels
135 Bgr8,
136 /// Pixel is 8-bit BGR with an alpha channel
137 Bgra8,
138
139 // TODO f16 types?
140 /// Pixel is 32-bit float RGB
141 Rgb32F,
142 /// Pixel is 32-bit float RGBA
143 Rgba32F,
144
145 /// Pixel is 8-bit CMYK
146 Cmyk8,
147
148 /// Pixel is of unknown color type with the specified bits per pixel. This can apply to pixels
149 /// which are associated with an external palette. In that case, the pixel value is an index
150 /// into the palette.
151 Unknown(u8),
152}
153
154impl ExtendedColorType {
155 /// Get the number of channels for colors of this type.
156 ///
157 /// Note that the `Unknown` variant returns a value of `1` since pixels can only be treated as
158 /// an opaque datum by the library.
159 pub fn channel_count(self) -> u8 {
160 match self {
161 ExtendedColorType::A8
162 | ExtendedColorType::L1
163 | ExtendedColorType::L2
164 | ExtendedColorType::L4
165 | ExtendedColorType::L8
166 | ExtendedColorType::L16
167 | ExtendedColorType::Unknown(_) => 1,
168 ExtendedColorType::La1
169 | ExtendedColorType::La2
170 | ExtendedColorType::La4
171 | ExtendedColorType::La8
172 | ExtendedColorType::La16 => 2,
173 ExtendedColorType::Rgb1
174 | ExtendedColorType::Rgb2
175 | ExtendedColorType::Rgb4
176 | ExtendedColorType::Rgb8
177 | ExtendedColorType::Rgb16
178 | ExtendedColorType::Rgb32F
179 | ExtendedColorType::Bgr8 => 3,
180 ExtendedColorType::Rgba1
181 | ExtendedColorType::Rgba2
182 | ExtendedColorType::Rgba4
183 | ExtendedColorType::Rgba8
184 | ExtendedColorType::Rgba16
185 | ExtendedColorType::Rgba32F
186 | ExtendedColorType::Bgra8
187 | ExtendedColorType::Cmyk8 => 4,
188 }
189 }
190}
191impl From<ColorType> for ExtendedColorType {
192 fn from(c: ColorType) -> Self {
193 match c {
194 ColorType::L8 => ExtendedColorType::L8,
195 ColorType::La8 => ExtendedColorType::La8,
196 ColorType::Rgb8 => ExtendedColorType::Rgb8,
197 ColorType::Rgba8 => ExtendedColorType::Rgba8,
198 ColorType::L16 => ExtendedColorType::L16,
199 ColorType::La16 => ExtendedColorType::La16,
200 ColorType::Rgb16 => ExtendedColorType::Rgb16,
201 ColorType::Rgba16 => ExtendedColorType::Rgba16,
202 ColorType::Rgb32F => ExtendedColorType::Rgb32F,
203 ColorType::Rgba32F => ExtendedColorType::Rgba32F,
204 }
205 }
206}
207
208macro_rules! define_colors {
209 {$(
210 $(#[$doc:meta])*
211 pub struct $ident:ident<T: $($bound:ident)*>([T; $channels:expr, $alphas:expr])
212 = $interpretation:literal;
213 )*} => {
214
215$( // START Structure definitions
216
217$(#[$doc])*
218#[derive(PartialEq, Eq, Clone, Debug, Copy, Hash)]
219#[repr(C)]
220#[allow(missing_docs)]
221pub struct $ident<T> (pub [T; $channels]);
222
223impl<T: $($bound+)*> Pixel for $ident<T> {
224 type Subpixel = T;
225
226 const CHANNEL_COUNT: u8 = $channels;
227
228 #[inline(always)]
229 fn channels(&self) -> &[T] {
230 &self.0
231 }
232
233 #[inline(always)]
234 fn channels_mut(&mut self) -> &mut [T] {
235 &mut self.0
236 }
237
238 const COLOR_MODEL: &'static str = $interpretation;
239
240 fn channels4(&self) -> (T, T, T, T) {
241 const CHANNELS: usize = $channels;
242 let mut channels = [T::DEFAULT_MAX_VALUE; 4];
243 channels[0..CHANNELS].copy_from_slice(&self.0);
244 (channels[0], channels[1], channels[2], channels[3])
245 }
246
247 fn from_channels(a: T, b: T, c: T, d: T,) -> $ident<T> {
248 const CHANNELS: usize = $channels;
249 *<$ident<T> as Pixel>::from_slice(&[a, b, c, d][..CHANNELS])
250 }
251
252 fn from_slice(slice: &[T]) -> &$ident<T> {
253 assert_eq!(slice.len(), $channels);
254 unsafe { &*(slice.as_ptr() as *const $ident<T>) }
255 }
256 fn from_slice_mut(slice: &mut [T]) -> &mut $ident<T> {
257 assert_eq!(slice.len(), $channels);
258 unsafe { &mut *(slice.as_mut_ptr() as *mut $ident<T>) }
259 }
260
261 fn to_rgb(&self) -> Rgb<T> {
262 let mut pix = Rgb([Zero::zero(), Zero::zero(), Zero::zero()]);
263 pix.from_color(self);
264 pix
265 }
266
267 fn to_rgba(&self) -> Rgba<T> {
268 let mut pix = Rgba([Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero()]);
269 pix.from_color(self);
270 pix
271 }
272
273 fn to_luma(&self) -> Luma<T> {
274 let mut pix = Luma([Zero::zero()]);
275 pix.from_color(self);
276 pix
277 }
278
279 fn to_luma_alpha(&self) -> LumaA<T> {
280 let mut pix = LumaA([Zero::zero(), Zero::zero()]);
281 pix.from_color(self);
282 pix
283 }
284
285 fn map<F>(& self, f: F) -> $ident<T> where F: FnMut(T) -> T {
286 let mut this = (*self).clone();
287 this.apply(f);
288 this
289 }
290
291 fn apply<F>(&mut self, mut f: F) where F: FnMut(T) -> T {
292 for v in &mut self.0 {
293 *v = f(*v)
294 }
295 }
296
297 fn map_with_alpha<F, G>(&self, f: F, g: G) -> $ident<T> where F: FnMut(T) -> T, G: FnMut(T) -> T {
298 let mut this = (*self).clone();
299 this.apply_with_alpha(f, g);
300 this
301 }
302
303 fn apply_with_alpha<F, G>(&mut self, mut f: F, mut g: G) where F: FnMut(T) -> T, G: FnMut(T) -> T {
304 const ALPHA: usize = $channels - $alphas;
305 for v in self.0[..ALPHA].iter_mut() {
306 *v = f(*v)
307 }
308 // The branch of this match is `const`. This way ensures that no subexpression fails the
309 // `const_err` lint (the expression `self.0[ALPHA]` would).
310 if let Some(v) = self.0.get_mut(ALPHA) {
311 *v = g(*v)
312 }
313 }
314
315 fn map2<F>(&self, other: &Self, f: F) -> $ident<T> where F: FnMut(T, T) -> T {
316 let mut this = (*self).clone();
317 this.apply2(other, f);
318 this
319 }
320
321 fn apply2<F>(&mut self, other: &$ident<T>, mut f: F) where F: FnMut(T, T) -> T {
322 for (a, &b) in self.0.iter_mut().zip(other.0.iter()) {
323 *a = f(*a, b)
324 }
325 }
326
327 fn invert(&mut self) {
328 Invert::invert(self)
329 }
330
331 fn blend(&mut self, other: &$ident<T>) {
332 Blend::blend(self, other)
333 }
334}
335
336impl<T> Index<usize> for $ident<T> {
337 type Output = T;
338 #[inline(always)]
339 fn index(&self, _index: usize) -> &T {
340 &self.0[_index]
341 }
342}
343
344impl<T> IndexMut<usize> for $ident<T> {
345 #[inline(always)]
346 fn index_mut(&mut self, _index: usize) -> &mut T {
347 &mut self.0[_index]
348 }
349}
350
351impl<T> From<[T; $channels]> for $ident<T> {
352 fn from(c: [T; $channels]) -> Self {
353 Self(c)
354 }
355}
356
357)* // END Structure definitions
358
359 }
360}
361
362define_colors! {
363 /// RGB colors.
364 ///
365 /// For the purpose of color conversion, as well as blending, the implementation of `Pixel`
366 /// assumes an `sRGB` color space of its data.
367 pub struct Rgb<T: Primitive Enlargeable>([T; 3, 0]) = "RGB";
368 /// Grayscale colors.
369 pub struct Luma<T: Primitive>([T; 1, 0]) = "Y";
370 /// RGB colors + alpha channel
371 pub struct Rgba<T: Primitive Enlargeable>([T; 4, 1]) = "RGBA";
372 /// Grayscale colors + alpha channel
373 pub struct LumaA<T: Primitive>([T; 2, 1]) = "YA";
374}
375
376/// Convert from one pixel component type to another. For example, convert from `u8` to `f32` pixel values.
377pub trait FromPrimitive<Component> {
378 /// Converts from any pixel component type to this type.
379 fn from_primitive(component: Component) -> Self;
380}
381
382impl<T: Primitive> FromPrimitive<T> for T {
383 fn from_primitive(sample: T) -> Self {
384 sample
385 }
386}
387
388// from f32:
389// Note that in to-integer-conversion we are performing rounding but NumCast::from is implemented
390// as truncate towards zero. We emulate rounding by adding a bias.
391
392impl FromPrimitive<f32> for u8 {
393 fn from_primitive(float: f32) -> Self {
394 let inner: f32 = (float.clamp(min:0.0, max:1.0) * u8::MAX as f32).round();
395 NumCast::from(inner).unwrap()
396 }
397}
398
399impl FromPrimitive<f32> for u16 {
400 fn from_primitive(float: f32) -> Self {
401 let inner: f32 = (float.clamp(min:0.0, max:1.0) * u16::MAX as f32).round();
402 NumCast::from(inner).unwrap()
403 }
404}
405
406// from u16:
407
408impl FromPrimitive<u16> for u8 {
409 fn from_primitive(c16: u16) -> Self {
410 fn from(c: impl Into<u32>) -> u32 {
411 c.into()
412 }
413 // The input c is the numerator of `c / u16::MAX`.
414 // Derive numerator of `num / u8::MAX`, with rounding.
415 //
416 // This method is based on the inverse (see FromPrimitive<u8> for u16) and was tested
417 // exhaustively in Python. It's the same as the reference function:
418 // round(c * (2**8 - 1) / (2**16 - 1))
419 NumCast::from((from(c16) + 128) / 257).unwrap()
420 }
421}
422
423impl FromPrimitive<u16> for f32 {
424 fn from_primitive(int: u16) -> Self {
425 (int as f32 / u16::MAX as f32).clamp(min:0.0, max:1.0)
426 }
427}
428
429// from u8:
430
431impl FromPrimitive<u8> for f32 {
432 fn from_primitive(int: u8) -> Self {
433 (int as f32 / u8::MAX as f32).clamp(min:0.0, max:1.0)
434 }
435}
436
437impl FromPrimitive<u8> for u16 {
438 fn from_primitive(c8: u8) -> Self {
439 let x: u64 = c8.to_u64().unwrap();
440 NumCast::from((x << 8) | x).unwrap()
441 }
442}
443
444/// Provides color conversions for the different pixel types.
445pub trait FromColor<Other> {
446 /// Changes `self` to represent `Other` in the color space of `Self`
447 fn from_color(&mut self, _: &Other);
448}
449
450/// Copy-based conversions to target pixel types using `FromColor`.
451// FIXME: this trait should be removed and replaced with real color space models
452// rather than assuming sRGB.
453pub(crate) trait IntoColor<Other> {
454 /// Constructs a pixel of the target type and converts this pixel into it.
455 fn into_color(&self) -> Other;
456}
457
458impl<O, S> IntoColor<O> for S
459where
460 O: Pixel + FromColor<S>,
461{
462 fn into_color(&self) -> O {
463 // Note we cannot use Pixel::CHANNELS_COUNT here to directly construct
464 // the pixel due to a current bug/limitation of consts.
465 #[allow(deprecated)]
466 let mut pix: O = O::from_channels(a:Zero::zero(), b:Zero::zero(), c:Zero::zero(), d:Zero::zero());
467 pix.from_color(self);
468 pix
469 }
470}
471
472/// Coefficients to transform from sRGB to a CIE Y (luminance) value.
473const SRGB_LUMA: [u32; 3] = [2126, 7152, 722];
474const SRGB_LUMA_DIV: u32 = 10000;
475
476#[inline]
477fn rgb_to_luma<T: Primitive + Enlargeable>(rgb: &[T]) -> T {
478 let l: ::Larger = <T::Larger as NumCast>::from(SRGB_LUMA[0]).unwrap() * rgb[0].to_larger()
479 + <T::Larger as NumCast>::from(SRGB_LUMA[1]).unwrap() * rgb[1].to_larger()
480 + <T::Larger as NumCast>::from(SRGB_LUMA[2]).unwrap() * rgb[2].to_larger();
481 T::clamp_from(l / <T::Larger as NumCast>::from(SRGB_LUMA_DIV).unwrap())
482}
483
484// `FromColor` for Luma
485impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for Luma<T>
486where
487 T: FromPrimitive<S>,
488{
489 fn from_color(&mut self, other: &Luma<S>) {
490 let own: &mut [T] = self.channels_mut();
491 let other: &[S] = other.channels();
492 own[0] = T::from_primitive(component:other[0]);
493 }
494}
495
496impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for Luma<T>
497where
498 T: FromPrimitive<S>,
499{
500 fn from_color(&mut self, other: &LumaA<S>) {
501 self.channels_mut()[0] = T::from_primitive(component:other.channels()[0])
502 }
503}
504
505impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgb<S>> for Luma<T>
506where
507 T: FromPrimitive<S>,
508{
509 fn from_color(&mut self, other: &Rgb<S>) {
510 let gray: &mut [T] = self.channels_mut();
511 let rgb: &[S] = other.channels();
512 gray[0] = T::from_primitive(component:rgb_to_luma(rgb));
513 }
514}
515
516impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgba<S>> for Luma<T>
517where
518 T: FromPrimitive<S>,
519{
520 fn from_color(&mut self, other: &Rgba<S>) {
521 let gray: &mut [T] = self.channels_mut();
522 let rgb: &[S] = other.channels();
523 let l: S = rgb_to_luma(rgb);
524 gray[0] = T::from_primitive(component:l);
525 }
526}
527
528// `FromColor` for LumaA
529
530impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for LumaA<T>
531where
532 T: FromPrimitive<S>,
533{
534 fn from_color(&mut self, other: &LumaA<S>) {
535 let own: &mut [T] = self.channels_mut();
536 let other: &[S] = other.channels();
537 own[0] = T::from_primitive(component:other[0]);
538 own[1] = T::from_primitive(component:other[1]);
539 }
540}
541
542impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgb<S>> for LumaA<T>
543where
544 T: FromPrimitive<S>,
545{
546 fn from_color(&mut self, other: &Rgb<S>) {
547 let gray_a: &mut [T] = self.channels_mut();
548 let rgb: &[S] = other.channels();
549 gray_a[0] = T::from_primitive(component:rgb_to_luma(rgb));
550 gray_a[1] = T::DEFAULT_MAX_VALUE;
551 }
552}
553
554impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgba<S>> for LumaA<T>
555where
556 T: FromPrimitive<S>,
557{
558 fn from_color(&mut self, other: &Rgba<S>) {
559 let gray_a: &mut [T] = self.channels_mut();
560 let rgba: &[S] = other.channels();
561 gray_a[0] = T::from_primitive(component:rgb_to_luma(rgb:rgba));
562 gray_a[1] = T::from_primitive(component:rgba[3]);
563 }
564}
565
566impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for LumaA<T>
567where
568 T: FromPrimitive<S>,
569{
570 fn from_color(&mut self, other: &Luma<S>) {
571 let gray_a: &mut [T] = self.channels_mut();
572 gray_a[0] = T::from_primitive(component:other.channels()[0]);
573 gray_a[1] = T::DEFAULT_MAX_VALUE;
574 }
575}
576
577// `FromColor` for RGBA
578
579impl<S: Primitive, T: Primitive> FromColor<Rgba<S>> for Rgba<T>
580where
581 T: FromPrimitive<S>,
582{
583 fn from_color(&mut self, other: &Rgba<S>) {
584 let own: &mut [T; 4] = &mut self.0;
585 let other: &[S; 4] = &other.0;
586 own[0] = T::from_primitive(component:other[0]);
587 own[1] = T::from_primitive(component:other[1]);
588 own[2] = T::from_primitive(component:other[2]);
589 own[3] = T::from_primitive(component:other[3]);
590 }
591}
592
593impl<S: Primitive, T: Primitive> FromColor<Rgb<S>> for Rgba<T>
594where
595 T: FromPrimitive<S>,
596{
597 fn from_color(&mut self, other: &Rgb<S>) {
598 let rgba: &mut [T; 4] = &mut self.0;
599 let rgb: &[S; 3] = &other.0;
600 rgba[0] = T::from_primitive(component:rgb[0]);
601 rgba[1] = T::from_primitive(component:rgb[1]);
602 rgba[2] = T::from_primitive(component:rgb[2]);
603 rgba[3] = T::DEFAULT_MAX_VALUE;
604 }
605}
606
607impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for Rgba<T>
608where
609 T: FromPrimitive<S>,
610{
611 fn from_color(&mut self, gray: &LumaA<S>) {
612 let rgba: &mut [T; 4] = &mut self.0;
613 let gray: &[S; 2] = &gray.0;
614 rgba[0] = T::from_primitive(component:gray[0]);
615 rgba[1] = T::from_primitive(component:gray[0]);
616 rgba[2] = T::from_primitive(component:gray[0]);
617 rgba[3] = T::from_primitive(component:gray[1]);
618 }
619}
620
621impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for Rgba<T>
622where
623 T: FromPrimitive<S>,
624{
625 fn from_color(&mut self, gray: &Luma<S>) {
626 let rgba: &mut [T; 4] = &mut self.0;
627 let gray: S = gray.0[0];
628 rgba[0] = T::from_primitive(component:gray);
629 rgba[1] = T::from_primitive(component:gray);
630 rgba[2] = T::from_primitive(component:gray);
631 rgba[3] = T::DEFAULT_MAX_VALUE;
632 }
633}
634
635// `FromColor` for RGB
636
637impl<S: Primitive, T: Primitive> FromColor<Rgb<S>> for Rgb<T>
638where
639 T: FromPrimitive<S>,
640{
641 fn from_color(&mut self, other: &Rgb<S>) {
642 let own: &mut [T; 3] = &mut self.0;
643 let other: &[S; 3] = &other.0;
644 own[0] = T::from_primitive(component:other[0]);
645 own[1] = T::from_primitive(component:other[1]);
646 own[2] = T::from_primitive(component:other[2]);
647 }
648}
649
650impl<S: Primitive, T: Primitive> FromColor<Rgba<S>> for Rgb<T>
651where
652 T: FromPrimitive<S>,
653{
654 fn from_color(&mut self, other: &Rgba<S>) {
655 let rgb: &mut [T; 3] = &mut self.0;
656 let rgba: &[S; 4] = &other.0;
657 rgb[0] = T::from_primitive(component:rgba[0]);
658 rgb[1] = T::from_primitive(component:rgba[1]);
659 rgb[2] = T::from_primitive(component:rgba[2]);
660 }
661}
662
663impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for Rgb<T>
664where
665 T: FromPrimitive<S>,
666{
667 fn from_color(&mut self, other: &LumaA<S>) {
668 let rgb: &mut [T; 3] = &mut self.0;
669 let gray: S = other.0[0];
670 rgb[0] = T::from_primitive(component:gray);
671 rgb[1] = T::from_primitive(component:gray);
672 rgb[2] = T::from_primitive(component:gray);
673 }
674}
675
676impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for Rgb<T>
677where
678 T: FromPrimitive<S>,
679{
680 fn from_color(&mut self, other: &Luma<S>) {
681 let rgb: &mut [T; 3] = &mut self.0;
682 let gray: S = other.0[0];
683 rgb[0] = T::from_primitive(component:gray);
684 rgb[1] = T::from_primitive(component:gray);
685 rgb[2] = T::from_primitive(component:gray);
686 }
687}
688
689/// Blends a color inter another one
690pub(crate) trait Blend {
691 /// Blends a color in-place.
692 fn blend(&mut self, other: &Self);
693}
694
695impl<T: Primitive> Blend for LumaA<T> {
696 fn blend(&mut self, other: &LumaA<T>) {
697 let max_t = T::DEFAULT_MAX_VALUE;
698 let max_t = max_t.to_f32().unwrap();
699 let (bg_luma, bg_a) = (self.0[0], self.0[1]);
700 let (fg_luma, fg_a) = (other.0[0], other.0[1]);
701
702 let (bg_luma, bg_a) = (
703 bg_luma.to_f32().unwrap() / max_t,
704 bg_a.to_f32().unwrap() / max_t,
705 );
706 let (fg_luma, fg_a) = (
707 fg_luma.to_f32().unwrap() / max_t,
708 fg_a.to_f32().unwrap() / max_t,
709 );
710
711 let alpha_final = bg_a + fg_a - bg_a * fg_a;
712 if alpha_final == 0.0 {
713 return;
714 };
715 let bg_luma_a = bg_luma * bg_a;
716 let fg_luma_a = fg_luma * fg_a;
717
718 let out_luma_a = fg_luma_a + bg_luma_a * (1.0 - fg_a);
719 let out_luma = out_luma_a / alpha_final;
720
721 *self = LumaA([
722 NumCast::from(max_t * out_luma).unwrap(),
723 NumCast::from(max_t * alpha_final).unwrap(),
724 ])
725 }
726}
727
728impl<T: Primitive> Blend for Luma<T> {
729 fn blend(&mut self, other: &Luma<T>) {
730 *self = *other
731 }
732}
733
734impl<T: Primitive> Blend for Rgba<T> {
735 fn blend(&mut self, other: &Rgba<T>) {
736 // http://stackoverflow.com/questions/7438263/alpha-compositing-algorithm-blend-modes#answer-11163848
737
738 if other.0[3].is_zero() {
739 return;
740 }
741 if other.0[3] == T::DEFAULT_MAX_VALUE {
742 *self = *other;
743 return;
744 }
745
746 // First, as we don't know what type our pixel is, we have to convert to floats between 0.0 and 1.0
747 let max_t = T::DEFAULT_MAX_VALUE;
748 let max_t = max_t.to_f32().unwrap();
749 let (bg_r, bg_g, bg_b, bg_a) = (self.0[0], self.0[1], self.0[2], self.0[3]);
750 let (fg_r, fg_g, fg_b, fg_a) = (other.0[0], other.0[1], other.0[2], other.0[3]);
751 let (bg_r, bg_g, bg_b, bg_a) = (
752 bg_r.to_f32().unwrap() / max_t,
753 bg_g.to_f32().unwrap() / max_t,
754 bg_b.to_f32().unwrap() / max_t,
755 bg_a.to_f32().unwrap() / max_t,
756 );
757 let (fg_r, fg_g, fg_b, fg_a) = (
758 fg_r.to_f32().unwrap() / max_t,
759 fg_g.to_f32().unwrap() / max_t,
760 fg_b.to_f32().unwrap() / max_t,
761 fg_a.to_f32().unwrap() / max_t,
762 );
763
764 // Work out what the final alpha level will be
765 let alpha_final = bg_a + fg_a - bg_a * fg_a;
766 if alpha_final == 0.0 {
767 return;
768 };
769
770 // We premultiply our channels by their alpha, as this makes it easier to calculate
771 let (bg_r_a, bg_g_a, bg_b_a) = (bg_r * bg_a, bg_g * bg_a, bg_b * bg_a);
772 let (fg_r_a, fg_g_a, fg_b_a) = (fg_r * fg_a, fg_g * fg_a, fg_b * fg_a);
773
774 // Standard formula for src-over alpha compositing
775 let (out_r_a, out_g_a, out_b_a) = (
776 fg_r_a + bg_r_a * (1.0 - fg_a),
777 fg_g_a + bg_g_a * (1.0 - fg_a),
778 fg_b_a + bg_b_a * (1.0 - fg_a),
779 );
780
781 // Unmultiply the channels by our resultant alpha channel
782 let (out_r, out_g, out_b) = (
783 out_r_a / alpha_final,
784 out_g_a / alpha_final,
785 out_b_a / alpha_final,
786 );
787
788 // Cast back to our initial type on return
789 *self = Rgba([
790 NumCast::from(max_t * out_r).unwrap(),
791 NumCast::from(max_t * out_g).unwrap(),
792 NumCast::from(max_t * out_b).unwrap(),
793 NumCast::from(max_t * alpha_final).unwrap(),
794 ])
795 }
796}
797
798impl<T: Primitive> Blend for Rgb<T> {
799 fn blend(&mut self, other: &Rgb<T>) {
800 *self = *other
801 }
802}
803
804/// Invert a color
805pub(crate) trait Invert {
806 /// Inverts a color in-place.
807 fn invert(&mut self);
808}
809
810impl<T: Primitive> Invert for LumaA<T> {
811 fn invert(&mut self) {
812 let l: [T; 2] = self.0;
813 let max: T = T::DEFAULT_MAX_VALUE;
814
815 *self = LumaA([max - l[0], l[1]])
816 }
817}
818
819impl<T: Primitive> Invert for Luma<T> {
820 fn invert(&mut self) {
821 let l: [T; 1] = self.0;
822
823 let max: T = T::DEFAULT_MAX_VALUE;
824 let l1: T = max - l[0];
825
826 *self = Luma([l1])
827 }
828}
829
830impl<T: Primitive> Invert for Rgba<T> {
831 fn invert(&mut self) {
832 let rgba: [T; 4] = self.0;
833
834 let max: T = T::DEFAULT_MAX_VALUE;
835
836 *self = Rgba([max - rgba[0], max - rgba[1], max - rgba[2], rgba[3]])
837 }
838}
839
840impl<T: Primitive> Invert for Rgb<T> {
841 fn invert(&mut self) {
842 let rgb: [T; 3] = self.0;
843
844 let max: T = T::DEFAULT_MAX_VALUE;
845
846 let r1: T = max - rgb[0];
847 let g1: T = max - rgb[1];
848 let b1: T = max - rgb[2];
849
850 *self = Rgb([r1, g1, b1])
851 }
852}
853
854#[cfg(test)]
855mod tests {
856 use super::{Luma, LumaA, Pixel, Rgb, Rgba};
857
858 #[test]
859 fn test_apply_with_alpha_rgba() {
860 let mut rgba = Rgba([0, 0, 0, 0]);
861 rgba.apply_with_alpha(|s| s, |_| 0xFF);
862 assert_eq!(rgba, Rgba([0, 0, 0, 0xFF]));
863 }
864
865 #[test]
866 fn test_apply_with_alpha_rgb() {
867 let mut rgb = Rgb([0, 0, 0]);
868 rgb.apply_with_alpha(|s| s, |_| panic!("bug"));
869 assert_eq!(rgb, Rgb([0, 0, 0]));
870 }
871
872 #[test]
873 fn test_map_with_alpha_rgba() {
874 let rgba = Rgba([0, 0, 0, 0]).map_with_alpha(|s| s, |_| 0xFF);
875 assert_eq!(rgba, Rgba([0, 0, 0, 0xFF]));
876 }
877
878 #[test]
879 fn test_map_with_alpha_rgb() {
880 let rgb = Rgb([0, 0, 0]).map_with_alpha(|s| s, |_| panic!("bug"));
881 assert_eq!(rgb, Rgb([0, 0, 0]));
882 }
883
884 #[test]
885 fn test_blend_luma_alpha() {
886 let a = &mut LumaA([255_u8, 255]);
887 let b = LumaA([255_u8, 255]);
888 a.blend(&b);
889 assert_eq!(a.0[0], 255);
890 assert_eq!(a.0[1], 255);
891
892 let a = &mut LumaA([255_u8, 0]);
893 let b = LumaA([255_u8, 255]);
894 a.blend(&b);
895 assert_eq!(a.0[0], 255);
896 assert_eq!(a.0[1], 255);
897
898 let a = &mut LumaA([255_u8, 255]);
899 let b = LumaA([255_u8, 0]);
900 a.blend(&b);
901 assert_eq!(a.0[0], 255);
902 assert_eq!(a.0[1], 255);
903
904 let a = &mut LumaA([255_u8, 0]);
905 let b = LumaA([255_u8, 0]);
906 a.blend(&b);
907 assert_eq!(a.0[0], 255);
908 assert_eq!(a.0[1], 0);
909 }
910
911 #[test]
912 fn test_blend_rgba() {
913 let a = &mut Rgba([255_u8, 255, 255, 255]);
914 let b = Rgba([255_u8, 255, 255, 255]);
915 a.blend(&b);
916 assert_eq!(a.0, [255, 255, 255, 255]);
917
918 let a = &mut Rgba([255_u8, 255, 255, 0]);
919 let b = Rgba([255_u8, 255, 255, 255]);
920 a.blend(&b);
921 assert_eq!(a.0, [255, 255, 255, 255]);
922
923 let a = &mut Rgba([255_u8, 255, 255, 255]);
924 let b = Rgba([255_u8, 255, 255, 0]);
925 a.blend(&b);
926 assert_eq!(a.0, [255, 255, 255, 255]);
927
928 let a = &mut Rgba([255_u8, 255, 255, 0]);
929 let b = Rgba([255_u8, 255, 255, 0]);
930 a.blend(&b);
931 assert_eq!(a.0, [255, 255, 255, 0]);
932 }
933
934 #[test]
935 fn test_apply_without_alpha_rgba() {
936 let mut rgba = Rgba([0, 0, 0, 0]);
937 rgba.apply_without_alpha(|s| s + 1);
938 assert_eq!(rgba, Rgba([1, 1, 1, 0]));
939 }
940
941 #[test]
942 fn test_apply_without_alpha_rgb() {
943 let mut rgb = Rgb([0, 0, 0]);
944 rgb.apply_without_alpha(|s| s + 1);
945 assert_eq!(rgb, Rgb([1, 1, 1]));
946 }
947
948 #[test]
949 fn test_map_without_alpha_rgba() {
950 let rgba = Rgba([0, 0, 0, 0]).map_without_alpha(|s| s + 1);
951 assert_eq!(rgba, Rgba([1, 1, 1, 0]));
952 }
953
954 #[test]
955 fn test_map_without_alpha_rgb() {
956 let rgb = Rgb([0, 0, 0]).map_without_alpha(|s| s + 1);
957 assert_eq!(rgb, Rgb([1, 1, 1]));
958 }
959
960 macro_rules! test_lossless_conversion {
961 ($a:ty, $b:ty, $c:ty) => {
962 let a: $a = [<$a as Pixel>::Subpixel::DEFAULT_MAX_VALUE >> 2;
963 <$a as Pixel>::CHANNEL_COUNT as usize]
964 .into();
965 let b: $b = a.into_color();
966 let c: $c = b.into_color();
967 assert_eq!(a.channels(), c.channels());
968 };
969 }
970
971 #[test]
972 fn test_lossless_conversions() {
973 use super::IntoColor;
974 use crate::traits::Primitive;
975
976 test_lossless_conversion!(Luma<u8>, Luma<u16>, Luma<u8>);
977 test_lossless_conversion!(LumaA<u8>, LumaA<u16>, LumaA<u8>);
978 test_lossless_conversion!(Rgb<u8>, Rgb<u16>, Rgb<u8>);
979 test_lossless_conversion!(Rgba<u8>, Rgba<u16>, Rgba<u8>);
980 }
981
982 #[test]
983 fn accuracy_conversion() {
984 use super::{Luma, Pixel, Rgb};
985 let pixel = Rgb::from([13, 13, 13]);
986 let Luma([luma]) = pixel.to_luma();
987 assert_eq!(luma, 13);
988 }
989}
990