HexColorPair   A
last analyzed

Complexity

Total Complexity 20

Size/Duplication

Total Lines 133
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
dl 0
loc 133
c 0
b 0
f 0
wmc 20
lcom 1
cbo 1
rs 10

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A make() 0 4 1
A ratio() 0 4 1
A random() 0 4 1
A sibling() 0 4 1
A minContrast() 0 15 3
A getRandom() 0 8 1
A getSibling() 0 8 1
A calculateRatio() 0 11 3
A luminance() 0 21 4
A rgbHexChannels() 0 10 1
A getRandomPairMinRatio() 0 9 2
1
<?php
2
3
namespace Breadthe\PhpContrast;
4
5
class HexColorPair
6
{
7
    const MIN_RATIO = 3.0;
8
    const MAX_RATIO = 4.5; // hard cap on the max requested ratio, to mitigate performance issues
9
10
    public $ratio; // computed contrast ratio between fg : bg
11
12
    // Calling these foreground/background instead of a more generic "color 1"/"color 2"
13
    // Doesn't really matter, they can be used interchangeably
14
    public $fg; // foreground (text) color
15
    public $bg; // background color
16
17
    protected $minRatio;
18
19
    public function __construct(HexColor $fg = null, HexColor $bg = null)
20
    {
21
        $this->fg = $fg;
22
        $this->bg = $bg;
23
        $this->ratio = static::calculateRatio($fg, $bg);
24
    }
25
26
    public static function make(HexColor $fg, HexColor $bg)
27
    {
28
        return new static($fg, $bg);
29
    }
30
31
    public static function ratio(HexColor $fg, HexColor $bg)
32
    {
33
        return (new static($fg, $bg))->ratio;
34
    }
35
36
    public static function random(): self
37
    {
38
        return (new static)->getRandom();
39
    }
40
41
    public static function sibling(string $hexValue): HexColor
42
    {
43
        return (new static)->getSibling($hexValue);
44
    }
45
46
    public static function minContrast($ratio): self
47
    {
48
        if ($ratio < self::MIN_RATIO) {
49
            $ratio = self::MIN_RATIO;
50
        }
51
52
        if ($ratio > self::MAX_RATIO) {
53
            $ratio = self::MAX_RATIO;
54
        }
55
56
        $pair = new static;
57
        $pair->minRatio = $ratio;
58
59
        return $pair;
60
    }
61
62
    public function getRandom(): self
63
    {
64
        $minRatio = $this->minRatio ?? self::MIN_RATIO;
65
66
        $fg = HexColor::random();
67
68
        return $this->getRandomPairMinRatio($fg, $minRatio);
69
    }
70
71
    public function getSibling(string $hexValue): HexColor
72
    {
73
        $minRatio = $this->minRatio ?? self::MIN_RATIO;
74
75
        $pair = $this->getRandomPairMinRatio(HexColor::make($hexValue), $minRatio);
76
77
        return $pair->bg;
78
    }
79
80
    protected static function calculateRatio(HexColor $fg = null, HexColor $bg = null)
81
    {
82
        if (! $fg || ! $bg) {
83
            return;
84
        }
85
86
        $fgLuminance = static::luminance($fg);
87
        $bgLuminance = static::luminance($bg);
88
89
        return round((max($fgLuminance, $bgLuminance) + 0.05) / (min($fgLuminance, $bgLuminance) + 0.05) * 10) / 10;
90
    }
91
92
    protected static function luminance(HexColor $color)
93
    {
94
        [$rHex, $gHex, $bHex] = static::rgbHexChannels($color);
0 ignored issues
show
Bug introduced by
The variable $rHex does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $gHex does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $bHex does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
95
96
        // Get decimal values
97
        $r8bit = base_convert($rHex, 16, 10);
98
        $g8bit = base_convert($gHex, 16, 10);
99
        $b8bit = base_convert($bHex, 16, 10);
100
101
        // Get sRGB values
102
        $rSrgb = $r8bit / 255;
103
        $gSrgb = $g8bit / 255;
104
        $bSrgb = $b8bit / 255;
105
106
        // Calculate luminance
107
        $r = ($rSrgb <= 0.03928) ? $rSrgb / 12.92 : pow((($rSrgb + 0.055) / 1.055), 2.4);
108
        $g = ($gSrgb <= 0.03928) ? $gSrgb / 12.92 : pow((($gSrgb + 0.055) / 1.055), 2.4);
109
        $b = ($bSrgb <= 0.03928) ? $bSrgb / 12.92 : pow((($bSrgb + 0.055) / 1.055), 2.4);
110
111
        return 0.2126 * $r + 0.7152 * $g + 0.0722 * $b;
112
    }
113
114
    /**
115
     * '#abcdef' => ['ab', 'cd', 'ef'].
116
     */
117
    protected static function rgbHexChannels(HexColor $hexColor): array
118
    {
119
        $hex = substr($hexColor->hex, 1); // strip the #
120
121
        return [
122
            substr($hex, 0, 2),
123
            substr($hex, 2, 2),
124
            substr($hex, 4, 2),
125
        ];
126
    }
127
128
    protected function getRandomPairMinRatio($fg, $minRatio): self
129
    {
130
        do {
131
            $bg = HexColor::random();
132
            $pair = new static($fg, $bg);
133
        } while ($pair->ratio <= $minRatio);
134
135
        return $pair;
136
    }
137
}
138