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 = 256 - 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