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