tiny_skia/
color.rs

1// Copyright 2006 The Android Open Source Project
2// Copyright 2020 Yevhenii Reizner
3//
4// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6
7use tiny_skia_path::{NormalizedF32, Scalar};
8
9/// 8-bit type for an alpha value. 255 is 100% opaque, zero is 100% transparent.
10pub type AlphaU8 = u8;
11
12/// Represents fully transparent AlphaU8 value.
13pub const ALPHA_U8_TRANSPARENT: AlphaU8 = 0x00;
14
15/// Represents fully opaque AlphaU8 value.
16pub const ALPHA_U8_OPAQUE: AlphaU8 = 0xFF;
17
18/// Represents fully transparent Alpha value.
19pub const ALPHA_TRANSPARENT: NormalizedF32 = NormalizedF32::ZERO;
20
21/// Represents fully opaque Alpha value.
22pub const ALPHA_OPAQUE: NormalizedF32 = NormalizedF32::ONE;
23
24/// A 32-bit RGBA color value.
25///
26/// Byteorder: RGBA (relevant for bytemuck casts)
27#[repr(transparent)]
28#[derive(Copy, Clone, PartialEq)]
29pub struct ColorU8([u8; 4]);
30
31impl ColorU8 {
32    /// Creates a new color.
33    pub const fn from_rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
34        ColorU8([r, g, b, a])
35    }
36
37    /// Returns color's red component.
38    pub const fn red(self) -> u8 {
39        self.0[0]
40    }
41
42    /// Returns color's green component.
43    pub const fn green(self) -> u8 {
44        self.0[1]
45    }
46
47    /// Returns color's blue component.
48    pub const fn blue(self) -> u8 {
49        self.0[2]
50    }
51
52    /// Returns color's alpha component.
53    pub const fn alpha(self) -> u8 {
54        self.0[3]
55    }
56
57    /// Check that color is opaque.
58    ///
59    /// Alpha == 255
60    pub fn is_opaque(&self) -> bool {
61        self.alpha() == ALPHA_U8_OPAQUE
62    }
63
64    /// Converts into a premultiplied color.
65    pub fn premultiply(&self) -> PremultipliedColorU8 {
66        let a = self.alpha();
67        if a != ALPHA_U8_OPAQUE {
68            PremultipliedColorU8::from_rgba_unchecked(
69                premultiply_u8(self.red(), a),
70                premultiply_u8(self.green(), a),
71                premultiply_u8(self.blue(), a),
72                a,
73            )
74        } else {
75            PremultipliedColorU8::from_rgba_unchecked(self.red(), self.green(), self.blue(), a)
76        }
77    }
78}
79
80impl core::fmt::Debug for ColorU8 {
81    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
82        f.debug_struct("ColorU8")
83            .field("r", &self.red())
84            .field("g", &self.green())
85            .field("b", &self.blue())
86            .field("a", &self.alpha())
87            .finish()
88    }
89}
90
91/// A 32-bit premultiplied RGBA color value.
92///
93/// Byteorder: RGBA (relevant for bytemuck casts)
94#[repr(transparent)]
95#[derive(Copy, Clone, PartialEq)]
96pub struct PremultipliedColorU8([u8; 4]);
97
98// Perfectly safe, since [u8; 4] is already Pod.
99unsafe impl bytemuck::Zeroable for PremultipliedColorU8 {}
100unsafe impl bytemuck::Pod for PremultipliedColorU8 {}
101
102impl PremultipliedColorU8 {
103    /// A transparent color.
104    pub const TRANSPARENT: Self = PremultipliedColorU8::from_rgba_unchecked(0, 0, 0, 0);
105
106    /// Creates a new premultiplied color.
107    ///
108    /// RGB components must be <= alpha.
109    pub fn from_rgba(r: u8, g: u8, b: u8, a: u8) -> Option<Self> {
110        if r <= a && g <= a && b <= a {
111            Some(PremultipliedColorU8([r, g, b, a]))
112        } else {
113            None
114        }
115    }
116
117    /// Creates a new color.
118    pub(crate) const fn from_rgba_unchecked(r: u8, g: u8, b: u8, a: u8) -> Self {
119        PremultipliedColorU8([r, g, b, a])
120    }
121
122    /// Returns color's red component.
123    ///
124    /// The value is <= alpha.
125    pub const fn red(self) -> u8 {
126        self.0[0]
127    }
128
129    /// Returns color's green component.
130    ///
131    /// The value is <= alpha.
132    pub const fn green(self) -> u8 {
133        self.0[1]
134    }
135
136    /// Returns color's blue component.
137    ///
138    /// The value is <= alpha.
139    pub const fn blue(self) -> u8 {
140        self.0[2]
141    }
142
143    /// Returns color's alpha component.
144    pub const fn alpha(self) -> u8 {
145        self.0[3]
146    }
147
148    /// Check that color is opaque.
149    ///
150    /// Alpha == 255
151    pub fn is_opaque(&self) -> bool {
152        self.alpha() == ALPHA_U8_OPAQUE
153    }
154
155    /// Returns a demultiplied color.
156    pub fn demultiply(&self) -> ColorU8 {
157        let alpha = self.alpha();
158        if alpha == ALPHA_U8_OPAQUE {
159            ColorU8(self.0)
160        } else {
161            let a = alpha as f64 / 255.0;
162            ColorU8::from_rgba(
163                (self.red() as f64 / a + 0.5) as u8,
164                (self.green() as f64 / a + 0.5) as u8,
165                (self.blue() as f64 / a + 0.5) as u8,
166                alpha,
167            )
168        }
169    }
170}
171
172impl core::fmt::Debug for PremultipliedColorU8 {
173    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
174        f.debug_struct("PremultipliedColorU8")
175            .field("r", &self.red())
176            .field("g", &self.green())
177            .field("b", &self.blue())
178            .field("a", &self.alpha())
179            .finish()
180    }
181}
182
183/// An RGBA color value, holding four floating point components.
184///
185/// # Guarantees
186///
187/// - All values are in 0..=1 range.
188#[derive(Copy, Clone, PartialEq, Debug)]
189pub struct Color {
190    r: NormalizedF32,
191    g: NormalizedF32,
192    b: NormalizedF32,
193    a: NormalizedF32,
194}
195
196const NV_ZERO: NormalizedF32 = NormalizedF32::ZERO;
197const NV_ONE: NormalizedF32 = NormalizedF32::ONE;
198
199impl Color {
200    /// A transparent color.
201    pub const TRANSPARENT: Color = Color {
202        r: NV_ZERO,
203        g: NV_ZERO,
204        b: NV_ZERO,
205        a: NV_ZERO,
206    };
207    /// A black color.
208    pub const BLACK: Color = Color {
209        r: NV_ZERO,
210        g: NV_ZERO,
211        b: NV_ZERO,
212        a: NV_ONE,
213    };
214    /// A white color.
215    pub const WHITE: Color = Color {
216        r: NV_ONE,
217        g: NV_ONE,
218        b: NV_ONE,
219        a: NV_ONE,
220    };
221
222    /// Creates a new color from 4 components.
223    ///
224    /// All values must be in 0..=1 range.
225    pub fn from_rgba(r: f32, g: f32, b: f32, a: f32) -> Option<Self> {
226        Some(Color {
227            r: NormalizedF32::new(r)?,
228            g: NormalizedF32::new(g)?,
229            b: NormalizedF32::new(b)?,
230            a: NormalizedF32::new(a)?,
231        })
232    }
233
234    /// Creates a new color from 4 components.
235    ///
236    /// u8 will be divided by 255 to get the float component.
237    pub fn from_rgba8(r: u8, g: u8, b: u8, a: u8) -> Self {
238        Color {
239            r: NormalizedF32::new_u8(r),
240            g: NormalizedF32::new_u8(g),
241            b: NormalizedF32::new_u8(b),
242            a: NormalizedF32::new_u8(a),
243        }
244    }
245
246    /// Returns color's red component.
247    ///
248    /// The value is guarantee to be in a 0..=1 range.
249    pub fn red(&self) -> f32 {
250        self.r.get()
251    }
252
253    /// Returns color's green component.
254    ///
255    /// The value is guarantee to be in a 0..=1 range.
256    pub fn green(&self) -> f32 {
257        self.g.get()
258    }
259
260    /// Returns color's blue component.
261    ///
262    /// The value is guarantee to be in a 0..=1 range.
263    pub fn blue(&self) -> f32 {
264        self.b.get()
265    }
266
267    /// Returns color's alpha component.
268    ///
269    /// The value is guarantee to be in a 0..=1 range.
270    pub fn alpha(&self) -> f32 {
271        self.a.get()
272    }
273
274    /// Sets the red component value.
275    ///
276    /// The new value will be clipped to the 0..=1 range.
277    pub fn set_red(&mut self, c: f32) {
278        self.r = NormalizedF32::new_clamped(c);
279    }
280
281    /// Sets the green component value.
282    ///
283    /// The new value will be clipped to the 0..=1 range.
284    pub fn set_green(&mut self, c: f32) {
285        self.g = NormalizedF32::new_clamped(c);
286    }
287
288    /// Sets the blue component value.
289    ///
290    /// The new value will be clipped to the 0..=1 range.
291    pub fn set_blue(&mut self, c: f32) {
292        self.b = NormalizedF32::new_clamped(c);
293    }
294
295    /// Sets the alpha component value.
296    ///
297    /// The new value will be clipped to the 0..=1 range.
298    pub fn set_alpha(&mut self, c: f32) {
299        self.a = NormalizedF32::new_clamped(c);
300    }
301
302    /// Shifts color's opacity.
303    ///
304    /// Essentially, multiplies color's alpha by opacity.
305    ///
306    /// `opacity` will be clamped to the 0..=1 range first.
307    /// The final alpha will also be clamped.
308    pub fn apply_opacity(&mut self, opacity: f32) {
309        self.a = NormalizedF32::new_clamped(self.a.get() * opacity.bound(0.0, 1.0));
310    }
311
312    /// Check that color is opaque.
313    ///
314    /// Alpha == 1.0
315    pub fn is_opaque(&self) -> bool {
316        self.a == ALPHA_OPAQUE
317    }
318
319    /// Converts into a premultiplied color.
320    pub fn premultiply(&self) -> PremultipliedColor {
321        if self.is_opaque() {
322            PremultipliedColor {
323                r: self.r,
324                g: self.g,
325                b: self.b,
326                a: self.a,
327            }
328        } else {
329            PremultipliedColor {
330                r: NormalizedF32::new_clamped(self.r.get() * self.a.get()),
331                g: NormalizedF32::new_clamped(self.g.get() * self.a.get()),
332                b: NormalizedF32::new_clamped(self.b.get() * self.a.get()),
333                a: self.a,
334            }
335        }
336    }
337
338    /// Converts into `ColorU8`.
339    pub fn to_color_u8(&self) -> ColorU8 {
340        let c = color_f32_to_u8(self.r, self.g, self.b, self.a);
341        ColorU8::from_rgba(c[0], c[1], c[2], c[3])
342    }
343}
344
345/// A premultiplied RGBA color value, holding four floating point components.
346///
347/// # Guarantees
348///
349/// - All values are in 0..=1 range.
350/// - RGB components are <= A.
351#[derive(Copy, Clone, PartialEq, Debug)]
352pub struct PremultipliedColor {
353    r: NormalizedF32,
354    g: NormalizedF32,
355    b: NormalizedF32,
356    a: NormalizedF32,
357}
358
359impl PremultipliedColor {
360    /// Returns color's red component.
361    ///
362    /// - The value is guarantee to be in a 0..=1 range.
363    /// - The value is <= alpha.
364    pub fn red(&self) -> f32 {
365        self.r.get()
366    }
367
368    /// Returns color's green component.
369    ///
370    /// - The value is guarantee to be in a 0..=1 range.
371    /// - The value is <= alpha.
372    pub fn green(&self) -> f32 {
373        self.g.get()
374    }
375
376    /// Returns color's blue component.
377    ///
378    /// - The value is guarantee to be in a 0..=1 range.
379    /// - The value is <= alpha.
380    pub fn blue(&self) -> f32 {
381        self.b.get()
382    }
383
384    /// Returns color's alpha component.
385    ///
386    /// - The value is guarantee to be in a 0..=1 range.
387    pub fn alpha(&self) -> f32 {
388        self.a.get()
389    }
390
391    /// Returns a demultiplied color.
392    pub fn demultiply(&self) -> Color {
393        let a = self.a.get();
394        if a == 0.0 {
395            Color::TRANSPARENT
396        } else {
397            Color {
398                r: NormalizedF32::new_clamped(self.r.get() / a),
399                g: NormalizedF32::new_clamped(self.g.get() / a),
400                b: NormalizedF32::new_clamped(self.b.get() / a),
401                a: self.a,
402            }
403        }
404    }
405
406    /// Converts into `PremultipliedColorU8`.
407    pub fn to_color_u8(&self) -> PremultipliedColorU8 {
408        let c = color_f32_to_u8(self.r, self.g, self.b, self.a);
409        PremultipliedColorU8::from_rgba_unchecked(c[0], c[1], c[2], c[3])
410    }
411}
412
413/// Return a*b/255, rounding any fractional bits.
414pub fn premultiply_u8(c: u8, a: u8) -> u8 {
415    let prod = u32::from(c) * u32::from(a) + 128;
416    ((prod + (prod >> 8)) >> 8) as u8
417}
418
419fn color_f32_to_u8(
420    r: NormalizedF32,
421    g: NormalizedF32,
422    b: NormalizedF32,
423    a: NormalizedF32,
424) -> [u8; 4] {
425    [
426        (r.get() * 255.0 + 0.5) as u8,
427        (g.get() * 255.0 + 0.5) as u8,
428        (b.get() * 255.0 + 0.5) as u8,
429        (a.get() * 255.0 + 0.5) as u8,
430    ]
431}
432
433#[cfg(test)]
434mod tests {
435    use super::*;
436
437    #[test]
438    fn premultiply_u8() {
439        assert_eq!(
440            ColorU8::from_rgba(10, 20, 30, 40).premultiply(),
441            PremultipliedColorU8::from_rgba_unchecked(2, 3, 5, 40)
442        );
443    }
444
445    #[test]
446    fn premultiply_u8_opaque() {
447        assert_eq!(
448            ColorU8::from_rgba(10, 20, 30, 255).premultiply(),
449            PremultipliedColorU8::from_rgba_unchecked(10, 20, 30, 255)
450        );
451    }
452
453    #[test]
454    fn demultiply_u8_1() {
455        assert_eq!(
456            PremultipliedColorU8::from_rgba_unchecked(2, 3, 5, 40).demultiply(),
457            ColorU8::from_rgba(13, 19, 32, 40)
458        );
459    }
460
461    #[test]
462    fn demultiply_u8_2() {
463        assert_eq!(
464            PremultipliedColorU8::from_rgba_unchecked(10, 20, 30, 255).demultiply(),
465            ColorU8::from_rgba(10, 20, 30, 255)
466        );
467    }
468
469    #[test]
470    fn demultiply_u8_3() {
471        assert_eq!(
472            PremultipliedColorU8::from_rgba_unchecked(153, 99, 54, 180).demultiply(),
473            ColorU8::from_rgba(217, 140, 77, 180)
474        );
475    }
476
477    #[test]
478    fn bytemuck_casts_rgba() {
479        let slice = &[
480            PremultipliedColorU8::from_rgba_unchecked(0, 1, 2, 3),
481            PremultipliedColorU8::from_rgba_unchecked(10, 11, 12, 13),
482        ];
483        let bytes: &[u8] = bytemuck::cast_slice(slice);
484        assert_eq!(bytes, &[0, 1, 2, 3, 10, 11, 12, 13]);
485    }
486}