| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
|
|
2
|
|
|
|
|
|
|
# OKHSV color space, converter under Copyright (c) 2021 Björn Ottosson, see LICENSE.OK |
|
3
|
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
package Graphics::Toolkit::Color::Space::Instance::OKHSV; |
|
5
|
16
|
|
|
16
|
|
257890
|
use v5.12; |
|
|
16
|
|
|
|
|
46
|
|
|
6
|
16
|
|
|
16
|
|
67
|
use warnings; |
|
|
16
|
|
|
|
|
19
|
|
|
|
16
|
|
|
|
|
858
|
|
|
7
|
16
|
|
|
16
|
|
445
|
use Graphics::Toolkit::Color::Space qw/max spow/; |
|
|
16
|
|
|
|
|
36
|
|
|
|
16
|
|
|
|
|
945
|
|
|
8
|
|
|
|
|
|
|
use Graphics::Toolkit::Color::Space::Instance::Helper::OK |
|
9
|
16
|
|
|
16
|
|
497
|
qw/find_cusp to_ST toe toe_inv oklab_to_linear_srgb linear_srgb_to_oklab/; |
|
|
16
|
|
|
|
|
19
|
|
|
|
16
|
|
|
|
|
9622
|
|
|
10
|
|
|
|
|
|
|
my $PI = 4 * atan2(1, 1); |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
sub from_hsv { |
|
14
|
8
|
|
|
8
|
0
|
12
|
my ($hsv) = @_; |
|
15
|
8
|
100
|
|
|
|
18
|
return [0, 0, 0] if $hsv->[2] <= 0; # black (v == 0) |
|
16
|
|
|
|
|
|
|
|
|
17
|
7
|
|
|
|
|
15
|
my $a = cos(2 * $PI * $hsv->[0]); # Farbtonrichtung |
|
18
|
7
|
|
|
|
|
10
|
my $b = sin(2 * $PI * $hsv->[0]); |
|
19
|
|
|
|
|
|
|
|
|
20
|
7
|
|
|
|
|
15
|
my ($L_cusp, $C_cusp) = find_cusp($a, $b); |
|
21
|
7
|
|
|
|
|
14
|
my ($S_max, $T_max) = to_ST($L_cusp, $C_cusp); |
|
22
|
7
|
|
|
|
|
8
|
my $S_0 = 0.5; |
|
23
|
7
|
|
|
|
|
9
|
my $k = 1 - $S_0 / $S_max; |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
# L, C als waere das Gamut ein perfektes Dreieck (Werte bei v == 1) |
|
26
|
7
|
|
|
|
|
11
|
my $denom = $S_0 + $T_max - $T_max * $k * $hsv->[1]; |
|
27
|
7
|
50
|
|
|
|
10
|
$denom = 1e-6 if $denom < 1e-6; |
|
28
|
|
|
|
|
|
|
|
|
29
|
7
|
|
|
|
|
11
|
my $L_v = 1 - $hsv->[1] * $S_0 / $denom; |
|
30
|
7
|
|
|
|
|
10
|
my $C_v = $hsv->[1] * $T_max * $S_0 / $denom; |
|
31
|
|
|
|
|
|
|
|
|
32
|
7
|
|
|
|
|
8
|
my $L = $hsv->[2] * $L_v; |
|
33
|
7
|
|
|
|
|
7
|
my $C = $hsv->[2] * $C_v; |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# Kompensation fuer toe und gekruemmte Dreiecksspitze |
|
36
|
7
|
|
|
|
|
10
|
my $L_vt = toe_inv($L_v); |
|
37
|
7
|
|
|
|
|
9
|
my $C_vt = $C_v * $L_vt / $L_v; |
|
38
|
|
|
|
|
|
|
|
|
39
|
7
|
|
|
|
|
10
|
my $L_new = toe_inv($L); |
|
40
|
7
|
|
|
|
|
7
|
$C = $C * $L_new / $L; |
|
41
|
7
|
|
|
|
|
8
|
$L = $L_new; |
|
42
|
|
|
|
|
|
|
|
|
43
|
7
|
|
|
|
|
14
|
my $rgb_scale = oklab_to_linear_srgb([$L_vt, $a * $C_vt, $b * $C_vt]); |
|
44
|
7
|
|
|
|
|
13
|
my $scale_L = spow(1 / max(@$rgb_scale, 0), 1/3); |
|
45
|
|
|
|
|
|
|
|
|
46
|
7
|
|
|
|
|
9
|
$L *= $scale_L; |
|
47
|
7
|
|
|
|
|
7
|
$C *= $scale_L; |
|
48
|
|
|
|
|
|
|
|
|
49
|
7
|
|
|
|
|
13
|
return oklab_to_linear_srgb([$L, $C * $a, $C * $b]); |
|
50
|
|
|
|
|
|
|
} |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub to_hsv { |
|
53
|
8
|
|
|
8
|
0
|
10
|
my ($rgb) = @_; # bereits LINEARES sRGB |
|
54
|
8
|
|
|
|
|
16
|
my $lab = linear_srgb_to_oklab($rgb); # roh, a/b um 0 zentriert |
|
55
|
|
|
|
|
|
|
|
|
56
|
8
|
|
|
|
|
22
|
my $C = spow($lab->[1]**2 + $lab->[2]**2, 1/2); # Chroma |
|
57
|
8
|
100
|
|
|
|
14
|
return [0, 0, toe($lab->[0])] if $C < 1e-9; # achromatisch |
|
58
|
|
|
|
|
|
|
|
|
59
|
7
|
|
|
|
|
14
|
my $a = $lab->[1] / $C; # Farbtonrichtung |
|
60
|
7
|
|
|
|
|
8
|
my $b = $lab->[2] / $C; |
|
61
|
7
|
|
|
|
|
18
|
my $h = 0.5 + 0.5 * atan2(-$lab->[2], -$lab->[1]) / $PI; |
|
62
|
|
|
|
|
|
|
|
|
63
|
7
|
|
|
|
|
15
|
my ($L_cusp, $C_cusp) = find_cusp($a, $b); |
|
64
|
7
|
|
|
|
|
15
|
my ($S_max, $T_max) = to_ST($L_cusp, $C_cusp); |
|
65
|
7
|
|
|
|
|
6
|
my $S_0 = 0.5; |
|
66
|
7
|
|
|
|
|
10
|
my $k = 1 - $S_0 / $S_max; |
|
67
|
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
# L_v, C_v und ihre toe-kompensierten Varianten |
|
69
|
7
|
|
|
|
|
10
|
my $t = $T_max / ($C + $lab->[0] * $T_max); |
|
70
|
7
|
|
|
|
|
9
|
my $L_v = $t * $lab->[0]; |
|
71
|
7
|
|
|
|
|
7
|
my $C_v = $t * $C; |
|
72
|
|
|
|
|
|
|
|
|
73
|
7
|
|
|
|
|
13
|
my $L_vt = toe_inv($L_v); |
|
74
|
7
|
|
|
|
|
9
|
my $C_vt = $C_v * $L_vt / $L_v; |
|
75
|
|
|
|
|
|
|
|
|
76
|
7
|
|
|
|
|
16
|
my $rgb_scale = oklab_to_linear_srgb([$L_vt, $a * $C_vt, $b * $C_vt]); |
|
77
|
7
|
|
|
|
|
16
|
my $scale_L = spow(1 / max(@$rgb_scale, 0), 1/3); |
|
78
|
|
|
|
|
|
|
|
|
79
|
7
|
|
|
|
|
13
|
my $L = $lab->[0] / $scale_L; |
|
80
|
7
|
|
|
|
|
8
|
$C = $C / $scale_L; |
|
81
|
7
|
|
|
|
|
12
|
$C = $C * toe($L) / $L; |
|
82
|
7
|
|
|
|
|
9
|
$L = toe($L); |
|
83
|
|
|
|
|
|
|
|
|
84
|
7
|
|
|
|
|
31
|
my $s = ($S_0 + $T_max) * $C_v / ($T_max * $S_0 + $T_max * $k * $C_v); |
|
85
|
|
|
|
|
|
|
|
|
86
|
7
|
|
|
|
|
27
|
return [$h, $s, $L / $L_v]; |
|
87
|
|
|
|
|
|
|
} |
|
88
|
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
Graphics::Toolkit::Color::Space->new( |
|
90
|
|
|
|
|
|
|
name => 'OKHSV', |
|
91
|
|
|
|
|
|
|
family => 'HSV', |
|
92
|
|
|
|
|
|
|
axis => [qw/hue saturation value/], |
|
93
|
|
|
|
|
|
|
type => [qw/angular linear linear/], |
|
94
|
|
|
|
|
|
|
range => [360, 1, 1], |
|
95
|
|
|
|
|
|
|
precision => 5, |
|
96
|
|
|
|
|
|
|
convert => {LinearRGB => [\&from_hsv, \&to_hsv]}, |
|
97
|
|
|
|
|
|
|
); |