1 module skia.SKColorF; 2 3 import skia.Definitions; 4 import skia.SkiaApi; 5 import skia.SKColor; 6 7 import std.algorithm; 8 import std.math; 9 10 struct SKColorF 11 { 12 enum float EPSILON = 0.001f; 13 14 enum SKColorF Empty = SKColorF(0, 0, 0, 0); 15 16 this(float red, float green, float blue) 17 { 18 fR = red; 19 fG = green; 20 fB = blue; 21 fA = 1f; 22 } 23 24 this(float red, float green, float blue, float alpha) 25 { 26 fR = red; 27 fG = green; 28 fB = blue; 29 fA = alpha; 30 } 31 32 // float fR 33 private const float fR; 34 const float Red() { 35 return fR; 36 } 37 38 // float fG 39 private const float fG; 40 const float Green() { 41 return fG; 42 } 43 44 // float fB 45 private const float fB; 46 const float Blue() { 47 return fB; 48 } 49 50 // float fA 51 private const float fA; 52 const float Alpha() { 53 return fA; 54 } 55 56 // const bool Equals (SKColorF obj) { 57 // return fR == obj.fR && fG == obj.fG && fB == obj.fB && fA == obj.fA 58 // } 59 60 // const override bool Equals (object obj) { 61 // return obj is SKColorF f && Equals (f) 62 // } 63 64 // static bool operator == (SKColorF left, SKColorF right) { 65 // return left.Equals (right) 66 // } 67 68 // static bool operator != (SKColorF left, SKColorF right) { 69 // return !left.Equals (right) 70 // } 71 72 // const override int GetHashCode () 73 // { 74 // var hash = new HashCode (); 75 // hash.Add (fR); 76 // hash.Add (fG); 77 // hash.Add (fB); 78 // hash.Add (fA); 79 // return hash.ToHashCode (); 80 // } 81 82 SKColorF WithRed(float red) 83 { 84 return SKColorF(red, fG, fB, fA); 85 } 86 87 SKColorF WithGreen(float green) 88 { 89 return SKColorF(fR, green, fB, fA); 90 } 91 92 SKColorF WithBlue(float blue) 93 { 94 return SKColorF(fR, fG, blue, fA); 95 } 96 97 SKColorF WithAlpha(float alpha) 98 { 99 return SKColorF(fR, fG, fB, alpha); 100 } 101 102 float Hue() 103 { 104 float h; 105 float s; 106 float v; 107 ToHsv(h, s, v); 108 return h; 109 } 110 111 SKColorF Clamp() 112 { 113 return SKColorF(Clamp(fR), Clamp(fG), Clamp(fB), Clamp(fA)); 114 115 116 } 117 118 private static float Clamp(float v) 119 { 120 if (v > 1f) 121 return 1f; 122 if (v < 0f) 123 return 0f; 124 return v; 125 } 126 127 static SKColorF FromHsl(float h, float s, float l, float a = 1f) 128 { 129 // convert from percentages 130 h = h / 360f; 131 s = s / 100f; 132 l = l / 100f; 133 134 // RGB results from 0 to 1 135 auto r = l; 136 auto g = l; 137 auto b = l; 138 139 // HSL from 0 to 1 140 if (abs(s) > EPSILON) 141 { 142 float v2; 143 if (l < 0.5f) 144 v2 = l * (1f + s); 145 else 146 v2 = (l + s) - (s * l); 147 148 auto v1 = 2f * l - v2; 149 150 r = HueToRgb(v1, v2, h + (1f / 3f)); 151 g = HueToRgb(v1, v2, h); 152 b = HueToRgb(v1, v2, h - (1f / 3f)); 153 } 154 155 return SKColorF(r, g, b, a); 156 } 157 158 private static float HueToRgb(float v1, float v2, float vH) 159 { 160 if (vH < 0f) 161 vH += 1f; 162 if (vH > 1f) 163 vH -= 1f; 164 165 if ((6f * vH) < 1f) 166 return (v1 + (v2 - v1) * 6f * vH); 167 if ((2f * vH) < 1f) 168 return (v2); 169 if ((3f * vH) < 2f) 170 return (v1 + (v2 - v1) * ((2f / 3f) - vH) * 6f); 171 return (v1); 172 } 173 174 static SKColorF FromHsv(float h, float s, float v, float a = 1f) 175 { 176 // convert from percentages 177 h = h / 360f; 178 s = s / 100f; 179 v = v / 100f; 180 181 // RGB results from 0 to 1 182 auto r = v; 183 auto g = v; 184 auto b = v; 185 186 // HSL from 0 to 1 187 if (abs(s) > EPSILON) 188 { 189 h = h * 6f; 190 if (abs(h - 6f) < EPSILON) 191 h = 0f; // H must be < 1 192 193 int hInt = cast(int) h; 194 auto v1 = v * (1f - s); 195 auto v2 = v * (1f - s * (h - hInt)); 196 auto v3 = v * (1f - s * (1f - (h - hInt))); 197 198 if (hInt == 0) 199 { 200 r = v; 201 g = v3; 202 b = v1; 203 } 204 else if (hInt == 1) 205 { 206 r = v2; 207 g = v; 208 b = v1; 209 } 210 else if (hInt == 2) 211 { 212 r = v1; 213 g = v; 214 b = v3; 215 } 216 else if (hInt == 3) 217 { 218 r = v1; 219 g = v2; 220 b = v; 221 } 222 else if (hInt == 4) 223 { 224 r = v3; 225 g = v1; 226 b = v; 227 } 228 else 229 { 230 r = v; 231 g = v1; 232 b = v2; 233 } 234 } 235 236 return SKColorF(r, g, b, a); 237 } 238 239 void ToHsl(ref float h, ref float s, ref float l) 240 { 241 // RGB from 0 to 1 242 auto r = fR; 243 auto g = fG; 244 auto b = fB; 245 246 auto min = std.algorithm.min(std.algorithm.min(r, g), b); // min value of RGB 247 auto max = std.algorithm.max(std.algorithm.max(r, g), b); // max value of RGB 248 auto delta = max - min; // delta RGB value 249 250 // default to a gray, no chroma... 251 h = 0f; 252 s = 0f; 253 l = (max + min) / 2f; 254 255 // chromatic data... 256 if (abs(delta) > EPSILON) 257 { 258 if (l < 0.5f) 259 s = delta / (max + min); 260 else 261 s = delta / (2f - max - min); 262 263 auto deltaR = (((max - r) / 6f) + (delta / 2f)) / delta; 264 auto deltaG = (((max - g) / 6f) + (delta / 2f)) / delta; 265 auto deltaB = (((max - b) / 6f) + (delta / 2f)) / delta; 266 267 if (abs(r - max) < EPSILON) // r == max 268 h = deltaB - deltaG; 269 else if (abs(g - max) < EPSILON) // g == max 270 h = (1f / 3f) + deltaR - deltaB; 271 else // b == max 272 h = (2f / 3f) + deltaG - deltaR; 273 274 if (h < 0f) 275 h += 1f; 276 if (h > 1f) 277 h -= 1f; 278 } 279 280 // convert to percentages 281 h = h * 360f; 282 s = s * 100f; 283 l = l * 100f; 284 } 285 286 void ToHsv(ref float h, ref float s, ref float v) 287 { 288 // RGB from 0 to 1 289 auto r = fR; 290 auto g = fG; 291 auto b = fB; 292 293 auto min = std.algorithm.min(std.algorithm.min(r, g), b); // min value of RGB 294 auto max = std.algorithm.max(std.algorithm.max(r, g), b); // max value of RGB 295 auto delta = max - min; // delta RGB value 296 297 // default to a gray, no chroma... 298 h = 0; 299 s = 0; 300 v = max; 301 302 // chromatic data... 303 if (abs(delta) > EPSILON) 304 { 305 s = delta / max; 306 307 auto deltaR = (((max - r) / 6f) + (delta / 2f)) / delta; 308 auto deltaG = (((max - g) / 6f) + (delta / 2f)) / delta; 309 auto deltaB = (((max - b) / 6f) + (delta / 2f)) / delta; 310 311 if (abs(r - max) < EPSILON) // r == max 312 h = deltaB - deltaG; 313 else if (abs(g - max) < EPSILON) // g == max 314 h = (1f / 3f) + deltaR - deltaB; 315 else // b == max 316 h = (2f / 3f) + deltaG - deltaR; 317 318 if (h < 0f) 319 h += 1f; 320 if (h > 1f) 321 h -= 1f; 322 } 323 324 // convert to percentages 325 h = h * 360f; 326 s = s * 100f; 327 v = v * 100f; 328 } 329 330 string ToString() 331 { 332 return (cast(SKColor) this).ToString(); 333 } 334 335 SKColor opCast(T)() if (is(T == SKColor)) 336 { 337 return SKColor(SkiaApi.sk_color4f_to_color(&this)); 338 } 339 340 }