6 bool isvalidcolour(string hexcolour
) {
10 if (hexcolour
[0] == '#') {
14 for (;index
< hexcolour
.length
; index
++) {
15 nam
= hexcolour
[index
];
20 if (!((('0' <= nam
) && (nam
<= '9')) ||
(('A' <= nam
) && (nam
<= 'F')))) {
34 bool isvalidcolour(string hexcolour
) {
35 import std
.regex
: ctRegex
, matchFirst
;
36 auto hexcolourmatch
= ctRegex
!("#?[0-9a-fA-F]{3,6}");
38 if (matchFirst(hexcolour
, hexcolourmatch
).empty
) {
47 ubyte r
=0xFF, g
=0xFF, b
=0xFF;
48 pragma(inline
, true) pure this(ubyte in_r
, ubyte in_g
, ubyte in_b
) {
55 // No constructor for colours of the form 0xFFF, because there's no way to tell the difference between 0xFFF and 0x000FFF
56 pragma(inline
, true) pure this(uint clr
) {
59 /* An interesting optimization. Ordinarily, you do b = clr % 256,
60 * g = (clr / 256) % 256, r = (clr / 256 / 256) % 256. left/right
61 * shifts are cheaper than multiplication, and by reassigning clr,
62 * there's an extra multiplication step that doesn't occur.
64 g
= (clr
>>= 8) % 256;
68 pure this(string hexcolour
, bool hasvalidated
=false) {
69 // strip leading #, if present
70 if ((hexcolour
.length
== 7) ||
(hexcolour
.length
== 4)) {
71 hexcolour
= hexcolour
[1..$];
75 if (hexcolour
.length
== 6) {
76 r
= hexcolour
[0..2].to
!ubyte(16);
77 g
= hexcolour
[2..4].to
!ubyte(16);
78 b
= hexcolour
[4..6].to
!ubyte(16);
80 // The ranges here are to get a string just one character long so to!ubyte works
81 r
= cast(ubyte)(hexcolour
[0..1].to
!ubyte(16)*16);
82 g
= cast(ubyte)(hexcolour
[1..2].to
!ubyte(16)*16);
83 b
= cast(ubyte)(hexcolour
[2..3].to
!ubyte(16)*16);
86 throw new InternalError("RGBColour constructor called but rgbcolour not validated!");
90 // shamelessly stolen from https://github.com/adamdruppe/arsd/blob/master/color.d#L448
92 pure this(HSLColour hsl
) {
93 nothrow @safe @nogc pure real absInternal(real a
) { return a
< 0 ?
-a
: a
; }
94 real h
= hsl
.h
, s
= hsl
.s
, l
= hsl
.l
;
98 real C
= (1 - absInternal(2 * l
- 1)) * s
;
100 real hPrime
= h
/ 60;
102 real X
= C
* (1 - absInternal(hPrime
% 2 - 1));
104 real tmpr
, tmpg
, tmpb
;
107 tmpr
= tmpg
= tmpb
= 0;
108 } else if (hPrime
>= 0 && hPrime
< 1) {
112 } else if (hPrime
>= 1 && hPrime
< 2) {
116 } else if (hPrime
>= 2 && hPrime
< 3) {
120 } else if (hPrime
>= 3 && hPrime
< 4) {
124 } else if (hPrime
>= 4 && hPrime
< 5) {
128 } else if (hPrime
>= 5 && hPrime
< 6) {
140 r
= cast(ubyte)(tmpr
* 255);
141 g
= cast(ubyte)(tmpg
* 255);
142 b
= cast(ubyte)(tmpb
* 255);
145 pragma(inline
, true) this(string hexcolour
) {
146 if (!isvalidcolour(hexcolour
)) {
147 throw new InternalError("RGBColour constructor called with faulty colour.");
149 this(hexcolour
, true);
152 pragma(inline
, true) pure uint toint() {
153 return (255 << 24) |
(r
<< 16) |
(g
<< 8) | b
;
157 RGBColour
darken(ubyte level
) {
159 tmp
.r
= cast(ubyte) ((r
< level
) ?
0 : r
-level
);
160 tmp
.g
= cast(ubyte) ((g
< level
) ?
0 : g
-level
);
161 tmp
.b
= cast(ubyte) ((b
< level
) ?
0 : b
-level
);
166 RGBColour
lighten(ubyte level
) {
169 tmp
.r
= cast(ubyte) (((255-r
) < level
) ?
255 : r
+level
);
170 tmp
.g
= cast(ubyte) (((255-g
) < level
) ?
255 : g
+level
);
171 tmp
.b
= cast(ubyte) (((255-b
) < level
) ?
255 : b
+level
);
185 // stolen from https://github.com/adamdruppe/arsd/blob/master/color.d#L501
186 pure this(RGBColour rgb
) {
187 pragma(inline
, true) {
188 real maxInternal(real a
, real b
, real c
) {
194 real minInternal(real a
, real b
, real c
) {
202 real r1
= cast(real) rgb
.r
/ 255.0;
203 real g1
= cast(real) rgb
.g
/ 255.0;
204 real b1
= cast(real) rgb
.b
/ 255.0;
206 real maxColor
= maxInternal(r1
, g1
, b1
);
207 real minColor
= minInternal(r1
, g1
, b1
);
209 real tmpl
= (maxColor
+ minColor
) / 2;
213 if (maxColor
!= minColor
) {
215 tmps
= (maxColor
- minColor
) / (maxColor
+ minColor
);
217 tmps
= (maxColor
- minColor
) / (2.0 - maxColor
- minColor
);
220 tmph
= (g1
-b1
) / (maxColor
- minColor
);
221 } else if(g1
== maxColor
) {
222 tmph
= 2.0 + (b1
- r1
) / (maxColor
- minColor
);
224 tmph
= 4.0 + (r1
- g1
) / (maxColor
- minColor
);