1 | use std::ops::{Index, IndexMut}; |
2 | |
3 | use num_traits::{NumCast, ToPrimitive, Zero}; |
4 | |
5 | use 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 ] |
10 | pub 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 | |
35 | impl 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 ] |
96 | pub 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 | |
159 | impl 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 | } |
238 | impl 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 | |
255 | macro_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)] |
268 | pub struct $ident<T> (pub [T; $channels]); |
269 | |
270 | impl<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 | |
383 | impl<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 | |
391 | impl<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 | |
398 | impl<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 | |
409 | define_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. |
424 | pub trait FromPrimitive<Component> { |
425 | /// Converts from any pixel component type to this type. |
426 | fn from_primitive(component: Component) -> Self; |
427 | } |
428 | |
429 | impl<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 ] |
443 | fn 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 | |
449 | impl 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 | |
455 | impl 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 | |
463 | impl 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 | |
478 | impl 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 | |
486 | impl 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 | |
492 | impl 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. |
500 | pub 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. |
509 | pub(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 | |
515 | impl<O, S> IntoColor<O> for S |
516 | where |
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. |
531 | const SRGB_LUMA: [u32; 3] = [2126, 7152, 722]; |
532 | const SRGB_LUMA_DIV: u32 = 10000; |
533 | |
534 | #[inline ] |
535 | fn 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 |
543 | impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for Luma<T> |
544 | where |
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 | |
554 | impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for Luma<T> |
555 | where |
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 | |
563 | impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgb<S>> for Luma<T> |
564 | where |
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 | |
574 | impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgba<S>> for Luma<T> |
575 | where |
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 | |
588 | impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for LumaA<T> |
589 | where |
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 | |
600 | impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgb<S>> for LumaA<T> |
601 | where |
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 | |
612 | impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgba<S>> for LumaA<T> |
613 | where |
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 | |
624 | impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for LumaA<T> |
625 | where |
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 | |
637 | impl<S: Primitive, T: Primitive> FromColor<Rgba<S>> for Rgba<T> |
638 | where |
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 | |
651 | impl<S: Primitive, T: Primitive> FromColor<Rgb<S>> for Rgba<T> |
652 | where |
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 | |
665 | impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for Rgba<T> |
666 | where |
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 | |
679 | impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for Rgba<T> |
680 | where |
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 | |
695 | impl<S: Primitive, T: Primitive> FromColor<Rgb<S>> for Rgb<T> |
696 | where |
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 | |
708 | impl<S: Primitive, T: Primitive> FromColor<Rgba<S>> for Rgb<T> |
709 | where |
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 | |
721 | impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for Rgb<T> |
722 | where |
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 | |
734 | impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for Rgb<T> |
735 | where |
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 |
748 | pub(crate) trait Blend { |
749 | /// Blends a color in-place. |
750 | fn blend(&mut self, other: &Self); |
751 | } |
752 | |
753 | impl<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 | |
786 | impl<T: Primitive> Blend for Luma<T> { |
787 | fn blend(&mut self, other: &Luma<T>) { |
788 | *self = *other; |
789 | } |
790 | } |
791 | |
792 | impl<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 | |
856 | impl<T: Primitive> Blend for Rgb<T> { |
857 | fn blend(&mut self, other: &Rgb<T>) { |
858 | *self = *other; |
859 | } |
860 | } |
861 | |
862 | /// Invert a color |
863 | pub(crate) trait Invert { |
864 | /// Inverts a color in-place. |
865 | fn invert(&mut self); |
866 | } |
867 | |
868 | impl<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 | |
877 | impl<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 | |
888 | impl<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 | |
898 | impl<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)] |
913 | mod 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 | |