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 pragma(inline, true) pure this(float in_r, float in_g, float in_b) {
69 r = cast(ubyte)(in_r * 255.8);
70 g = cast(ubyte)(in_g * 255.8);
71 b = cast(ubyte)(in_b * 255.8);
75 pure this(string hexcolour
, bool hasvalidated
=false) {
76 // strip leading #, if present
77 if ((hexcolour
.length
== 7) ||
(hexcolour
.length
== 4)) {
78 hexcolour
= hexcolour
[1..$];
82 if (hexcolour
.length
== 6) {
83 r
= hexcolour
[0..2].to
!ubyte(16);
84 g
= hexcolour
[2..4].to
!ubyte(16);
85 b
= hexcolour
[4..6].to
!ubyte(16);
87 // The ranges here are to get a string just one character long so to!ubyte works
88 r
= cast(ubyte)(hexcolour
[0..1].to
!ubyte(16)*16);
89 g
= cast(ubyte)(hexcolour
[1..2].to
!ubyte(16)*16);
90 b
= cast(ubyte)(hexcolour
[2..3].to
!ubyte(16)*16);
93 throw new InternalError("RGBColour constructor called but rgbcolour not validated!");
97 // shamelessly stolen from https://github.com/adamdruppe/arsd/blob/master/color.d#L448
99 pure this(HSLColour hsl
) {
100 nothrow @safe @nogc pure real absInternal(real a
) { return a
< 0 ?
-a
: a
; }
101 real h
= hsl
.h
, s
= hsl
.s
, l
= hsl
.l
;
105 real C
= (1 - absInternal(2 * l
- 1)) * s
;
107 real hPrime
= h
/ 60;
109 real X
= C
* (1 - absInternal(hPrime
% 2 - 1));
111 real tmpr
, tmpg
, tmpb
;
114 tmpr
= tmpg
= tmpb
= 0;
115 } else if (hPrime
>= 0 && hPrime
< 1) {
119 } else if (hPrime
>= 1 && hPrime
< 2) {
123 } else if (hPrime
>= 2 && hPrime
< 3) {
127 } else if (hPrime
>= 3 && hPrime
< 4) {
131 } else if (hPrime
>= 4 && hPrime
< 5) {
135 } else if (hPrime
>= 5 && hPrime
< 6) {
147 r
= cast(ubyte)(tmpr
* 255);
148 g
= cast(ubyte)(tmpg
* 255);
149 b
= cast(ubyte)(tmpb
* 255);
152 pragma(inline
, true) this(string hexcolour
) {
153 if (!isvalidcolour(hexcolour
)) {
154 throw new InternalError("RGBColour constructor called with faulty colour.");
156 this(hexcolour
, true);
159 pragma(inline
, true) pure uint toint() {
160 return (255 << 24) |
(r
<< 16) |
(g
<< 8) | b
;
164 RGBColour
darken(ubyte level
) {
166 tmp
.r
= cast(ubyte) ((r
< level
) ?
0 : r
-level
);
167 tmp
.g
= cast(ubyte) ((g
< level
) ?
0 : g
-level
);
168 tmp
.b
= cast(ubyte) ((b
< level
) ?
0 : b
-level
);
173 RGBColour
lighten(ubyte level
) {
176 tmp
.r
= cast(ubyte) (((255-r
) < level
) ?
255 : r
+level
);
177 tmp
.g
= cast(ubyte) (((255-g
) < level
) ?
255 : g
+level
);
178 tmp
.b
= cast(ubyte) (((255-b
) < level
) ?
255 : b
+level
);
192 private import std
.traits
: isFloatingPoint
;
193 pure this(T
)(T h
, T s
, T l
) if (isFloatingPoint
!T
) {
194 this.h
= cast(real)h
;
195 this.s
= cast(real)s
;
196 this.l
= cast(real)l
;
199 // stolen from https://github.com/adamdruppe/arsd/blob/master/color.d#L501
200 pure this(RGBColour rgb
) {
201 pragma(inline
, true) {
202 real maxInternal(real a
, real b
, real c
) {
208 real minInternal(real a
, real b
, real c
) {
216 real r1
= cast(real) rgb
.r
/ 255.0;
217 real g1
= cast(real) rgb
.g
/ 255.0;
218 real b1
= cast(real) rgb
.b
/ 255.0;
220 real maxColor
= maxInternal(r1
, g1
, b1
);
221 real minColor
= minInternal(r1
, g1
, b1
);
223 real tmpl
= (maxColor
+ minColor
) / 2;
227 if (maxColor
!= minColor
) {
229 tmps
= (maxColor
- minColor
) / (maxColor
+ minColor
);
231 tmps
= (maxColor
- minColor
) / (2.0 - maxColor
- minColor
);
234 tmph
= (g1
-b1
) / (maxColor
- minColor
);
235 } else if(g1
== maxColor
) {
236 tmph
= 2.0 + (b1
- r1
) / (maxColor
- minColor
);
238 tmph
= 4.0 + (r1
- g1
) / (maxColor
- minColor
);