1 #ifndef ENCODE_INCLUDED
2 #define ENCODE_INCLUDED
3 
4 #include <unordered_map>
5 #include <string>
6 #include "ColorSpace.h"
7 #include <R.h>
8 #define R_NO_REMAP
9 #include <Rinternals.h>
10 
11 #define OP_SET 1
12 #define OP_ADD 2
13 #define OP_MULT 3
14 #define OP_LEAST 4
15 #define OP_MOST 5
16 
mod_val(double val,double mod,int op)17 inline double mod_val(double val, double mod, int op) {
18   switch (op) {
19   case OP_SET: return mod;
20   case OP_ADD: return val + mod;
21   case OP_MULT: return val * mod;
22   case OP_LEAST: return val < mod ? mod : val;
23   case OP_MOST: return val > mod ? mod : val;
24   }
25   return val;
26 }
27 
28 struct rgb_colour {
29   int r;
30   int g;
31   int b;
32   int a;
33 };
34 typedef std::unordered_map<std::string, rgb_colour> ColourMap;
35 
36 // Defined in init.cpp
37 ColourMap& get_named_colours();
38 
39 SEXP encode_c(SEXP colour, SEXP alpha, SEXP from, SEXP white);
40 SEXP decode_c(SEXP codes, SEXP alpha, SEXP to, SEXP white, SEXP na);
41 SEXP encode_channel_c(SEXP codes, SEXP channel, SEXP value, SEXP space, SEXP op, SEXP white, SEXP na);
42 SEXP decode_channel_c(SEXP codes, SEXP channel, SEXP space, SEXP white, SEXP na);
43 SEXP load_colour_names_c(SEXP name, SEXP value);
44 SEXP encode_native_c(SEXP color);
45 SEXP decode_native_c(SEXP native);
46 
47 template <typename Space>
48 inline void modify_channel(Space&, double value, int channel, int op);
49 
50 template <>
51 inline void modify_channel<ColorSpace::Rgb>(ColorSpace::Rgb& color, double value, int channel, int op){
52   switch (channel) {
53   case 1:
54     color.r = mod_val(color.r, value, op);
55     break;
56   case 2:
57     color.g = mod_val(color.g, value, op);
58     break;
59   case 3:
60     color.b = mod_val(color.b, value, op);
61     break;
62   }
63 }
64 
65 template <>
66 inline void modify_channel<ColorSpace::Xyz>(ColorSpace::Xyz& color, double value, int channel, int op){
67   switch (channel) {
68   case 1:
69     color.x = mod_val(color.x, value, op);
70     break;
71   case 2:
72     color.y = mod_val(color.y, value, op);
73     break;
74   case 3:
75     color.z = mod_val(color.z, value, op);
76     break;
77   }
78 }
79 
80 template <>
81 inline void modify_channel<ColorSpace::Hsl>(ColorSpace::Hsl& color, double value, int channel, int op){
82   switch (channel) {
83   case 1:
84     color.h = mod_val(color.h, value, op);
85     break;
86   case 2:
87     color.s = mod_val(color.s, value, op);
88     break;
89   case 3:
90     color.l = mod_val(color.l, value, op);
91     break;
92   }
93 }
94 
95 template <>
96 inline void modify_channel<ColorSpace::Lab>(ColorSpace::Lab& color, double value, int channel, int op){
97   switch (channel) {
98   case 1:
99     color.l = mod_val(color.l, value, op);
100     break;
101   case 2:
102     color.a = mod_val(color.a, value, op);
103     break;
104   case 3:
105     color.b = mod_val(color.b, value, op);
106     break;
107   }
108 }
109 
110 template <>
111 inline void modify_channel<ColorSpace::Lch>(ColorSpace::Lch& color, double value, int channel, int op){
112   switch (channel) {
113   case 1:
114     color.l = mod_val(color.l, value, op);
115     break;
116   case 2:
117     color.c = mod_val(color.c, value, op);
118     break;
119   case 3:
120     color.h = mod_val(color.h, value, op);
121     break;
122   }
123 }
124 
125 template <>
126 inline void modify_channel<ColorSpace::Luv>(ColorSpace::Luv& color, double value, int channel, int op){
127   switch (channel) {
128   case 1:
129     color.l = mod_val(color.l, value, op);
130     break;
131   case 2:
132     color.u = mod_val(color.u, value, op);
133     break;
134   case 3:
135     color.v = mod_val(color.v, value, op);
136     break;
137   }
138 }
139 
140 template <>
141 inline void modify_channel<ColorSpace::Yxy>(ColorSpace::Yxy& color, double value, int channel, int op){
142   switch (channel) {
143   case 1:
144     color.y1 = mod_val(color.y1, value, op);
145     break;
146   case 2:
147     color.x = mod_val(color.x, value, op);
148     break;
149   case 3:
150     color.y2 = mod_val(color.y2, value, op);
151     break;
152   }
153 }
154 
155 template <>
156 inline void modify_channel<ColorSpace::Cmy>(ColorSpace::Cmy& color, double value, int channel, int op){
157   switch (channel) {
158   case 1:
159     color.c = mod_val(color.c, value, op);
160     break;
161   case 2:
162     color.m = mod_val(color.m, value, op);
163     break;
164   case 3:
165     color.y = mod_val(color.y, value, op);
166     break;
167   }
168 }
169 
170 template <>
171 inline void modify_channel<ColorSpace::Cmyk>(ColorSpace::Cmyk& color, double value, int channel, int op){
172   switch (channel) {
173   case 1:
174     color.c = mod_val(color.c, value, op);
175     break;
176   case 2:
177     color.m = mod_val(color.m, value, op);
178     break;
179   case 3:
180     color.y = mod_val(color.y, value, op);
181     break;
182   case 4:
183     color.k = mod_val(color.k, value, op);
184     break;
185   }
186 }
187 
188 template <>
189 inline void modify_channel<ColorSpace::Hsv>(ColorSpace::Hsv& color, double value, int channel, int op){
190   switch (channel) {
191   case 1:
192     color.h = mod_val(color.h, value, op);
193     break;
194   case 2:
195     color.s = mod_val(color.s, value, op);
196     break;
197   case 3:
198     color.v = mod_val(color.v, value, op);
199     break;
200   }
201 }
202 
203 template <>
204 inline void modify_channel<ColorSpace::Hsb>(ColorSpace::Hsb& color, double value, int channel, int op){
205   switch (channel) {
206   case 1:
207     color.h = mod_val(color.h, value, op);
208     break;
209   case 2:
210     color.s = mod_val(color.s, value, op);
211     break;
212   case 3:
213     color.b = mod_val(color.b, value, op);
214     break;
215   }
216 }
217 
218 template <>
219 inline void modify_channel<ColorSpace::HunterLab>(ColorSpace::HunterLab& color, double value, int channel, int op){
220   switch (channel) {
221   case 1:
222     color.l = mod_val(color.l, value, op);
223     break;
224   case 2:
225     color.a = mod_val(color.a, value, op);
226     break;
227   case 3:
228     color.b = mod_val(color.b, value, op);
229     break;
230   }
231 }
232 
233 template <>
234 inline void modify_channel<ColorSpace::Hcl>(ColorSpace::Hcl& color, double value, int channel, int op){
235   switch (channel) {
236   case 1:
237     color.h = mod_val(color.h, value, op);
238     break;
239   case 2:
240     color.c = mod_val(color.c, value, op);
241     break;
242   case 3:
243     color.l = mod_val(color.l, value, op);
244     break;
245   }
246 }
247 
248 template <>
249 inline void modify_channel<ColorSpace::OkLab>(ColorSpace::OkLab& color, double value, int channel, int op){
250   switch (channel) {
251   case 1:
252     color.l = mod_val(color.l, value, op);
253     break;
254   case 2:
255     color.a = mod_val(color.a, value, op);
256     break;
257   case 3:
258     color.b = mod_val(color.b, value, op);
259     break;
260   }
261 }
262 
263 template <>
264 inline void modify_channel<ColorSpace::OkLch>(ColorSpace::OkLch& color, double value, int channel, int op){
265   switch (channel) {
266   case 1:
267     color.l = mod_val(color.l, value, op);
268     break;
269   case 2:
270     color.c = mod_val(color.c, value, op);
271     break;
272   case 3:
273     color.h = mod_val(color.h, value, op);
274     break;
275   }
276 }
277 
278 
279 template <typename Space>
280 inline double grab_channel(Space&,int channel);
281 
282 template <>
283 inline double grab_channel<ColorSpace::Rgb>(ColorSpace::Rgb& color, int channel){
284   switch (channel) {
285   case 1: return color.r;
286   case 2: return color.g;
287   case 3: return color.b;
288   }
289   return 0.0;
290 }
291 
292 template <>
293 inline double grab_channel<ColorSpace::Xyz>(ColorSpace::Xyz& color, int channel){
294   switch (channel) {
295   case 1: return color.x;
296   case 2: return color.y;
297   case 3: return color.z;
298   }
299   return 0.0;
300 }
301 
302 template <>
303 inline double grab_channel<ColorSpace::Hsl>(ColorSpace::Hsl& color, int channel){
304   switch (channel) {
305   case 1: return color.h;
306   case 2: return color.s;
307   case 3: return color.l;
308   }
309   return 0.0;
310 }
311 
312 template <>
313 inline double grab_channel<ColorSpace::Lab>(ColorSpace::Lab& color, int channel){
314   switch (channel) {
315   case 1: return color.l;
316   case 2: return color.a;
317   case 3: return color.b;
318   }
319   return 0.0;
320 }
321 
322 template <>
323 inline double grab_channel<ColorSpace::Lch>(ColorSpace::Lch& color, int channel){
324   switch (channel) {
325   case 1: return color.l;
326   case 2: return color.c;
327   case 3: return color.h;
328   }
329   return 0.0;
330 }
331 
332 template <>
333 inline double grab_channel<ColorSpace::Luv>(ColorSpace::Luv& color, int channel){
334   switch (channel) {
335   case 1: return color.l;
336   case 2: return color.u;
337   case 3: return color.v;
338   }
339   return 0.0;
340 }
341 
342 template <>
343 inline double grab_channel<ColorSpace::Yxy>(ColorSpace::Yxy& color, int channel){
344   switch (channel) {
345   case 1: return color.y1;
346   case 2: return color.x;
347   case 3: return color.y2;
348   }
349   return 0.0;
350 }
351 
352 template <>
353 inline double grab_channel<ColorSpace::Cmy>(ColorSpace::Cmy& color, int channel){
354   switch (channel) {
355   case 1: return color.c;
356   case 2: return color.m;
357   case 3: return color.y;
358   }
359   return 0.0;
360 }
361 
362 template <>
363 inline double grab_channel<ColorSpace::Cmyk>(ColorSpace::Cmyk& color, int channel){
364   switch (channel) {
365   case 1: return color.c;
366   case 2: return color.m;
367   case 3: return color.y;
368   case 4: return color.k;
369   }
370   return 0.0;
371 }
372 
373 template <>
374 inline double grab_channel<ColorSpace::Hsv>(ColorSpace::Hsv& color, int channel){
375   switch (channel) {
376   case 1: return color.h;
377   case 2: return color.s;
378   case 3: return color.v;
379   }
380   return 0.0;
381 }
382 
383 template <>
384 inline double grab_channel<ColorSpace::Hsb>(ColorSpace::Hsb& color, int channel){
385   switch (channel) {
386   case 1: return color.h;
387   case 2: return color.s;
388   case 3: return color.b;
389   }
390   return 0.0;
391 }
392 
393 template <>
394 inline double grab_channel<ColorSpace::HunterLab>(ColorSpace::HunterLab& color, int channel){
395   switch (channel) {
396   case 1: return color.l;
397   case 2: return color.a;
398   case 3: return color.b;
399   }
400   return 0.0;
401 }
402 
403 template <>
404 inline double grab_channel<ColorSpace::Hcl>(ColorSpace::Hcl& color, int channel){
405   switch (channel) {
406   case 1: return color.h;
407   case 2: return color.c;
408   case 3: return color.l;
409   }
410   return 0.0;
411 }
412 
413 template <>
414 inline double grab_channel<ColorSpace::OkLab>(ColorSpace::OkLab& color, int channel){
415   switch (channel) {
416   case 1: return color.l;
417   case 2: return color.a;
418   case 3: return color.b;
419   }
420   return 0.0;
421 }
422 
423 template <>
424 inline double grab_channel<ColorSpace::OkLch>(ColorSpace::OkLch& color, int channel){
425   switch (channel) {
426   case 1: return color.l;
427   case 2: return color.c;
428   case 3: return color.h;
429   }
430   return 0.0;
431 }
432 
433 #endif
434