skia_safe/core/
color.rs

1use crate::prelude::*;
2use skia_bindings::{self as sb, SkColor, SkColor4f, SkHSVToColor, SkPMColor, SkRGBToHSV, U8CPU};
3use std::ops::{BitAnd, BitOr, Index, IndexMut, Mul};
4
5// TODO: What should we do with SkAlpha?
6// It does not seem to be used, but if we want to export it, we'd
7// like to define Alpha::TRANSPARENT and Alpha::OPAQUE.
8// pub type Alpha = u8;
9
10// Note: SkColor _is_ a u32, and therefore its components are
11// endian dependent, so we can't expose it as (transmuted) individual
12// argb fields.
13#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
14#[repr(transparent)]
15pub struct Color(SkColor);
16
17native_transmutable!(SkColor, Color, color_layout);
18
19impl From<u32> for Color {
20    fn from(argb: u32) -> Self {
21        Color::new(argb)
22    }
23}
24
25impl From<RGB> for Color {
26    fn from(rgb: RGB) -> Self {
27        Color::from_rgb(rgb.r, rgb.g, rgb.b)
28    }
29}
30
31//
32// Bitwise operators.
33//
34
35impl BitOr for Color {
36    type Output = Self;
37
38    fn bitor(self, rhs: Self) -> Self::Output {
39        Color::from_native_c(self.native() | rhs.native())
40    }
41}
42
43impl BitAnd for Color {
44    type Output = Self;
45
46    fn bitand(self, rhs: Self) -> Self::Output {
47        Color::from_native_c(self.native() & rhs.native())
48    }
49}
50
51impl BitOr<u32> for Color {
52    type Output = Self;
53
54    fn bitor(self, rhs: u32) -> Self::Output {
55        self | Color::from_native_c(rhs)
56    }
57}
58
59impl BitAnd<u32> for Color {
60    type Output = Self;
61
62    fn bitand(self, rhs: u32) -> Self::Output {
63        self & (Color::from_native_c(rhs))
64    }
65}
66
67impl Color {
68    pub const fn new(argb: u32) -> Self {
69        Self(argb)
70    }
71
72    // Don't use the u8cpu type in the arguments here, because we trust the Rust compiler to
73    // optimize the storage type.
74    pub const fn from_argb(a: u8, r: u8, g: u8, b: u8) -> Color {
75        Self(((a as U8CPU) << 24) | ((r as U8CPU) << 16) | ((g as U8CPU) << 8) | (b as U8CPU))
76    }
77
78    pub const fn from_rgb(r: u8, g: u8, b: u8) -> Color {
79        Self::from_argb(0xff, r, g, b)
80    }
81
82    pub fn a(self) -> u8 {
83        (self.into_native() >> 24) as _
84    }
85
86    pub fn r(self) -> u8 {
87        (self.into_native() >> 16) as _
88    }
89
90    pub fn g(self) -> u8 {
91        (self.into_native() >> 8) as _
92    }
93
94    pub fn b(self) -> u8 {
95        self.into_native() as _
96    }
97
98    #[must_use]
99    pub fn with_a(self, a: u8) -> Self {
100        Self::from_argb(a, self.r(), self.g(), self.b())
101    }
102
103    pub const TRANSPARENT: Self = Self(sb::SK_ColorTRANSPARENT);
104    pub const BLACK: Self = Self(sb::SK_ColorBLACK);
105    pub const DARK_GRAY: Self = Self(sb::SK_ColorDKGRAY);
106    pub const GRAY: Self = Self(sb::SK_ColorGRAY);
107    pub const LIGHT_GRAY: Self = Self(sb::SK_ColorLTGRAY);
108    pub const WHITE: Self = Self(sb::SK_ColorWHITE);
109    pub const RED: Self = Self(sb::SK_ColorRED);
110    pub const GREEN: Self = Self(sb::SK_ColorGREEN);
111    pub const BLUE: Self = Self(sb::SK_ColorBLUE);
112    pub const YELLOW: Self = Self(sb::SK_ColorYELLOW);
113    pub const CYAN: Self = Self(sb::SK_ColorCYAN);
114    pub const MAGENTA: Self = Self(sb::SK_ColorMAGENTA);
115
116    pub fn to_rgb(self) -> RGB {
117        (self.r(), self.g(), self.b()).into()
118    }
119
120    pub fn to_hsv(self) -> HSV {
121        self.to_rgb().to_hsv()
122    }
123}
124
125#[derive(Copy, Clone, PartialEq, Eq, Debug)]
126pub struct RGB {
127    pub r: u8,
128    pub g: u8,
129    pub b: u8,
130}
131
132impl From<(u8, u8, u8)> for RGB {
133    fn from((r, g, b): (u8, u8, u8)) -> Self {
134        Self { r, g, b }
135    }
136}
137
138impl RGB {
139    pub fn to_hsv(self) -> HSV {
140        let mut hsv: [f32; 3] = Default::default();
141        unsafe {
142            SkRGBToHSV(
143                self.r.into(),
144                self.g.into(),
145                self.b.into(),
146                hsv.as_mut_ptr(),
147            );
148        }
149        HSV {
150            h: hsv[0],
151            s: hsv[1],
152            v: hsv[2],
153        }
154    }
155}
156
157#[derive(Copy, Clone, PartialEq, Debug)]
158pub struct HSV {
159    pub h: f32,
160    pub s: f32,
161    pub v: f32,
162}
163
164impl From<(f32, f32, f32)> for HSV {
165    fn from((h, s, v): (f32, f32, f32)) -> Self {
166        Self { h, s, v }
167    }
168}
169
170impl HSV {
171    pub fn to_color(self, alpha: u8) -> Color {
172        Color::from_native_c(unsafe {
173            SkHSVToColor(alpha.into(), [self.h, self.s, self.v].as_ptr())
174        })
175    }
176}
177
178pub type PMColor = SkPMColor;
179
180pub fn pre_multiply_argb(a: U8CPU, r: U8CPU, g: U8CPU, b: U8CPU) -> PMColor {
181    unsafe { sb::SkPreMultiplyARGB(a, r, g, b) }
182}
183
184pub fn pre_multiply_color(c: impl Into<Color>) -> PMColor {
185    unsafe { sb::SkPreMultiplyColor(c.into().into_native()) }
186}
187
188pub use sb::SkColorChannel as ColorChannel;
189
190#[test]
191fn color_channel_naming() {
192    let _ = ColorChannel::R;
193}
194
195bitflags! {
196    #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
197    pub struct ColorChannelFlag: u32 {
198        const RED = sb::SkColorChannelFlag::kRed_SkColorChannelFlag as _;
199        const GREEN = sb::SkColorChannelFlag::kGreen_SkColorChannelFlag as _;
200        const BLUE = sb::SkColorChannelFlag::kBlue_SkColorChannelFlag as _;
201        const ALPHA = sb::SkColorChannelFlag::kAlpha_SkColorChannelFlag as _;
202        const GRAY = sb::SkColorChannelFlag::kGray_SkColorChannelFlag as _;
203        const GRAY_ALPHA = Self::GRAY.bits() | Self::ALPHA.bits();
204        const RG = Self::RED.bits() | Self::GREEN.bits();
205        const RGB = Self::RG.bits() | Self::BLUE.bits();
206        const RGBA = Self::RGB.bits() | Self::ALPHA.bits();
207    }
208}
209
210// TODO: SkRGBA4f
211
212#[derive(Copy, Clone, PartialEq, Debug)]
213#[repr(C)]
214pub struct Color4f {
215    pub r: f32,
216    pub g: f32,
217    pub b: f32,
218    pub a: f32,
219}
220
221native_transmutable!(SkColor4f, Color4f, color4f_layout);
222
223impl AsRef<Self> for Color4f {
224    fn as_ref(&self) -> &Self {
225        self
226    }
227}
228
229impl Mul<f32> for Color4f {
230    type Output = Self;
231    fn mul(self, scale: f32) -> Self {
232        let r = self.r * scale;
233        let g = self.g * scale;
234        let b = self.b * scale;
235        let a = self.a * scale;
236        Self { r, g, b, a }
237    }
238}
239
240impl Mul for Color4f {
241    type Output = Self;
242    fn mul(self, scale: Self) -> Self {
243        self.mul(&scale)
244    }
245}
246
247impl Mul<&Self> for Color4f {
248    type Output = Self;
249    fn mul(self, scale: &Self) -> Self {
250        Self {
251            r: self.r * scale.r,
252            g: self.g * scale.g,
253            b: self.b * scale.b,
254            a: self.a * scale.a,
255        }
256    }
257}
258
259impl Index<usize> for Color4f {
260    type Output = f32;
261    fn index(&self, index: usize) -> &f32 {
262        &self.as_array()[index]
263    }
264}
265
266impl IndexMut<usize> for Color4f {
267    fn index_mut(&mut self, index: usize) -> &mut f32 {
268        &mut self.as_array_mut()[index]
269    }
270}
271
272impl From<Color> for Color4f {
273    fn from(color: Color) -> Self {
274        fn c(c: u8) -> f32 {
275            (f32::from(c)) * (1.0 / 255.0)
276        }
277        let r = c(color.r());
278        let g = c(color.g());
279        let b = c(color.b());
280        let a = c(color.a());
281        Self { r, g, b, a }
282    }
283}
284
285// Add all Color::From implementations to Color4f, so that
286// function signatures can promote Into<Color> to Into<Color4f>.
287
288impl From<u32> for Color4f {
289    fn from(color: u32) -> Self {
290        Color::from(color).into()
291    }
292}
293
294impl From<RGB> for Color4f {
295    fn from(rgb: RGB) -> Self {
296        Color::from(rgb).into()
297    }
298}
299
300impl Color4f {
301    pub const fn new(r: f32, g: f32, b: f32, a: f32) -> Color4f {
302        Self { r, g, b, a }
303    }
304
305    // corresponding Skia function: vec()
306    pub fn as_array(&self) -> &[f32; 4] {
307        unsafe { transmute_ref(self) }
308    }
309
310    // corresponding Skia function: vec()
311    pub fn as_array_mut(&mut self) -> &mut [f32; 4] {
312        unsafe { transmute_ref_mut(self) }
313    }
314
315    #[allow(clippy::float_cmp)]
316    pub fn is_opaque(&self) -> bool {
317        self.a == 1.0
318    }
319
320    // TODO: This is the copied implementation, it would probably be better
321    //       to call the Skia function.
322    pub fn fits_in_bytes(&self) -> bool {
323        debug_assert!(self.a >= 0.0 && self.a <= 1.0);
324        self.r >= 0.0
325            && self.r <= 1.0
326            && self.g >= 0.0
327            && self.g <= 1.0
328            && self.b >= 0.0
329            && self.b <= 1.0
330    }
331
332    pub fn to_color(self) -> Color {
333        fn c(f: f32) -> u8 {
334            (f.clamp(0.0, 1.0) * 255.0) as u8
335        }
336        let a = c(self.a);
337        let r = c(self.r);
338        let g = c(self.g);
339        let b = c(self.b);
340        Color::from_argb(a, r, g, b)
341    }
342
343    // TODO: FromPMColor
344    // TODO: premul()
345    // TODO: unpremul()
346
347    #[must_use]
348    pub fn to_bytes(self) -> u32 {
349        unsafe { sb::C_SkColor4f_toBytes_RGBA(self.native()) }
350    }
351
352    #[must_use]
353    pub fn from_bytes_rgba(color: u32) -> Self {
354        Self::from_native_c(unsafe { sb::C_SkColor4f_FromBytes_RGBA(color) })
355    }
356
357    #[must_use]
358    pub fn to_opaque(self) -> Self {
359        Self { a: 1.0, ..self }
360    }
361
362    #[must_use]
363    pub fn pin_alpha(self) -> Self {
364        Self {
365            r: self.r,
366            g: self.g,
367            b: self.b,
368            a: 0f32.max(self.a.min(1.0)),
369        }
370    }
371}
372
373pub mod colors {
374    use crate::Color4f;
375
376    pub const TRANSPARENT: Color4f = Color4f::new(0.0, 0.0, 0.0, 0.0);
377    pub const BLACK: Color4f = Color4f::new(0.0, 0.0, 0.0, 1.0);
378    pub const DARK_GREY: Color4f = Color4f::new(0.25, 0.25, 0.25, 1.0);
379    pub const GREY: Color4f = Color4f::new(0.5, 0.5, 0.5, 1.0);
380    pub const LIGHT_GREY: Color4f = Color4f::new(0.75, 0.75, 0.75, 1.0);
381    pub const WHITE: Color4f = Color4f::new(1.0, 1.0, 1.0, 1.0);
382    pub const RED: Color4f = Color4f::new(1.0, 0.0, 0.0, 1.0);
383    pub const GREEN: Color4f = Color4f::new(0.0, 1.0, 0.0, 1.0);
384    pub const BLUE: Color4f = Color4f::new(0.0, 0.0, 1.0, 1.0);
385    pub const YELLOW: Color4f = Color4f::new(1.0, 1.0, 0.0, 1.0);
386    pub const CYAN: Color4f = Color4f::new(0.0, 1.0, 1.0, 1.0);
387    pub const MAGENTA: Color4f = Color4f::new(1.0, 0.0, 1.0, 1.0);
388}
389
390#[cfg(test)]
391mod tests {
392    use super::{colors, Color, Color4f};
393
394    #[test]
395    #[allow(clippy::float_cmp)]
396    pub fn color4f_array_access() {
397        let mut color = Color4f {
398            r: 0.1,
399            g: 0.2,
400            b: 0.3,
401            a: 0.4,
402        };
403        color[1] = 0.5;
404        assert_eq!(0.5, color.g);
405    }
406
407    #[test]
408    pub fn color_color4f_conversion() {
409        let c = Color::from_argb(1, 2, 3, 4);
410        let cf = Color4f::from(c);
411        let c2 = cf.to_color();
412        assert_eq!(c, c2);
413    }
414
415    #[test]
416    pub fn color4f_value_can_be_passed_as_ref() {
417        fn passed_as_ref(_c: impl AsRef<Color4f>) {}
418        passed_as_ref(colors::BLACK);
419    }
420}