• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

excessive / cpml / 1

31 Mar 2022 01:05PM UTC coverage: 44.185% (-13.5%) from 57.717%
1

push

github

web-flow
Merge pull request #75 from idbrii/precond

Include offending type in precondition failure msg

50 of 60 new or added lines in 6 files covered. (83.33%)

205 existing lines in 6 files now uncovered.

76716 of 173626 relevant lines covered (44.18%)

1272.48 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

39.33
/modules/color.lua
1
--- Color utilities
2
-- @module color
3

4
local modules  = (...):gsub('%.[^%.]+$', '') .. "."
568✔
5
local utils    = require(modules .. "utils")
568✔
6
local precond  = require(modules .. "_private_precond")
568✔
7
local color    = {}
568✔
8
local color_mt = {}
568✔
9

10
local function new(r, g, b, a)
UNCOV
11
        local c = { r, g, b, a }
×
UNCOV
12
        c._c = c
×
UNCOV
13
        return setmetatable(c, color)
×
14
end
15

16
-- HSV utilities (adapted from http://www.cs.rit.edu/~ncs/color/t_convert.html)
17
-- hsv_to_color(hsv)
18
-- Converts a set of HSV values to a color. hsv is a table.
19
-- See also: hsv(h, s, v)
20
local function hsv_to_color(hsv)
21
        local i
22
        local f, q, p, t
23
        local h, s, v
UNCOV
24
        local a = hsv[4] or 255
×
UNCOV
25
        s = hsv[2]
×
UNCOV
26
        v = hsv[3]
×
27

UNCOV
28
        if s == 0 then
×
UNCOV
29
                return new(v, v, v, a)
×
30
        end
31

UNCOV
32
        h = hsv[1] / 60
×
33

UNCOV
34
        i = math.floor(h)
×
UNCOV
35
        f = h - i
×
UNCOV
36
        p = v * (1-s)
×
UNCOV
37
        q = v * (1-s*f)
×
UNCOV
38
        t = v * (1-s*(1-f))
×
39

UNCOV
40
        if     i == 0 then return new(v, t, p, a)
×
UNCOV
41
        elseif i == 1 then return new(q, v, p, a)
×
UNCOV
42
        elseif i == 2 then return new(p, v, t, a)
×
UNCOV
43
        elseif i == 3 then return new(p, q, v, a)
×
UNCOV
44
        elseif i == 4 then return new(t, p, v, a)
×
UNCOV
45
        else               return new(v, p, q, a)
×
46
        end
47
end
48

49
-- color_to_hsv(c)
50
-- Takes in a normal color and returns a table with the HSV values.
51
local function color_to_hsv(c)
UNCOV
52
        local r = c[1]
×
UNCOV
53
        local g = c[2]
×
UNCOV
54
        local b = c[3]
×
UNCOV
55
        local a = c[4] or 255
56
        local h, s, v
57

UNCOV
58
        local min = math.min(r, g, b)
UNCOV
59
        local max = math.max(r, g, b)
×
UNCOV
60
        v = max
×
61

UNCOV
62
        local delta = max - min
63

64
        -- black, nothing else is really possible here.
UNCOV
65
        if min == 0 and max == 0 then
UNCOV
66
                return { 0, 0, 0, a }
×
67
        end
68

UNCOV
69
        if max ~= 0 then
UNCOV
70
                s = delta / max
×
71
        else
72
                -- r = g = b = 0 s = 0, v is undefined
UNCOV
73
                s = 0
UNCOV
74
                h = -1
×
75
                return { h, s, v, 255 }
×
76
        end
77

UNCOV
78
        if r == max then
UNCOV
79
                h = ( g - b ) / delta     -- yellow/magenta
×
UNCOV
80
        elseif g == max then
×
UNCOV
81
                h = 2 + ( b - r ) / delta -- cyan/yellow
×
82
        else
UNCOV
83
                h = 4 + ( r - g ) / delta -- magenta/cyan
84
        end
85

UNCOV
86
        h = h * 60 -- degrees
87

UNCOV
88
        if h < 0 then
UNCOV
89
                h = h + 360
×
90
        end
91

UNCOV
92
        return { h, s, v, a }
93
end
94

95
--- The public constructor.
96
-- @param x Can be of three types: </br>
97
-- number red component 0-255
98
-- table {r, g, b, a}
99
-- nil for {0,0,0,0}
100
-- @tparam number g Green component 0-255
101
-- @tparam number b Blue component 0-255
102
-- @tparam number a Alpha component 0-255
103
-- @treturn color out
104
function color.new(r, g, b, a)
566✔
105
        -- number, number, number, number
2✔
UNCOV
106
        if r and g and b and a then
NEW
107
                precond.typeof(r, "number", "new: Wrong argument type for r")
×
NEW
108
                precond.typeof(g, "number", "new: Wrong argument type for g")
×
NEW
109
                precond.typeof(b, "number", "new: Wrong argument type for b")
×
NEW
110
                precond.typeof(a, "number", "new: Wrong argument type for a")
×
111

UNCOV
112
                return new(r, g, b, a)
113

114
        -- {r, g, b, a}
UNCOV
115
        elseif type(r) == "table" then
UNCOV
116
                local rr, gg, bb, aa = r[1], r[2], r[3], r[4]
×
NEW
117
                precond.typeof(rr, "number", "new: Wrong argument type for r")
×
NEW
118
                precond.typeof(gg, "number", "new: Wrong argument type for g")
×
NEW
119
                precond.typeof(bb, "number", "new: Wrong argument type for b")
×
NEW
120
                precond.typeof(aa, "number", "new: Wrong argument type for a")
×
121

UNCOV
122
                return new(rr, gg, bb, aa)
123
        end
124

125
        return new(0, 0, 0, 0)
126
end
127

128
--- Convert hue,saturation,value table to color object.
129
-- @tparam table hsva {hue 0-359, saturation 0-1, value 0-1, alpha 0-255}
130
-- @treturn color out
131
color.hsv_to_color_table = hsv_to_color
566✔
132

2✔
133
--- Convert color to hue,saturation,value table
134
-- @tparam color in
135
-- @treturn table hsva {hue 0-359, saturation 0-1, value 0-1, alpha 0-255}
136
color.color_to_hsv_table = color_to_hsv
566✔
137

2✔
138
--- Convert hue,saturation,value to color object.
139
-- @tparam number h hue 0-359
140
-- @tparam number s saturation 0-1
141
-- @tparam number v value 0-1
142
-- @treturn color out
143
function color.from_hsv(h, s, v)
566✔
UNCOV
144
        return hsv_to_color { h, s, v }
2✔
145
end
146

147
--- Convert hue,saturation,value to color object.
148
-- @tparam number h hue 0-359
149
-- @tparam number s saturation 0-1
150
-- @tparam number v value 0-1
151
-- @tparam number a alpha 0-255
152
-- @treturn color out
153
function color.from_hsva(h, s, v, a)
566✔
UNCOV
154
        return hsv_to_color { h, s, v, a }
2✔
155
end
156

157
--- Invert a color.
158
-- @tparam color to invert
159
-- @treturn color out
160
function color.invert(c)
566✔
UNCOV
161
        return new(255 - c[1], 255 - c[2], 255 - c[3], c[4])
2✔
162
end
163

164
--- Lighten a color by a component-wise fixed amount (alpha unchanged)
165
-- @tparam color to lighten
166
-- @tparam number amount to increase each component by, 0-255 scale
167
-- @treturn color out
168
function color.lighten(c, v)
566✔
UNCOV
169
        return new(
2✔
UNCOV
170
                utils.clamp(c[1] + v * 255, 0, 255),
×
UNCOV
171
                utils.clamp(c[2] + v * 255, 0, 255),
×
UNCOV
172
                utils.clamp(c[3] + v * 255, 0, 255),
×
173
                c[4]
174
        )
175
end
176

177
function color.lerp(a, b, s)
566✔
UNCOV
178
        return a + s * (b - a)
2✔
179
end
180

181
--- Darken a color by a component-wise fixed amount (alpha unchanged)
182
-- @tparam color to darken
183
-- @tparam number amount to decrease each component by, 0-255 scale
184
-- @treturn color out
185
function color.darken(c, v)
566✔
UNCOV
186
        return new(
2✔
UNCOV
187
                utils.clamp(c[1] - v * 255, 0, 255),
×
UNCOV
188
                utils.clamp(c[2] - v * 255, 0, 255),
×
UNCOV
189
                utils.clamp(c[3] - v * 255, 0, 255),
×
190
                c[4]
191
        )
192
end
193

194
--- Multiply a color's components by a value (alpha unchanged)
195
-- @tparam color to multiply
196
-- @tparam number to multiply each component by
197
-- @treturn color out
198
function color.multiply(c, v)
566✔
UNCOV
199
        local t = color.new()
2✔
UNCOV
200
        for i = 1, 3 do
×
UNCOV
201
                t[i] = c[i] * v
×
202
        end
203

UNCOV
204
        t[4] = c[4]
UNCOV
205
        return t
×
206
end
207

208
-- directly set alpha channel
209
-- @tparam color to alter
210
-- @tparam number new alpha 0-255
211
-- @treturn color out
212
function color.alpha(c, v)
566✔
UNCOV
213
        local t = color.new()
2✔
UNCOV
214
        for i = 1, 3 do
×
UNCOV
215
                t[i] = c[i]
×
216
        end
217

UNCOV
218
        t[4] = v * 255
UNCOV
219
        return t
×
220
end
221

222
--- Multiply a color's alpha by a value
223
-- @tparam color to multiply
224
-- @tparam number to multiply alpha by
225
-- @treturn color out
226
function color.opacity(c, v)
566✔
UNCOV
227
        local t = color.new()
2✔
UNCOV
228
        for i = 1, 3 do
×
UNCOV
229
                t[i] = c[i]
×
230
        end
231

UNCOV
232
        t[4] = c[4] * v
UNCOV
233
        return t
×
234
end
235

236
--- Set a color's hue (saturation, value, alpha unchanged)
237
-- @tparam color to alter
238
-- @tparam hue to set 0-359
239
-- @treturn color out
240
function color.hue(col, hue)
566✔
UNCOV
241
        local c = color_to_hsv(col)
2✔
UNCOV
242
        c[1] = (hue + 360) % 360
×
UNCOV
243
        return hsv_to_color(c)
×
244
end
245

246
--- Set a color's saturation (hue, value, alpha unchanged)
247
-- @tparam color to alter
248
-- @tparam hue to set 0-359
249
-- @treturn color out
250
function color.saturation(col, percent)
566✔
UNCOV
251
        local c = color_to_hsv(col)
2✔
UNCOV
252
        c[2] = utils.clamp(percent, 0, 1)
×
UNCOV
253
        return hsv_to_color(c)
×
254
end
255

256
--- Set a color's value (saturation, hue, alpha unchanged)
257
-- @tparam color to alter
258
-- @tparam hue to set 0-359
259
-- @treturn color out
260
function color.value(col, percent)
566✔
UNCOV
261
        local c = color_to_hsv(col)
2✔
UNCOV
262
        c[3] = utils.clamp(percent, 0, 1)
×
UNCOV
263
        return hsv_to_color(c)
×
264
end
265

266
-- http://en.wikipedia.org/wiki/SRGB#The_reverse_transformation
267
function color.gamma_to_linear(r, g, b, a)
566✔
268
        local function convert(c)
2✔
UNCOV
269
                if c > 1.0 then
UNCOV
270
                        return 1.0
×
UNCOV
271
                elseif c < 0.0 then
×
UNCOV
272
                        return 0.0
×
UNCOV
273
                elseif c <= 0.04045 then
×
UNCOV
274
                        return c / 12.92
×
275
                else
UNCOV
276
                        return math.pow((c + 0.055) / 1.055, 2.4)
277
                end
278
        end
279

UNCOV
280
        if type(r) == "table" then
UNCOV
281
                local c = {}
×
UNCOV
282
                for i = 1, 3 do
×
UNCOV
283
                        c[i] = convert(r[i] / 255) * 255
×
284
                end
285

UNCOV
286
                c[4] = convert(r[4] / 255) * 255
UNCOV
287
                return c
×
288
        else
UNCOV
289
                return convert(r / 255) * 255, convert(g / 255) * 255, convert(b / 255) * 255, a or 255
290
        end
291
end
292

293
-- http://en.wikipedia.org/wiki/SRGB#The_forward_transformation_.28CIE_xyY_or_CIE_XYZ_to_sRGB.29
294
function color.linear_to_gamma(r, g, b, a)
566✔
295
        local function convert(c)
2✔
UNCOV
296
                if c > 1.0 then
UNCOV
297
                        return 1.0
×
UNCOV
298
                elseif c < 0.0 then
×
UNCOV
299
                        return 0.0
×
UNCOV
300
                elseif c < 0.0031308 then
×
UNCOV
301
                        return c * 12.92
×
302
                else
UNCOV
303
                        return 1.055 * math.pow(c, 0.41666) - 0.055
304
                end
305
        end
306

UNCOV
307
        if type(r) == "table" then
UNCOV
308
                local c = {}
×
UNCOV
309
                for i = 1, 3 do
×
UNCOV
310
                        c[i] = convert(r[i] / 255) * 255
×
311
                end
312

UNCOV
313
                c[4] = convert(r[4] / 255) * 255
UNCOV
314
                return c
×
315
        else
UNCOV
316
                return convert(r / 255) * 255, convert(g / 255) * 255, convert(b / 255) * 255, a or 255
317
        end
318
end
319

320
--- Check if color is valid
321
-- @tparam color to test
322
-- @treturn boolean is color
323
function color.is_color(a)
566✔
UNCOV
324
        if type(a) ~= "table" then
2✔
UNCOV
325
                return false
×
326
        end
327

UNCOV
328
        for i = 1, 4 do
329
                if type(a[i]) ~= "number" then
×
UNCOV
330
                        return false
×
331
                end
332
        end
333

UNCOV
334
        return true
335
end
336

337
--- Return a formatted string.
338
-- @tparam color a color to be turned into a string
339
-- @treturn string formatted
340
function color.to_string(a)
566✔
UNCOV
341
        return string.format("[ %3.0f, %3.0f, %3.0f, %3.0f ]", a[1], a[2], a[3], a[4])
2✔
342
end
343

344
function color_mt.__index(t, k)
566✔
UNCOV
345
        if type(t) == "cdata" then
2✔
UNCOV
346
                if type(k) == "number" then
×
UNCOV
347
                        return t._c[k-1]
×
348
                end
349
        end
350

UNCOV
351
        return rawget(color, k)
352
end
353

354
function color_mt.__newindex(t, k, v)
566✔
UNCOV
355
        if type(t) == "cdata" then
2✔
UNCOV
356
                if type(k) == "number" then
×
357
                        t._c[k-1] = v
×
358
                end
359
        end
360
end
361

362
color_mt.__tostring = color.to_string
566✔
363

2✔
364
function color_mt.__call(_, r, g, b, a)
566✔
UNCOV
365
        return color.new(r, g, b, a)
2✔
366
end
367

368
function color_mt.__add(a, b)
566✔
UNCOV
369
        return new(a[1] + b[1], a[2] + b[2], a[3] + b[3], a[4] + b[4])
2✔
370
end
371

372
function color_mt.__sub(a, b)
566✔
373
        return new(a[1] - b[1], a[2] - b[2], a[3] - b[3], a[4] - b[4])
2✔
374
end
375

376
function color_mt.__mul(a, b)
566✔
UNCOV
377
        if type(a) == "number" then
2✔
UNCOV
378
                return new(a * b[1], a * b[2], a * b[3], a * b[4])
×
UNCOV
379
        elseif type(b) == "number" then
×
UNCOV
380
                return new(b * a[1], b * a[2], b * a[3], b * a[4])
×
381
        else
UNCOV
382
                return new(a[1] * b[1], a[2] * b[2], a[3] * b[3], a[4] * b[4])
383
        end
384
end
385

386
return setmetatable({}, color_mt)
566✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc