Advertisement
Guest User

Untitled

a guest
Feb 25th, 2020
126
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 12.93 KB | None | 0 0
  1. // TODO: fix clippy and add tests
  2.  
  3. use cgmath::{Vector3, Vector4};
  4. use serde::{Deserialize, Serialize};
  5. use std::{
  6.     convert::TryFrom,
  7.     ops::{Add, AddAssign, Mul, MulAssign},
  8. };
  9.  
  10. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
  11. pub struct Color {
  12.     pub r: u8,
  13.     pub g: u8,
  14.     pub b: u8,
  15.     pub a: u8
  16. }
  17.  
  18. impl Color {
  19.     pub const BLACK: Self = Self::new(0, 0, 0, 255);
  20.     pub const BLUE: Self = Self::new(0, 0, 255, 255);
  21.     pub const CYAN: Self = Self::new(0, 255, 255, 255);
  22.     pub const GREEN: Self = Self::new(0, 255, 0, 255);
  23.     pub const MAGENTA: Self = Self::new(255, 0, 255, 255);
  24.     pub const ORANGE: Self = Self::new(255, 165, 0, 255);
  25.     pub const RED: Self = Self::new(255, 0, 0, 255);
  26.     pub const YELLOW: Self = Self::new(255, 255, 0, 255);
  27.     pub const WHITE: Self = Self::new(255, 255, 255, 255);
  28.  
  29.     #[inline]
  30.     pub const fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
  31.         Self { r, g, b, a }
  32.     }
  33.  
  34.     #[inline]
  35.     pub const fn from_lightness(l: u8) -> Self {
  36.         Self::new(l, l, l, 255)
  37.     }
  38.  
  39.     #[inline]
  40.     pub const fn is_opaque(self) -> bool {
  41.         self.a == 255
  42.     }
  43.  
  44.     #[inline]
  45.     pub fn from_cmy(cyan: f32, magenta: f32, yellow: f32) -> Self {
  46.         Self::new(
  47.             ((1.0 - cyan) * 255.0) as u8,
  48.             ((1.0 - magenta) * 255.0) as u8,
  49.             ((1.0 - yellow) * 255.0) as u8,
  50.             255,
  51.         )
  52.     }
  53.  
  54.     #[inline]
  55.     pub fn from_cmyk(cyan: f32, magenta: f32, yellow: f32, black: f32) -> Self {
  56.         Self::from_cmy(
  57.             cyan * (1.0 - black) + black,
  58.             magenta * (1.0 - black) + black,
  59.             yellow * (1.0 - black) + black,
  60.         )
  61.     }
  62.  
  63.     #[inline]
  64.     pub fn from_hsl(hue: f32, saturation: f32, lightness: f32) -> Self {
  65.         if saturation == 0.0 {
  66.             return Self::from_lightness((lightness * 255.0) as u8);
  67.         }
  68.  
  69.         let v2 = if lightness < 0.5 {
  70.             lightness * (1.0 + saturation)
  71.         } else {
  72.             (lightness + saturation) - (saturation * lightness)
  73.         };
  74.  
  75.         let v1 = 2.0 * lightness - v2;
  76.         let h = hue / 360.0;
  77.  
  78.         Self::new(
  79.             (255.0 * Self::hue_to_rgb(v1, v2, h + 1.0 / 3.0)) as u8,
  80.             (255.0 * Self::hue_to_rgb(v1, v2, h)) as u8,
  81.             (255.0 * Self::hue_to_rgb(v1, v2, h - 1.0 / 3.0)) as u8,
  82.             255,
  83.         )
  84.     }
  85.  
  86.     #[inline]
  87.     pub fn from_hsv(hue: f32, saturation: f32, value: f32) -> Self {
  88.         if saturation == 0.0 {
  89.             return Self::from_lightness((value * 255.0) as u8);
  90.         }
  91.  
  92.         let mut h = hue / 360.0 * 6.0; // pourquoi pas / 60 ?
  93.  
  94.         if h == 6.0 {
  95.             h = 0.0 // h must be < 1
  96.         }
  97.  
  98.         let i = h as isize;
  99.         let v1 = value * (1.0 - saturation);
  100.         let v2 = value * (1.0 - saturation * (h - i as f32));
  101.         let v3 = value * (1.0 - saturation * (1.0 - (h - i as f32)));
  102.  
  103.         let (r, g, b) = match i {
  104.             0 => (value, v3, v1),
  105.             1 => (v2, value, v1),
  106.             2 => (v1, value, v3),
  107.             3 => (v1, v2, value),
  108.             4 => (v3, v1, value),
  109.             _ => (value, v1, v2),
  110.         };
  111.  
  112.         Self::new((r * 255.0) as u8, (g * 255.0) as u8, (b * 255.0) as u8, 255)
  113.     }
  114.    
  115.     #[inline]
  116.     pub fn from_xyz(mut x: f32, mut y: f32, mut z: f32) -> Self {
  117.         x /= 100.0; // X from 0 to  95.047
  118.         y /= 100.0; // Y from 0 to 100.000
  119.         z /= 100.0; // Z from 0 to 108.883
  120.  
  121.         let mut r = x *  3.2406 + y * -1.5372 + z * -0.4986;
  122.         let mut g = x * -0.9689 + y *  1.8758 + z *  0.0415;
  123.         let mut b = x *  0.0557 + y * -0.2040 + z *  1.0570;
  124.        
  125.         if r > 0.0031308 {
  126.             r = 1.055 * r.powf(1.0/2.4) - 0.055;
  127.         }
  128.         else {
  129.             r *= 12.92;
  130.         }
  131.  
  132.         if g > 0.0031308 {
  133.             g = 1.055 * g.powf(1.0/2.4) - 0.055;
  134.         } else {
  135.             g *= 12.92;
  136.         }
  137.  
  138.         if b > 0.0031308 {
  139.             b = 1.055 * b.powf(1.0/2.4) - 0.055;
  140.         } else {
  141.             b *= 12.92;
  142.         }
  143.  
  144.         Color::new(
  145.             (r * 255.0) as u8,
  146.             (g * 255.0) as u8,
  147.             (b * 255.0) as u8,
  148.             255
  149.         )
  150.     }  
  151.    
  152.     #[inline]
  153.     pub fn to_cmy(&self) -> (f32, f32, f32) {
  154.         (
  155.             1.0 - self.r as f32 / 255.0,
  156.             1.0 - self.g as f32 / 255.0,
  157.             1.0 - self.b as f32 / 255.0,
  158.         )
  159.     }
  160.  
  161.     #[inline]
  162.     pub fn to_cmyk(&self) -> (f32, f32, f32, f32) {
  163.         let (cyan, magenta, yellow) = self.to_cmy();
  164.  
  165.         let key = 1.0f32.min(cyan).min(magenta).min(yellow);
  166.  
  167.         if key == 1.0 {
  168.             // Black
  169.             (0.0, 0.0, 0.0, key)
  170.         } else {
  171.             (
  172.                 (cyan - key) / (1.0 - key),
  173.                 (magenta - key) / (1.0 - key),
  174.                 (yellow - key) / (1.0 - key),
  175.                 key
  176.             )
  177.         }
  178.     }
  179.  
  180.     #[inline]
  181.     pub fn to_hsl(&self) -> (f32, f32, f32) {
  182.         let red = self.r as f32 / 255.0;
  183.         let green = self.g as f32 / 255.0;
  184.         let blue = self.b as f32 / 255.0;
  185.  
  186.         let min = red.min(green).min(blue); // Min. value of RGB
  187.         let max = red.max(green).max(blue); // Max. value of RGB
  188.  
  189.         let delta_max = max - min; // Delta RGB value
  190.  
  191.         let lightness = (max + min)/2.0;
  192.  
  193.         if delta_max == 0.0 {
  194.             // This is gray, no chroma...
  195.             return (0.0, 0.0, lightness);
  196.         }
  197.  
  198.         let saturation = if lightness <= 0.5 {
  199.             delta_max / (max + min)
  200.         } else {
  201.             delta_max / (2.0 - max - min)
  202.         };
  203.  
  204.         let delta_red = ((max - red) / 6.0 + delta_max / 2.0) / delta_max;
  205.         let delta_green = ((max - green) / 6.0 + delta_max / 2.0) / delta_max;
  206.         let delta_blue = ((max - blue) / 6.0 + delta_max / 2.0) / delta_max;
  207.  
  208.         let hue = {
  209.             let h = {
  210.                 if red == max {
  211.                     delta_blue - delta_green
  212.                 } else if green == max {
  213.                     1.0 / 3.0 + delta_red - delta_blue
  214.                 } else {
  215.                     2.0 / 3.0 + delta_green - delta_red
  216.                 }
  217.             };
  218.  
  219.             if h < 0.0 {
  220.                 h + 1.0
  221.             } else {
  222.                 h - 1.0
  223.             }
  224.         } * 360.0;
  225.  
  226.         (hue, saturation, lightness)
  227.     }
  228.  
  229.     #[inline]
  230.     pub fn to_hsv(&self) -> (f32, f32, f32) {
  231.         let red = self.r as f32 / 255.0;
  232.         let green = self.g as f32 / 255.0;
  233.         let blue = self.b as f32 / 255.0;
  234.  
  235.         let min = red.min(green).min(blue); // Min. value of RGB
  236.         let max = red.max(green).max(blue); // Max. value of RGB
  237.  
  238.         let delta_max = max - min; // Delta RGB value
  239.  
  240.         let value = max;
  241.  
  242.         if delta_max == 0.0 {
  243.             // This is gray, no chroma...
  244.             return (0.0, 0.0, value);
  245.         }
  246.         // Chromatic data...
  247.         let saturation = delta_max / max;
  248.  
  249.         let delta_red = ((max - red) / 6.0 + delta_max / 2.0) / delta_max;
  250.         let delta_green = ((max - green) / 6.0 + delta_max / 2.0) / delta_max;
  251.         let delta_blue = ((max - blue) / 6.0 + delta_max / 2.0) / delta_max;
  252.  
  253.         let hue = {
  254.             let h = {
  255.                 if red == max {
  256.                     delta_blue - delta_green
  257.                 } else if green == max {
  258.                     1.0 / 3.0 + delta_red - delta_blue
  259.                 } else {
  260.                     2.0 / 3.0 + delta_green - delta_red
  261.                 }
  262.             };
  263.  
  264.             if h < 0.0 {
  265.                 h + 1.0
  266.             } else {
  267.                 h - 1.0
  268.             }
  269.         } * 360.0;
  270.  
  271.         (hue, saturation, value)
  272.     }
  273.  
  274.     #[inline]
  275.     pub fn to_xyz(&self) -> (f32, f32, f32) {
  276.         let mut red = self.r as f32 / 255.0;
  277.         let mut green = self.g as f32 / 255.0;
  278.         let mut blue = self.b as f32 / 255.0;
  279.  
  280.         if red > 0.04045 {
  281.             red = ((red + 0.055) / 1.055).powf(2.4);
  282.         } else {
  283.             red /= 12.92;
  284.         }
  285.  
  286.         if green > 0.04045 {
  287.             green = ((green + 0.055) / 1.055).powf(2.4);
  288.         } else {
  289.             green /= 12.92;
  290.         }
  291.  
  292.         if blue > 0.04045 {
  293.             blue = ((blue + 0.055) / 1.055).powf(2.4);
  294.         } else {
  295.             blue /= 12.92;
  296.         }
  297.  
  298.         red *= 100.0;
  299.         blue *= 100.0;
  300.         green *= 100.0;
  301.  
  302.         // Observer. = 2, Illuminant = D65
  303.         (
  304.             red * 0.4124 + green * 0.3576 + blue * 0.1805,
  305.             red * 0.2126 + green * 0.7152 + blue * 0.0722,
  306.             red * 0.0193 + green * 0.1192 + blue * 0.9505,
  307.         )
  308.     }
  309.  
  310.     #[allow(non_snake_case)]
  311.     #[inline]
  312.     fn hue_to_rgb(v1: f32, v2: f32, mut v_h: f32) -> f32 {
  313.         if v_h < 0.0 {
  314.             v_h += 1.0;
  315.         }
  316.  
  317.         if v_h > 1.0 {
  318.             v_h -= 1.0;
  319.         }
  320.  
  321.         if (6.0 * v_h) < 1.0 {
  322.             return v1 + (v2 - v1) * 6.0 * v_h;
  323.         }
  324.  
  325.         if (2.0 * v_h) < 1.0 {
  326.             return v2;
  327.         }
  328.  
  329.         if (3.0 * v_h) < 2.0 {
  330.             return v1 + (v2 - v1) * (2.0 / 3.0 - v_h) * 6.0;
  331.         }
  332.  
  333.         v1
  334.     }
  335. }
  336.  
  337. impl Add for Color {
  338.     type Output = Self;
  339.  
  340.     #[inline]
  341.     fn add(self, other: Self) -> Self::Output {
  342.         Self::new(
  343.             (self.r as usize + other.r as usize).min(255) as u8,
  344.             (self.g as usize + other.g as usize).min(255) as u8,
  345.             (self.b as usize + other.b as usize).min(255) as u8,
  346.             (self.a as usize + other.a as usize).min(255) as u8,
  347.         )
  348.     }
  349. }
  350.  
  351. impl AddAssign for Color {
  352.     #[inline]
  353.     fn add_assign(&mut self, other: Self) {
  354.         *self = *self + other
  355.     }
  356. }
  357.  
  358. impl Mul for Color {
  359.     type Output = Self;
  360.  
  361.     #[inline]
  362.     fn mul(self, other: Self) -> Self::Output {
  363.         Self::new(
  364.             ((self.r as usize * other.r as usize) / 255) as u8,
  365.             ((self.g as usize * other.g as usize) / 255) as u8,
  366.             ((self.b as usize * other.b as usize) / 255) as u8,
  367.             ((self.a as usize * other.a as usize) / 255) as u8,
  368.         )
  369.     }
  370. }
  371.  
  372. impl MulAssign for Color {
  373.     #[inline]
  374.     fn mul_assign(&mut self, other: Self) {
  375.         *self = *self * other
  376.     }
  377. }
  378.  
  379. impl From<(u8, u8, u8)> for Color {
  380.     #[inline]
  381.     fn from(color: (u8, u8, u8)) -> Self {
  382.         Self::new(color.0, color.1, color.2, 255)
  383.     }
  384. }
  385.  
  386. impl From<[u8; 3]> for Color {
  387.     #[inline]
  388.     fn from(color: [u8; 3]) -> Self {
  389.         Self::new(color[0], color[1], color[2], 255)
  390.     }
  391. }
  392.  
  393. impl From<Vector3<u8>> for Color {
  394.     #[inline]
  395.     fn from(color: Vector3<u8>) -> Self {
  396.         Self::new(color[0], color[1], color[2], 255)
  397.     }
  398. }
  399.  
  400. impl From<(u8, u8, u8, u8)> for Color {
  401.     #[inline]
  402.     fn from(color: (u8, u8, u8, u8)) -> Self {
  403.         Self::new(color.0, color.1, color.2, color.3)
  404.     }
  405. }
  406.  
  407. impl From<([u8; 3], u8)> for Color {
  408.     #[inline]
  409.     fn from(color: ([u8; 3], u8)) -> Self {
  410.         Self::new(color.0[0], color.0[1], color.0[2], color.1)
  411.     }
  412. }
  413.  
  414. impl From<[u8; 4]> for Color {
  415.     #[inline]
  416.     fn from(color: [u8; 4]) -> Self {
  417.         Self::new(color[0], color[1], color[2], color[3])
  418.     }
  419. }
  420.  
  421. impl From<Vector4<u8>> for Color {
  422.     #[inline]
  423.     fn from(color: Vector4<u8>) -> Self {
  424.         Self::new(color[0], color[1], color[2], color[3])
  425.     }
  426. }
  427.  
  428. impl From<Color> for (u8, u8, u8) {
  429.     #[inline]
  430.     fn from(color: Color) -> Self {
  431.         (color.r, color.g, color.b)
  432.     }
  433. }
  434.  
  435. impl From<Color> for [u8; 3] {
  436.     #[inline]
  437.     fn from(color: Color) -> Self {
  438.         [color.r, color.g, color.b]
  439.     }
  440. }
  441.  
  442. impl From<Color> for Vector3<u8> {
  443.     #[inline]
  444.     fn from(color: Color) -> Self {
  445.         Vector3::new(color.r, color.g, color.b)
  446.     }
  447. }
  448.  
  449. impl From<Color> for (u8, u8, u8, u8) {
  450.     #[inline]
  451.     fn from(color: Color) -> Self {
  452.         (color.r, color.g, color.b, color.a)
  453.     }
  454. }
  455.  
  456. impl From<Color> for [u8; 4] {
  457.     #[inline]
  458.     fn from(color: Color) -> Self {
  459.         [color.r, color.g, color.b, color.a]
  460.     }
  461. }
  462.  
  463. impl From<Color> for ([u8; 3], u8) {
  464.     #[inline]
  465.     fn from(color: Color) -> Self {
  466.         ([color.r, color.g, color.b], color.a)
  467.     }
  468. }
  469.  
  470. impl From<Color> for Vector4<u8> {
  471.     #[inline]
  472.     fn from(color: Color) -> Self {
  473.         Vector4::new(color.r, color.g, color.b, color.a)
  474.     }
  475. }
  476.  
  477. impl TryFrom<&[u8]> for Color {
  478.     type Error = Result<(Self, String), String>;
  479.  
  480.     fn try_from(color: &[u8]) -> Result<Self, Self::Error> {
  481.         match color.len() {
  482.             n if n < 3 => Err(Err(format!(
  483.                 "len should be at least 3, not {}",
  484.                 color.len()
  485.             ))),
  486.             3 => Err(Ok((
  487.                 Color::new(color[0], color[1], color[2], 255),
  488.                 String::from("fail to create a color with alpha component"),
  489.             ))),
  490.             _ => Ok(Color::new(color[0], color[1], color[2], color[3])),
  491.         }
  492.     }
  493. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement