-
Notifications
You must be signed in to change notification settings - Fork 47
/
Copy pathparse.jl
147 lines (120 loc) · 4.6 KB
/
parse.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# Helper data for color parsing
include("names_data.jl")
# Color Parsing
# -------------
const col_pat_hex1 = r"(#|0x)([[:xdigit:]])([[:xdigit:]])([[:xdigit:]])"
const col_pat_hex2 = r"(#|0x)([[:xdigit:]]{2})([[:xdigit:]]{2})([[:xdigit:]]{2})"
const col_pat_rgb = r"rgb\((\d+%?),(\d+%?),(\d+%?)\)"
const col_pat_hsl = r"hsl\((\d+%?),(\d+%?),(\d+%?)\)"
const col_pat_rgba = r"rgba\((\d+%?),(\d+%?),(\d+%?),(\d+(?:\.\d*)?%?)\)"
const col_pat_hsla = r"hsla\((\d+%?),(\d+%?),(\d+%?),(\d+(?:\.\d*)?%?)\)"
# Parse a number used in the "rgb()" or "hsl()" color.
function parse_rgb(num::AbstractString)
if num[end] == '%'
return clamp(parse(Int, num[1:end-1], 10) / 100, 0, 1)
else
return clamp(parse(Int, num, 10) / 255, 0, 1)
end
end
function parse_hsl_hue(num::AbstractString)
if num[end] == '%'
error("hue cannot end in %")
else
return parse(Int, num, 10)
end
end
function parse_hsl_sl(num::AbstractString)
if num[end] != '%'
error("saturation and lightness must end in %")
else
return parse(Int, num[1:end-1], 10) / 100
end
end
# Parse a number used in the alpha field of "rgba()" and "hsla()".
function parse_alpha_num(num::AbstractString)
if num[end] == '%'
return parse(Int, num[1:end-1]) / 100
else
return parse(Float32, num)
end
end
"""
parse(Colorant, desc)
Parse a color description.
This parses subset of HTML/CSS color specifications. In particular, everything
is supported but: "currentColor".
It does support named colors (though it uses X11 named colors, which are
slightly different than W3C named colors in some cases), "rgb()", "hsl()",
"#RGB", and "#RRGGBB' syntax.
Args:
- `Colorant`: literal "Colorant" will parse according to the `desc`
string (usually returning an `RGB`); any more specific choice will
return a color of the specified type.
- `desc`: A color name or description.
Returns:
An `RGB{U8}` color, unless:
- "hsl(h,s,l)" was used, in which case an `HSL` color;
- "rgba(r,g,b,a)" was used, in which case an `RGBA` color;
- "hsla(h,s,l,a)" was used, in which case an `HSLA` color;
- a specific `Colorant` type was specified in the first argument
"""
function Base.parse(::Type{Colorant}, desc::AbstractString)
desc_ = replace(desc, " ", "")
mat = match(col_pat_hex2, desc_)
if mat != nothing
return RGB{U8}(parse(Int, mat.captures[2], 16) / 255,
parse(Int, mat.captures[3], 16) / 255,
parse(Int, mat.captures[4], 16) / 255)
end
mat = match(col_pat_hex1, desc_)
if mat != nothing
return RGB{U8}((16 * parse(Int, mat.captures[2], 16)) / 255,
(16 * parse(Int, mat.captures[3], 16)) / 255,
(16 * parse(Int, mat.captures[4], 16)) / 255)
end
mat = match(col_pat_rgb, desc_)
if mat != nothing
return RGB{U8}(parse_rgb(mat.captures[1]),
parse_rgb(mat.captures[2]),
parse_rgb(mat.captures[3]))
end
mat = match(col_pat_hsl, desc_)
if mat != nothing
return HSL{ColorTypes.eltype_default(HSL)}(parse_hsl_hue(mat.captures[1]),
parse_hsl_sl(mat.captures[2]),
parse_hsl_sl(mat.captures[3]))
end
mat = match(col_pat_rgba, desc_)
if mat != nothing
return RGBA{U8}(parse_rgb(mat.captures[1]),
parse_rgb(mat.captures[2]),
parse_rgb(mat.captures[3]),
parse_alpha_num(mat.captures[4]))
end
mat = match(col_pat_hsla, desc_)
if mat != nothing
return HSLA{ColorTypes.eltype_default(HSLA)}(parse_hsl_hue(mat.captures[1]),
parse_hsl_sl(mat.captures[2]),
parse_hsl_sl(mat.captures[3]),
parse_alpha_num(mat.captures[4]))
end
desc_ = lowercase(desc_)
if desc_ == "transparent"
return RGBA{U8}(0,0,0,0)
end
if !haskey(color_names, desc_)
error("Unknown color: ", desc)
end
c = color_names[desc_]
return RGB{U8}(c[1] / 255, c[2] / 255, c[3] / 255)
end
Base.parse{C<:Colorant}(::Type{C}, desc) = convert(C, parse(Colorant, desc))::C
macro colorant_str(ex)
isa(ex, AbstractString) || error("colorant requires literal strings")
col = parse(Colorant, ex)
:($col)
end
@noinline function ColorTypes.color(str::AbstractString)
Base.depwarn("color(\"$str\") is deprecated, use colorant\"$str\" or parse(Colorant, \"$str\")", :color)
parse(Colorant, str)
end