1 // Written in the D programming language.
2 
3 /**
4 This module contains declaration of useful color related operations.
5 
6 In dlangui, colors are represented as 32 bit uint AARRGGBB values.
7 
8 Synopsis:
9 
10 ----
11 import dlangui.graphics.colors;
12 
13 ----
14 
15 Copyright: Vadim Lopatin, 2015
16 License:   Boost License 1.0
17 Authors:   Vadim Lopatin, coolreader.org@gmail.com
18 */
19 module dlangui.graphics.colors;
20 
21 import dlangui.core.types;
22 
23 private import std.string : strip;
24 
25 /// special color constant to identify value as not a color (to use default/parent value instead)
26 immutable uint COLOR_UNSPECIFIED = 0xFFDEADFF;
27 /// transparent color constant
28 immutable uint COLOR_TRANSPARENT = 0xFFFFFFFF;
29 
30 immutable string COLOR_DRAWABLE = "#color";
31 
32 /// Color constants enum, contributed by zhaopuming
33 /// refer to http://rapidtables.com/web/color/RGB_Color.htm#color%20table
34 /// #275
35 enum Color {
36     maroon = 0x800000,
37     dark_red = 0x8B0000,
38     brown = 0xA52A2A,
39     firebrick = 0xB22222,
40     crimson = 0xDC143C,
41     red = 0xFF0000,
42     tomato = 0xFF6347,
43     coral = 0xFF7F50,
44     indian_red = 0xCD5C5C,
45     light_coral = 0xF08080,
46     dark_salmon = 0xE9967A,
47     salmon = 0xFA8072,
48     light_salmon = 0xFFA07A,
49     orange_red = 0xFF4500,
50     dark_orange = 0xFF8C00,
51     orange = 0xFFA500,
52     gold = 0xFFD700,
53     dark_golden_rod = 0xB8860B,
54     golden_rod = 0xDAA520,
55     pale_golden_rod = 0xEEE8AA,
56     dark_khaki = 0xBDB76B,
57     khaki = 0xF0E68C,
58     olive = 0x808000,
59     yellow = 0xFFFF00,
60     yellow_green = 0x9ACD32,
61     dark_olive_green = 0x556B2F,
62     olive_drab = 0x6B8E23,
63     lawn_green = 0x7CFC00,
64     chart_reuse = 0x7FFF00,
65     green_yellow = 0xADFF2F,
66     dark_green = 0x006400,
67     green = 0x008000,
68     forest_green = 0x228B22,
69     lime = 0x00FF00,
70     lime_green = 0x32CD32,
71     light_green = 0x90EE90,
72     pale_green = 0x98FB98,
73     dark_sea_green = 0x8FBC8F,
74     medium_spring_green = 0x00FA9A,
75     spring_green = 0x00FF7F,
76     sea_green = 0x2E8B57,
77     medium_aqua_marine = 0x66CDAA,
78     medium_sea_green = 0x3CB371,
79     light_sea_green = 0x20B2AA,
80     dark_slate_gray = 0x2F4F4F,
81     teal = 0x008080,
82     dark_cyan = 0x008B8B,
83     aqua = 0x00FFFF,
84     cyan = 0x00FFFF,
85     light_cyan = 0xE0FFFF,
86     dark_turquoise = 0x00CED1,
87     turquoise = 0x40E0D0,
88     medium_turquoise = 0x48D1CC,
89     pale_turquoise = 0xAFEEEE,
90     aqua_marine = 0x7FFFD4,
91     powder_blue = 0xB0E0E6,
92     cadet_blue = 0x5F9EA0,
93     steel_blue = 0x4682B4,
94     corn_flower_blue = 0x6495ED,
95     deep_sky_blue = 0x00BFFF,
96     dodger_blue = 0x1E90FF,
97     light_blue = 0xADD8E6,
98     sky_blue = 0x87CEEB,
99     light_sky_blue = 0x87CEFA,
100     midnight_blue = 0x191970,
101     navy = 0x000080,
102     dark_blue = 0x00008B,
103     medium_blue = 0x0000CD,
104     blue = 0x0000FF,
105     royal_blue = 0x4169E1,
106     blue_violet = 0x8A2BE2,
107     indigo = 0x4B0082,
108     dark_slate_blue = 0x483D8B,
109     slate_blue = 0x6A5ACD,
110     medium_slate_blue = 0x7B68EE,
111     medium_purple = 0x9370DB,
112     dark_magenta = 0x8B008B,
113     dark_violet = 0x9400D3,
114     dark_orchid = 0x9932CC,
115     medium_orchid = 0xBA55D3,
116     purple = 0x800080,
117     thistle = 0xD8BFD8,
118     plum = 0xDDA0DD,
119     violet = 0xEE82EE,
120     magenta = 0xFF00FF,
121     fuchsia = 0xFF00FF,
122     orchid = 0xDA70D6,
123     medium_violet_red = 0xC71585,
124     pale_violet_red = 0xDB7093,
125     deep_pink = 0xFF1493,
126     hot_pink = 0xFF69B4,
127     light_pink = 0xFFB6C1,
128     pink = 0xFFC0CB,
129     antique_white = 0xFAEBD7,
130     beige = 0xF5F5DC,
131     bisque = 0xFFE4C4,
132     blanched_almond = 0xFFEBCD,
133     wheat = 0xF5DEB3,
134     corn_silk = 0xFFF8DC,
135     lemon_chiffon = 0xFFFACD,
136     light_golden_rod_yellow = 0xFAFAD2,
137     light_yellow = 0xFFFFE0,
138     saddle_brown = 0x8B4513,
139     sienna = 0xA0522D,
140     chocolate = 0xD2691E,
141     peru = 0xCD853F,
142     sandy_brown = 0xF4A460,
143     burly_wood = 0xDEB887,
144     tan = 0xD2B48C,
145     rosy_brown = 0xBC8F8F,
146     moccasin = 0xFFE4B5,
147     navajo_white = 0xFFDEAD,
148     peach_puff = 0xFFDAB9,
149     misty_rose = 0xFFE4E1,
150     lavender_blush = 0xFFF0F5,
151     linen = 0xFAF0E6,
152     old_lace = 0xFDF5E6,
153     papaya_whip = 0xFFEFD5,
154     sea_shell = 0xFFF5EE,
155     mint_cream = 0xF5FFFA,
156     slate_gray = 0x708090,
157     light_slate_gray = 0x778899,
158     light_steel_blue = 0xB0C4DE,
159     lavender = 0xE6E6FA,
160     floral_white = 0xFFFAF0,
161     alice_blue = 0xF0F8FF,
162     ghost_white = 0xF8F8FF,
163     honeydew = 0xF0FFF0,
164     ivory = 0xFFFFF0,
165     azure = 0xF0FFFF,
166     snow = 0xFFFAFA,
167     black = 0x000000,
168     dim_gray = 0x696969,
169     gray = 0x808080,
170     dark_gray = 0xA9A9A9,
171     silver = 0xC0C0C0,
172     light_gray = 0xD3D3D3,
173     gainsboro = 0xDCDCDC,
174     white_smoke = 0xF5F5F5,
175     white = 0xFFFFFF,
176 
177 }
178 
179 immutable uint COLOR_TRANSFORM_OFFSET_NONE = 0x80808080;
180 immutable uint COLOR_TRANSFORM_MULTIPLY_NONE = 0x40404040;
181 
182 
183 uint makeRGBA(T)(T r, T g, T b, T a) pure nothrow {
184     return (cast(uint)a << 24)|(cast(uint)r << 16)|(cast(uint)g << 8)|(cast(uint)b);
185 }
186 
187 /// blend two RGB pixels using alpha
188 uint blendARGB(uint dst, uint src, uint alpha) pure nothrow {
189     uint dstalpha = dst >> 24;
190     if (dstalpha > 0x80)
191         return src;
192     uint srcr = (src >> 16) & 0xFF;
193     uint srcg = (src >> 8) & 0xFF;
194     uint srcb = (src >> 0) & 0xFF;
195     uint dstr = (dst >> 16) & 0xFF;
196     uint dstg = (dst >> 8) & 0xFF;
197     uint dstb = (dst >> 0) & 0xFF;
198     uint ialpha = 255 - alpha;
199     uint r = ((srcr * ialpha + dstr * alpha) >> 8) & 0xFF;
200     uint g = ((srcg * ialpha + dstg * alpha) >> 8) & 0xFF;
201     uint b = ((srcb * ialpha + dstb * alpha) >> 8) & 0xFF;
202     return (r << 16) | (g << 8) | b;
203 }
204 
205 //immutable int[3] COMPONENT_OFFSET_BGR = [2, 1, 0];
206 immutable int[3] COMPONENT_OFFSET_BGR = [2, 1, 0];
207 //immutable int[3] COMPONENT_OFFSET_BGR = [1, 2, 0];
208 immutable int[3] COMPONENT_OFFSET_RGB = [0, 1, 2];
209 immutable int COMPONENT_OFFSET_ALPHA = 3;
210 int subpixelComponentIndex(int x0, SubpixelRenderingMode mode) pure nothrow {
211     switch (mode) with(SubpixelRenderingMode) {
212         case RGB:
213             return COMPONENT_OFFSET_BGR[x0];
214         case BGR:
215         default:
216             return COMPONENT_OFFSET_BGR[x0];
217     }
218 }
219 
220 /// blend subpixel using alpha
221 void blendSubpixel(ubyte * dst, ubyte * src, uint alpha, int x0, SubpixelRenderingMode mode) {
222     uint dstalpha = dst[COMPONENT_OFFSET_ALPHA];
223     int offset = subpixelComponentIndex(x0, mode);
224     uint srcr = src[offset];
225     dst[COMPONENT_OFFSET_ALPHA] = 0;
226     if (dstalpha > 0x80) {
227         dst[offset] = cast(ubyte)srcr;
228         return;
229     }
230     uint dstr = dst[offset];
231     uint ialpha = 256 - alpha;
232     uint r = ((srcr * ialpha + dstr * alpha) >> 8) & 0xFF;
233     dst[offset] = cast(ubyte)r;
234 }
235 
236 /// blend two alpha values 0..255 (255 is fully transparent, 0 is opaque)
237 uint blendAlpha(uint a1, uint a2) pure nothrow {
238     if (!a1)
239         return a2;
240     if (!a2)
241         return a1;
242     return (((a1 ^ 0xFF) * (a2 ^ 0xFF)) >> 8) ^ 0xFF;
243 }
244 
245 /// applies additional alpha to color
246 uint addAlpha(uint color, uint alpha) pure nothrow {
247     alpha = blendAlpha(color >> 24, alpha);
248     return (color & 0xFFFFFF) | (alpha << 24);
249 }
250 
251 ubyte rgbToGray(uint color) pure nothrow {
252     uint srcr = (color >> 16) & 0xFF;
253     uint srcg = (color >> 8) & 0xFF;
254     uint srcb = (color >> 0) & 0xFF;
255     return cast(uint)(((srcr + srcg + srcg + srcb) >> 2) & 0xFF);
256 }
257 
258 
259 // todo
260 struct ColorTransformHandler {
261     void initialize(ref ColorTransform transform) {
262 
263     }
264     uint transform(uint color) {
265         return color;
266     }
267 }
268 
269 uint transformComponent(int src, int addBefore, int multiply, int addAfter) pure nothrow {
270     int add1 = (cast(int)(addBefore << 1)) - 0x100;
271     int add2 = (cast(int)(addAfter << 1)) - 0x100;
272     int mul = cast(int)(multiply << 2);
273     int res = (((src + add1) * mul) >> 8) + add2;
274     if (res < 0)
275         res = 0;
276     else if (res > 255)
277         res = 255;
278     return cast(uint)res;
279 }
280 
281 uint transformRGBA(uint src, uint addBefore, uint multiply, uint addAfter) pure nothrow {
282     uint a = transformComponent(src >> 24, addBefore >> 24, multiply >> 24, addAfter >> 24);
283     uint r = transformComponent((src >> 16) & 0xFF, (addBefore >> 16) & 0xFF, (multiply >> 16) & 0xFF, (addAfter >> 16) & 0xFF);
284     uint g = transformComponent((src >> 8) & 0xFF, (addBefore >> 8) & 0xFF, (multiply >> 8) & 0xFF, (addAfter >> 8) & 0xFF);
285     uint b = transformComponent(src & 0xFF, addBefore & 0xFF, multiply & 0xFF, addAfter & 0xFF);
286     return (a << 24) | (r << 16) | (g << 8) | b;
287 }
288 
289 struct ColorTransform {
290     uint addBefore = COLOR_TRANSFORM_OFFSET_NONE;
291     uint multiply = COLOR_TRANSFORM_MULTIPLY_NONE;
292     uint addAfter = COLOR_TRANSFORM_OFFSET_NONE;
293     @property bool empty() const {
294         return addBefore == COLOR_TRANSFORM_OFFSET_NONE
295             && multiply == COLOR_TRANSFORM_MULTIPLY_NONE
296             && addAfter == COLOR_TRANSFORM_OFFSET_NONE;
297     }
298     uint transform(uint color) {
299         return transformRGBA(color, addBefore, multiply, addAfter);
300     }
301 }
302 
303 
304 /// blend two RGB pixels using alpha
305 ubyte blendGray(ubyte dst, ubyte src, uint alpha) pure nothrow {
306     uint ialpha = 256 - alpha;
307     return cast(ubyte)(((src * ialpha + dst * alpha) >> 8) & 0xFF);
308 }
309 
310 /// returns true if color is #FFxxxxxx (color alpha is 255)
311 bool isFullyTransparentColor(uint color) pure nothrow {
312     return (color >> 24) == 0xFF;
313 }
314 
315 /// decode color string  supported formats: #RGB #ARGB #RRGGBB #AARRGGBB
316 uint decodeHexColor(string s, uint defValue = 0) pure {
317     s = strip(s);
318     switch (s) {
319         case "@null":
320         case "transparent":
321             return COLOR_TRANSPARENT;
322         case "black":
323             return 0x000000;
324         case "white":
325             return 0xFFFFFF;
326         case "red":
327             return 0xFF0000;
328         case "green":
329             return 0x00FF00;
330         case "blue":
331             return 0x0000FF;
332         case "gray":
333             return 0x808080;
334         case "lightgray":
335         case "silver":
336             return 0xC0C0C0;
337         default:
338             break;
339     }
340     if (s.length != 4 && s.length != 5 && s.length != 7 && s.length != 9)
341         return defValue;
342     if (s[0] != '#')
343         return defValue;
344     uint value = 0;
345     foreach(i; 1 .. s.length) {
346         uint digit = parseHexDigit(s[i]);
347         if (digit == uint.max)
348             return defValue;
349         value = (value << 4) | digit;
350         if (s.length < 7) // double the same digit for short forms
351             value = (value << 4) | digit;
352     }
353     return value;
354 }
355