1 module des.util.colorparse;
2 
3 ///
4 ulong hex2ulong( string hex )
5 {
6     import std..string;
7 
8     enum tbl = [ '0':  0, '1':  1, '2':  2, '3':  3, 
9                  '4':  4, '5':  5, '6':  6, '7':  7, 
10                  '8':  8, '9':  9, 'A': 10, 'B': 11, 
11                  'C': 12, 'D': 13, 'E': 14, 'F': 15 ];
12 
13     ulong ret = 0;
14     size_t i = 0;
15     auto uHex = toUpper( hex );
16     foreach_reverse( c; uHex )
17         ret += tbl[c] << (4 * i++);
18 
19     return ret;
20 }
21 
22 ///
23 T[4] parseColorStr(T=float)( string cstr, real norm=1 )
24 {
25     if( cstr[0] == '#' )
26         cstr = cstr[ 1 .. $ ];
27     else if( cstr[0] == '0' && cstr[1] == 'x' )
28         cstr = cstr[ 2 .. $ ];
29     else
30         throw new Exception( "unsupported hex color string (format): '" ~ cstr ~ "'" );
31 
32     ulong shortWrite = 0;
33     bool alpha = false;
34     switch( cstr.length )
35     {
36         case 1:
37             shortWrite = 2;
38             break;
39         case 2:
40             shortWrite = 3;
41             alpha = true;
42             break;
43         case 3:
44             shortWrite = 1;
45             break;
46         case 4:
47             shortWrite = 1;
48             alpha = true;
49             break;
50         case 6: break;
51         case 8:
52             alpha = true;
53             break;
54         default: 
55             throw new Exception( "unsupported hex color string (length): '" ~ cstr ~ "'" );
56     }
57 
58     if( shortWrite == 1 )
59     {
60         string buf;
61 
62         foreach( c; cstr )
63             buf ~= [c,c];
64 
65         cstr = buf;
66     }
67     else if( shortWrite >= 2 )
68     {
69         string buf;
70 
71         buf ~= [ cstr[0], cstr[0], cstr[0], cstr[0], cstr[0], cstr[0] ];
72 
73         if( shortWrite == 3 )
74             buf ~= [ cstr[1], cstr[1] ];
75 
76         cstr = buf;
77     }
78 
79     ulong val = hex2ulong( cstr );
80 
81     enum compbits = byte.sizeof * 8;
82     enum compmask = 0xFF;
83 
84     auto k = norm / cast(real)(compmask);
85     auto cr = cast(T)( ( ( val >> ( ( 2 + alpha ) * compbits ) ) & compmask ) * k );
86     auto cg = cast(T)( ( ( val >> ( ( 1 + alpha ) * compbits ) ) & compmask ) * k );
87     auto cb = cast(T)( ( ( val >> ( ( 0 + alpha ) * compbits ) ) & compmask ) * k );
88     auto ca = cast(T)( alpha ? ( val & compmask ) * k : norm );
89 
90     return [ cr, cg, cb, ca ];
91 }
92 
93 ///
94 unittest
95 {
96     assert( [1.0f,0,1,0] == parseColorStr( "#FF00FF00" ) );
97     assert( [1.0f,0,1,1] == parseColorStr( "#FF00FF" ) );
98     assert( [1.0f,0,1,0] == parseColorStr( "#F0F0" ) );
99     assert( [1.0f,0,1,1] == parseColorStr( "#F0F" ) );
100     assert( [1.0f,1,1,0] == parseColorStr( "#F0" ) );
101     assert( [1.0f,1,1,1] == parseColorStr( "#F" ) );
102     assert( [0.0f,0,0,1] == parseColorStr( "#0" ) );
103     assert( [1.0f,1,1,1] == parseColorStr( "0xF" ) );
104     assert( [0.0f,0,0,1] == parseColorStr( "0x0" ) );
105 
106     assert( [255,15,255,255] == parseColorStr!ubyte( "#FF0FFF", 255 ) );
107 }