1 module skia.SKColor; 2 3 import skia.SKColorF; 4 import skia.Exceptions; 5 6 import std.experimental.logger; 7 8 import std.conv; 9 import std.format; 10 import std.range; 11 import std..string; 12 13 struct SKColor { 14 enum SKColor Empty = SKColor(0); 15 16 private uint color; 17 18 this(uint value) { 19 color = value; 20 } 21 22 this(ubyte red, ubyte green, ubyte blue, ubyte alpha) { 23 color = cast(uint)((alpha << 24) | (red << 16) | (green << 8) | blue); 24 } 25 26 this(ubyte red, ubyte green, ubyte blue) { 27 color = (0xff000000u | cast(uint)(red << 16) | cast(uint)(green << 8) | blue); 28 } 29 30 SKColor WithRed(ubyte red) { 31 return SKColor(red, Green, Blue, Alpha); 32 } 33 34 SKColor WithGreen(ubyte green) { 35 return SKColor(Red, green, Blue, Alpha); 36 } 37 38 SKColor WithBlue(ubyte blue) { 39 return SKColor(Red, Green, blue, Alpha); 40 } 41 42 SKColor WithAlpha(ubyte alpha) { 43 return SKColor(Red, Green, Blue, alpha); 44 } 45 46 ubyte Alpha() { 47 return cast(ubyte)((color >> 24) & 0xff); 48 } 49 50 ubyte Red() { 51 return cast(ubyte)((color >> 16) & 0xff); 52 } 53 54 ubyte Green() { 55 return cast(ubyte)((color >> 8) & 0xff); 56 } 57 58 ubyte Blue() { 59 return cast(ubyte)((color) & 0xff); 60 } 61 62 float Hue() { 63 float h; 64 float s; 65 float v; 66 ToHsv(h, s, v); 67 return h; 68 } 69 70 static SKColor FromHsl(float h, float s, float l, ubyte a = cast(ubyte) 255) { 71 auto colorf = SKColorF.FromHsl(h, s, l); 72 73 // RGB results from 0 to 255 74 auto r = colorf.Red * 255f; 75 auto g = colorf.Green * 255f; 76 auto b = colorf.Blue * 255f; 77 78 return SKColor(cast(ubyte) r, cast(ubyte) g, cast(ubyte) b, a); 79 } 80 81 static SKColor FromHsv(float h, float s, float v, ubyte a = cast(ubyte) 255) { 82 auto colorf = SKColorF.FromHsv(h, s, v); 83 84 // RGB results from 0 to 255 85 auto r = colorf.Red * 255f; 86 auto g = colorf.Green * 255f; 87 auto b = colorf.Blue * 255f; 88 89 return SKColor(cast(ubyte) r, cast(ubyte) g, cast(ubyte) b, a); 90 } 91 92 void ToHsl(ref float h, ref float s, ref float l) { 93 // RGB from 0 to 255 94 auto r = Red / 255f; 95 auto g = Green / 255f; 96 auto b = Blue / 255f; 97 98 auto colorf = SKColorF(r, g, b); 99 colorf.ToHsl(h, s, l); 100 } 101 102 void ToHsv(ref float h, ref float s, ref float v) { 103 // RGB from 0 to 255 104 auto r = Red / 255f; 105 auto g = Green / 255f; 106 auto b = Blue / 255f; 107 108 auto colorf = SKColorF(r, g, b); 109 colorf.ToHsv(h, s, v); 110 } 111 112 string ToString() { 113 // return "#{Alpha:x2}{Red:x2}{Green:x2}{Blue:x2}"; 114 return format("#%02x%02x%02x%02x", Alpha, Red, Green, Blue); 115 } 116 117 // bool Equals(SKColor obj) 118 // { 119 // return obj.color == color; 120 // } 121 122 // override bool Equals(object other) 123 // { 124 // return other is SKColor f && Equals(f); 125 // } 126 127 // static bool operator == (SKColor left, SKColor right) 128 // { 129 // return left.Equals(right); 130 // } 131 132 // static bool operator != (SKColor left, SKColor right) 133 // { 134 // return !left.Equals(right); 135 // } 136 137 // override int GetHashCode() 138 // { 139 // return color.GetHashCode(); 140 // } 141 142 uint opCast(T)() if (is(T == uint)) { 143 return color; 144 } 145 146 static SKColor Parse(string hexString) { 147 SKColor color; 148 if (!TryParse(hexString, color)) 149 throw new ArgumentException("Invalid hexadecimal color string.", hexString.stringof); 150 return color; 151 } 152 153 static bool TryParse(string hexString, ref SKColor color) { 154 if (hexString.empty()) { 155 // error 156 color = SKColor.Empty; 157 return false; 158 } 159 160 // clean up string 161 hexString = hexString.strip().toUpper(); 162 if (hexString[0] == '#') 163 hexString = hexString[1 .. $]; 164 165 size_t len = hexString.length; 166 if (len == 3 || len == 4) { 167 ubyte a; 168 // parse [A] 169 if (len == 4) { 170 if (!tryParse(format("%c%c", hexString[len - 4], hexString[len - 4]), a)) { 171 // error 172 color = SKColor.Empty; 173 return false; 174 } 175 } else { 176 a = cast(ubyte) 255; 177 } 178 179 // parse RGB 180 ubyte r, g, b; 181 if (!tryParse(format("%c%c", hexString[len - 3], 182 hexString[len - 3]), r) || !tryParse(format("%c%c", hexString[len - 2], 183 hexString[len - 2]), g) || !tryParse(format("%c%c", 184 hexString[len - 1], hexString[len - 1]), b)) { 185 // error 186 color = SKColor.Empty; 187 return false; 188 } 189 190 // success 191 color = SKColor(r, g, b, a); 192 return true; 193 } 194 195 if (len == 6 || len == 8) { 196 // parse [AA]RRGGBB 197 uint number = 0; 198 199 if (!tryParse(hexString, number)) { 200 // error 201 color = SKColor.Empty; 202 return false; 203 } 204 205 // success 206 color = SKColor(number); 207 208 // alpha was not provided, so use 255 209 if (len == 6) { 210 color = color.WithAlpha(cast(ubyte) 255); 211 } 212 return true; 213 } 214 215 // error 216 color = SKColor.Empty; 217 return false; 218 } 219 220 // parse [AA]RRGGBB 221 static bool tryParse(string hexString, out uint color) { 222 try { 223 color = to!uint(hexString, 16); 224 return true; 225 } catch (Exception ex) { 226 warningf("Hex: %s, Error: %s", hexString, ex.msg); 227 return false; 228 } 229 } 230 231 // parse CC 232 static bool tryParse(string hexString, out ubyte data) { 233 try { 234 data = to!ubyte(hexString, 16); 235 return true; 236 } catch (Exception ex) { 237 warningf("Hex: %s, Error: %s", hexString, ex.msg); 238 return false; 239 } 240 } 241 242 SKColorF opCast(T)() if (is(T == SKColorF)) { 243 SKColorF colorF; 244 SkiaApi.sk_color4f_from_color(color, &colorF); 245 return colorF; 246 } 247 }