1 //Возможно, этому модулю подойдет другое имя
2 module rip.concepts.makers;
3 
4 protected {
5     import std.stdio;
6     import std.math;
7 
8     import rip.concepts.color;
9 }
10 
11 /++
12     Funcs for translating color formats to RGBColor
13 +/
14 
15 RGBColor    makeHSV(in float h, lazy float s, lazy float v)
16 in {
17     if(!isNaN(h)) {
18         assert(h >= 0 && h <= 360,
19             "H must belong to the segment [0, 360] or be NAN");
20         assert(s >= 0 && s <= 1,
21             "S must belong to the segment [0, 1]");
22         assert(v >= 0 && v <= 1,
23             "V must belong to the segment [0, 1]");
24     }
25 }
26 body {
27     if(isNaN(h))
28         return new RGBColor(0, 0, 0);
29     else {
30 
31         float c = v * s;
32         float _h = h / 60;
33         float x = c * (1 - abs(_h % 2 - 1));
34         float m = v - c;
35 
36         float _r = 0, _g = 0, _b = 0;
37 
38         if(_h >= 0 && _h < 1) {
39             _r = c;
40             _g = x;
41         }
42         else if(_h < 2) {
43             _r = x;
44             _g = c;
45         }
46         else if(_h < 3) {
47             _g = c;
48             _b = x;
49         }
50         else if(_h < 4) {
51             _g = x;
52             _b = c;
53         }
54         else if(_h < 5) {
55             _r = x;
56             _b = c;
57         }
58         else {
59             _r = c;
60             _b = x;
61         }
62 
63         return new RGBColor(
64             round((_r + m) * 255),
65             round((_g + m) * 255),
66             round((_b + m) * 255));
67     }
68 
69     assert(0);
70 }
71 
72 /++ ditto +/
73 //Две практически одинаковые ф-ции в модуле. Надо
74 //подумать об их объединении
75 RGBColor    makeHSL(in float h, lazy float s, lazy float l)
76 in {
77     if(!isNaN(h)) {
78         assert(h >= 0 && h < 360,
79             "H must belong to the segment [0, 360) or be NAN");
80         assert(s >= 0 && s <= 1,
81             "S must belong to the segment [0, 1]");
82         assert(l >= 0 && l <= 1,
83             "L must belong to the segment [0, 1]");
84     }
85 }
86 body {
87     if(isNaN(h))
88         return new RGBColor(0, 0, 0);
89     else {
90 
91         float c = (1 - abs(2 * l - 1)) * s;
92         float _h = h / 60;
93         float x = c * (1 - abs(_h % 2 - 1));
94         float m = l - c / 2;
95 
96         float _r = 0, _g = 0, _b = 0;
97 
98         if(_h >= 0 && _h < 1) {
99             _r = c;
100             _g = x;
101         }
102         else if(_h < 2) {
103             _r = x;
104             _g = c;
105         }
106         else if(_h < 3) {
107             _g = c;
108             _b = x;
109         }
110         else if(_h < 4) {
111             _g = x;
112             _b = c;
113         }
114         else if(_h < 5) {
115             _r = x;
116             _b = c;
117         }
118         else {
119             _r = c;
120             _b = x;
121         }
122 
123         return new RGBColor(
124             round((_r + m) * 255),
125             round((_g + m) * 255),
126             round((_b + m) * 255));
127     }
128 
129     assert(0);
130 }
131 
132 /++ ditto +/
133 RGBColor makeCMYK(in float c, in float m, in float y, in float k)
134 in {
135     assert(c >= 0 && c <= 1,
136         "C must belong to the segment [0, 1]");
137     assert(m >= 0 && m <= 1,
138         "M must belong to the segment [0, 1]");
139     assert(y >= 0 && y <= 1,
140         "Y must belong to the segment [0, 1]");
141     assert(k >= 0 && k <= 1,
142         "K must belong to the segment [0, 1]");
143 }
144 body {
145     return new RGBColor(
146         round(255 * (1 - c) * (1 - k)),
147         round(255 * (1 - m) * (1 - k)),
148         round(255 * (1 - y) * (1 - k)));
149 }
150 
151 /++ ditto +/
152 RGBColor makeXYZ(float x, float y, float z)
153 in {
154     assert(x >= 0 && x <= 95.047f,
155         "x must belong to the segment [0, 95.047]");
156     assert(y >= 0 && y <= 100,
157         "y must belong to the segment [0, 100]");
158     assert(z >= 0 && z <= 108.883f,
159         "z must belong to the segment [0, 108.883]");
160 }
161 body {
162     x /= 100.0f;
163     y /= 100.0f;
164     z /= 100.0f;
165 
166     auto r = x * 3.2406 + y * -1.5372 + z * -0.4986;
167     auto g = x * -0.9689 + y * 1.8758 + z * 0.0415;
168     auto b = x * 0.0557 + y * -0.2040 + z * 1.0570;
169 
170     r = r > 0.0031308 ? 1.055 * pow(r, 1 / 2.4) - 0.055 : 12.92 * r;
171     g = g > 0.0031308 ? 1.055 * pow(g, 1 / 2.4) - 0.055 : 12.92 * g;
172     b = b > 0.0031308 ? 1.055 * pow(b, 1 / 2.4) - 0.055 : 12.92 * b;
173 
174     return new RGBColor(r * 255.0f, g * 255.0f, b * 255.0f);
175 }
176 
177 /++ ditto +/
178 RGBColor makeLAB(float l, float a, float b)
179 in {}
180 body {
181     const float E = 0.008856f;
182     const float K = 903.3f;
183 
184     auto wX = 95.047f;
185     auto wY = 100.0f;
186     auto wZ = 108.883f;
187 
188     float _y = (l + 16) / 116;
189     float _x = a / 500 + _y;
190     float _z = _y - b / 200;
191 
192     auto y3 = pow(_y, 3);
193     auto x3 = pow(_x, 3);
194     auto z3 = pow(_z, 3);
195 
196     if(y3 > E)
197         _y = y3;
198     else
199         _y = (_y - 16 / 116 ) / 7.787;
200 
201     if(x3 > E)
202         _x = x3;
203     else
204         _x = (_x - 16 / 116 ) / 7.787;
205 
206     if(z3 > E)
207         _z = z3;
208     else
209         _z = (_z - 16 / 116 ) / 7.787;
210 
211     _x *= wX;
212     _y *= wY;
213     _z *= wZ;
214 
215     return makeXYZ(_x, _y, _z);
216 }
217 
218 unittest {
219     auto color = makeHSV(72, 0.83, 0.73);
220 
221     assert(color.red!ubyte == 155);
222     assert(color.green!ubyte == 186);
223     assert(color.blue!ubyte == 32);
224 
225     float emptyFloat;
226     color = makeHSV(emptyFloat, 0.45, 0.6);
227 
228     assert(color.red!ubyte == 0);
229     assert(color.green!ubyte == 0);
230     assert(color.blue!ubyte == 0);
231 }