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 #[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 /// Returns if there is an alpha channel.
52 #[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 /// Returns false if the color scheme is grayscale, true otherwise.
62 #[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 /// Returns the number of bits contained in a pixel of `ColorType` ```c``` (which will always be
72 /// a multiple of 8).
73 #[must_use]
74 pub fn bits_per_pixel(self) -> u16 {
75 <u16 as From<u8>>::from(self.bytes_per_pixel()) * 8
76 }
77
78 /// Returns the number of color channels that make up this pixel
79 #[must_use]
80 pub fn channel_count(self) -> u8 {
81 let e: ExtendedColorType = self.into();
82 e.channel_count()
83 }
84}
85
86/// An enumeration of color types encountered in image formats.
87///
88/// This is not exhaustive over all existing image formats but should be granular enough to allow
89/// round tripping of decoding and encoding as much as possible. The variants will be extended as
90/// necessary to enable this.
91///
92/// Another purpose is to advise users of a rough estimate of the accuracy and effort of the
93/// decoding from and encoding to such an image format.
94#[derive(Copy, PartialEq, Eq, Debug, Clone, Hash)]
95#[non_exhaustive]
96pub enum ExtendedColorType {
97 /// Pixel is 8-bit alpha
98 A8,
99 /// Pixel is 1-bit luminance
100 L1,
101 /// Pixel is 1-bit luminance with an alpha channel
102 La1,
103 /// Pixel contains 1-bit R, G and B channels
104 Rgb1,
105 /// Pixel is 1-bit RGB with an alpha channel
106 Rgba1,
107 /// Pixel is 2-bit luminance
108 L2,
109 /// Pixel is 2-bit luminance with an alpha channel
110 La2,
111 /// Pixel contains 2-bit R, G and B channels
112 Rgb2,
113 /// Pixel is 2-bit RGB with an alpha channel
114 Rgba2,
115 /// Pixel is 4-bit luminance
116 L4,
117 /// Pixel is 4-bit luminance with an alpha channel
118 La4,
119 /// Pixel contains 4-bit R, G and B channels
120 Rgb4,
121 /// Pixel is 4-bit RGB with an alpha channel
122 Rgba4,
123 /// Pixel is 8-bit luminance
124 L8,
125 /// Pixel is 8-bit luminance with an alpha channel
126 La8,
127 /// Pixel contains 8-bit R, G and B channels
128 Rgb8,
129 /// Pixel is 8-bit RGB with an alpha channel
130 Rgba8,
131 /// Pixel is 16-bit luminance
132 L16,
133 /// Pixel is 16-bit luminance with an alpha channel
134 La16,
135 /// Pixel contains 16-bit R, G and B channels
136 Rgb16,
137 /// Pixel is 16-bit RGB with an alpha channel
138 Rgba16,
139 /// Pixel contains 8-bit B, G and R channels
140 Bgr8,
141 /// Pixel is 8-bit BGR with an alpha channel
142 Bgra8,
143
144 // TODO f16 types?
145 /// Pixel is 32-bit float RGB
146 Rgb32F,
147 /// Pixel is 32-bit float RGBA
148 Rgba32F,
149
150 /// Pixel is 8-bit CMYK
151 Cmyk8,
152
153 /// Pixel is of unknown color type with the specified bits per pixel. This can apply to pixels
154 /// which are associated with an external palette. In that case, the pixel value is an index
155 /// into the palette.
156 Unknown(u8),
157}
158
159impl ExtendedColorType {
160 /// Get the number of channels for colors of this type.
161 ///
162 /// Note that the `Unknown` variant returns a value of `1` since pixels can only be treated as
163 /// an opaque datum by the library.
164 #[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 /// Returns the number of bits per pixel for this color type.
198 #[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 /// Returns the number of bytes required to hold a width x height image of this color type.
232 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$( // START Structure definitions
263
264$(#[$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 // The branch of this match is `const`. This way ensures that no subexpression fails the
356 // `const_err` lint (the expression `self.0[ALPHA]` would).
357 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)* // END Structure definitions
405
406 }
407}
408
409define_colors! {
410 /// RGB colors.
411 ///
412 /// For the purpose of color conversion, as well as blending, the implementation of `Pixel`
413 /// assumes an `sRGB` color space of its data.
414 pub struct Rgb<T: Primitive Enlargeable>([T; 3, 0]) = "RGB";
415 /// Grayscale colors.
416 pub struct Luma<T: Primitive>([T; 1, 0]) = "Y";
417 /// RGB colors + alpha channel
418 pub struct Rgba<T: Primitive Enlargeable>([T; 4, 1]) = "RGBA";
419 /// Grayscale colors + alpha channel
420 pub struct LumaA<T: Primitive>([T; 2, 1]) = "YA";
421}
422
423/// Convert from one pixel component type to another. For example, convert from `u8` to `f32` pixel values.
424pub trait FromPrimitive<Component> {
425 /// Converts from any pixel component type to this type.
426 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// from f32:
436// Note that in to-integer-conversion we are performing rounding but NumCast::from is implemented
437// as truncate towards zero. We emulate rounding by adding a bias.
438
439// All other special values are clamped inbetween 0.0 and 1.0 (infinities and subnormals)
440// NaN however always maps to NaN therefore we have to force it towards some value.
441// 1.0 (white) was picked as firefox and chrome choose to map NaN to that.
442#[inline]
443fn normalize_float(float: f32, max: f32) -> f32 {
444 #[allow(clippy::neg_cmp_op_on_partial_ord)]
445 let clamped: f32 = 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
461// from u16:
462
463impl FromPrimitive<u16> for u8 {
464 fn from_primitive(c16: u16) -> Self {
465 fn from(c: impl Into<u32>) -> u32 {
466 c.into()
467 }
468 // The input c is the numerator of `c / u16::MAX`.
469 // Derive numerator of `num / u8::MAX`, with rounding.
470 //
471 // This method is based on the inverse (see FromPrimitive<u8> for u16) and was tested
472 // exhaustively in Python. It's the same as the reference function:
473 // round(c * (2**8 - 1) / (2**16 - 1))
474 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(min:0.0, max:1.0)
481 }
482}
483
484// from u8:
485
486impl FromPrimitive<u8> for f32 {
487 fn from_primitive(int: u8) -> Self {
488 (int as f32 / u8::MAX as f32).clamp(min:0.0, max:1.0)
489 }
490}
491
492impl FromPrimitive<u8> for u16 {
493 fn from_primitive(c8: u8) -> Self {
494 let x: u64 = c8.to_u64().unwrap();
495 NumCast::from((x << 8) | x).unwrap()
496 }
497}
498
499/// Provides color conversions for the different pixel types.
500pub trait FromColor<Other> {
501 /// Changes `self` to represent `Other` in the color space of `Self`
502 #[allow(clippy::wrong_self_convention)]
503 fn from_color(&mut self, _: &Other);
504}
505
506/// Copy-based conversions to target pixel types using `FromColor`.
507// FIXME: this trait should be removed and replaced with real color space models
508// rather than assuming sRGB.
509pub(crate) trait IntoColor<Other> {
510 /// Constructs a pixel of the target type and converts this pixel into it.
511 #[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 // Note we cannot use Pixel::CHANNELS_COUNT here to directly construct
522 // the pixel due to a current bug/limitation of consts.
523 #[allow(deprecated)]
524 let mut pix: O = O::from_channels(a:Zero::zero(), b:Zero::zero(), c:Zero::zero(), d:Zero::zero());
525 pix.from_color(self);
526 pix
527 }
528}
529
530/// Coefficients to transform from sRGB to a CIE Y (luminance) value.
531const 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: ::Larger = <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
542// `FromColor` for Luma
543impl<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: &mut [T] = self.channels_mut();
549 let other: &[S] = other.channels();
550 own[0] = T::from_primitive(component: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(component: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: &mut [T] = self.channels_mut();
569 let rgb: &[S] = other.channels();
570 gray[0] = T::from_primitive(component: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: &mut [T] = self.channels_mut();
580 let rgb: &[S] = other.channels();
581 let l: S = rgb_to_luma(rgb);
582 gray[0] = T::from_primitive(component:l);
583 }
584}
585
586// `FromColor` for LumaA
587
588impl<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: &mut [T] = self.channels_mut();
594 let other: &[S] = other.channels();
595 own[0] = T::from_primitive(component:other[0]);
596 own[1] = T::from_primitive(component: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: &mut [T] = self.channels_mut();
606 let rgb: &[S] = other.channels();
607 gray_a[0] = T::from_primitive(component: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: &mut [T] = self.channels_mut();
618 let rgba: &[S] = other.channels();
619 gray_a[0] = T::from_primitive(component:rgb_to_luma(rgb:rgba));
620 gray_a[1] = T::from_primitive(component: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: &mut [T] = self.channels_mut();
630 gray_a[0] = T::from_primitive(component:other.channels()[0]);
631 gray_a[1] = T::DEFAULT_MAX_VALUE;
632 }
633}
634
635// `FromColor` for RGBA
636
637impl<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 [T; 4] = &mut self.0;
643 let other: &[S; 4] = &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 own[3] = T::from_primitive(component: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 [T; 4] = &mut self.0;
657 let rgb: &[S; 3] = &other.0;
658 rgba[0] = T::from_primitive(component:rgb[0]);
659 rgba[1] = T::from_primitive(component:rgb[1]);
660 rgba[2] = T::from_primitive(component: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 [T; 4] = &mut self.0;
671 let gray: &[S; 2] = &gray.0;
672 rgba[0] = T::from_primitive(component:gray[0]);
673 rgba[1] = T::from_primitive(component:gray[0]);
674 rgba[2] = T::from_primitive(component:gray[0]);
675 rgba[3] = T::from_primitive(component: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 [T; 4] = &mut self.0;
685 let gray: S = gray.0[0];
686 rgba[0] = T::from_primitive(component:gray);
687 rgba[1] = T::from_primitive(component:gray);
688 rgba[2] = T::from_primitive(component:gray);
689 rgba[3] = T::DEFAULT_MAX_VALUE;
690 }
691}
692
693// `FromColor` for RGB
694
695impl<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 [T; 3] = &mut self.0;
701 let other: &[S; 3] = &other.0;
702 own[0] = T::from_primitive(component:other[0]);
703 own[1] = T::from_primitive(component:other[1]);
704 own[2] = T::from_primitive(component: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 [T; 3] = &mut self.0;
714 let rgba: &[S; 4] = &other.0;
715 rgb[0] = T::from_primitive(component:rgba[0]);
716 rgb[1] = T::from_primitive(component:rgba[1]);
717 rgb[2] = T::from_primitive(component: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 [T; 3] = &mut self.0;
727 let gray: S = other.0[0];
728 rgb[0] = T::from_primitive(component:gray);
729 rgb[1] = T::from_primitive(component:gray);
730 rgb[2] = T::from_primitive(component: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 [T; 3] = &mut self.0;
740 let gray: S = other.0[0];
741 rgb[0] = T::from_primitive(component:gray);
742 rgb[1] = T::from_primitive(component:gray);
743 rgb[2] = T::from_primitive(component:gray);
744 }
745}
746
747/// Blends a color inter another one
748pub(crate) trait Blend {
749 /// Blends a color in-place.
750 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 // http://stackoverflow.com/questions/7438263/alpha-compositing-algorithm-blend-modes#answer-11163848
795
796 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 // First, as we don't know what type our pixel is, we have to convert to floats between 0.0 and 1.0
805 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 // Work out what the final alpha level will be
823 let alpha_final = bg_a + fg_a - bg_a * fg_a;
824 if alpha_final == 0.0 {
825 return;
826 };
827
828 // We premultiply our channels by their alpha, as this makes it easier to calculate
829 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 // Standard formula for src-over alpha compositing
833 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 // Unmultiply the channels by our resultant alpha channel
840 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 // Cast back to our initial type on return
847 *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
862/// Invert a color
863pub(crate) trait Invert {
864 /// Inverts a color in-place.
865 fn invert(&mut self);
866}
867
868impl<T: Primitive> Invert for LumaA<T> {
869 fn invert(&mut self) {
870 let l: [T; 2] = self.0;
871 let max: T = 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: [T; 1] = self.0;
880
881 let max: T = T::DEFAULT_MAX_VALUE;
882 let l1: T = 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: [T; 4] = self.0;
891
892 let max: T = 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: [T; 3] = self.0;
901
902 let max: T = T::DEFAULT_MAX_VALUE;
903
904 let r1: T = max - rgb[0];
905 let g1: T = max - rgb[1];
906 let b1: T = 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}
1048