Skip to content

Commit 94d2e53

Browse files
committed
Clean up colors and add constrast calculation
1 parent a2810be commit 94d2e53

File tree

10 files changed

+399
-187
lines changed

10 files changed

+399
-187
lines changed

index.php

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<?php
22

33
use Intervention\Image\ImageManager;
4+
use marijnvdwerf\palette\Color\AbstractColor;
5+
use marijnvdwerf\palette\Color\RGBColor;
46
use marijnvdwerf\palette\Palette;
57
use marijnvdwerf\palette\Swatch;
68

@@ -21,6 +23,8 @@
2123
.swatch {
2224
padding: 15px;
2325
list-style-type: none;
26+
font-weight: 500;
27+
font-size: 14px;
2428
}
2529

2630
.swatch__color {
@@ -29,10 +33,17 @@
2933

3034
.album {
3135
width: 320px;
36+
float: left;
37+
margin-left: 40px;
38+
padding-bottom: 40px;
3239
}
40+
41+
3342
</style>
3443

3544
<?php
45+
46+
3647
$basePath = './specs/artwork';
3748
$files = scandir($basePath);
3849

@@ -48,7 +59,7 @@
4859

4960

5061
echo '<div class="album">';
51-
echo "<img src='data:image/png;base64," . base64_encode($image->encode('png')) . "' />";
62+
echo "<img src='data:image/png;base64," . base64_encode($image->resize(320, 0)->encode('png')) . "' />";
5263
echo '<h1>' . $filename . '</h1>';
5364
printPalette($palette);
5465
//printSwatches($swatches);
@@ -75,6 +86,13 @@ function printPalette(Palette $palette)
7586
$v1s = ['Vibrant', 'Muted'];
7687
$v2s = ['', 'Light', 'Dark'];
7788

89+
$textColors = [
90+
new RGBColor(1, 1, 1, 0.87),
91+
new RGBColor(1, 1, 1),
92+
new RGBColor(0, 0, 0, 0.87),
93+
new RGBColor(0, 0, 0)
94+
];
95+
7896
echo '<ul>';
7997
foreach ($v1s as $v1) {
8098
foreach ($v2s as $v2) {
@@ -83,7 +101,14 @@ function printPalette(Palette $palette)
83101

84102
$swatchName = implode(' ', array_filter([$v2, $v1]));
85103
if ($swatch !== null) {
86-
echo sprintf('<li class="swatch" style="background-color: %1$s"><span class="swatch__name">%2$s</span> <span class="swatch__color">%1$s</span></li>', $swatch->getColor(), $swatchName);
104+
$textColor = null;
105+
foreach ($textColors as $foregroundColor) {
106+
if (AbstractColor::calculateContrast($swatch->getColor(), $foregroundColor) >= 3) {
107+
$textColor = $foregroundColor;
108+
break;
109+
}
110+
}
111+
echo sprintf('<li class="swatch" style="background-color: %1$s; color: %3$s"><span class="swatch__name">%2$s</span> <span class="swatch__color">%1$s</span></li>', $swatch->getColor(), $swatchName, $textColor);
87112
} else {
88113
echo sprintf('<li class="swatch swatch--empty">%s</li>', $swatchName);
89114
}

src/AbstractColor.php

Lines changed: 0 additions & 16 deletions
This file was deleted.

src/Color/AbstractColor.php

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
3+
namespace marijnvdwerf\palette\Color;
4+
5+
/**
6+
* @property float alpha
7+
*/
8+
abstract class AbstractColor
9+
{
10+
protected $_alpha;
11+
12+
/**
13+
* @return HSLColor
14+
*/
15+
public abstract function asHSLColor();
16+
17+
/**
18+
* @return RGBColor
19+
*/
20+
public abstract function asRGBColor();
21+
22+
/**
23+
* @return float Alpha component [0...1]
24+
*/
25+
public function getAlphaComponent()
26+
{
27+
return $this->_alpha;
28+
}
29+
30+
/**
31+
* Returns the luminance of a color.
32+
* Formula defined here: http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
33+
*
34+
* @return float luminance
35+
*/
36+
public function getLuminance()
37+
{
38+
return $this->asRGBColor()->getLuminance();
39+
}
40+
41+
public function composedOn(AbstractColor $background)
42+
{
43+
$foregroundRGB = $this->asRGBColor();
44+
$foregroundAlpha = $this->alpha;
45+
$backgroundRGB = $background->asRGBColor();
46+
$backgroundAlpha = $background->alpha;
47+
48+
$alpha = ($foregroundAlpha + $backgroundAlpha) * (1 - $foregroundAlpha);
49+
$red = ($foregroundRGB->red * $foregroundAlpha)
50+
+ $backgroundRGB->red * $backgroundAlpha * (1 - $this->alpha);
51+
$green = ($foregroundRGB->green * $this->alpha)
52+
+ $backgroundRGB->green * $backgroundAlpha * (1 - $this->alpha);
53+
$blue = ($foregroundRGB->blue * $this->alpha)
54+
+ $backgroundRGB->blue * $backgroundAlpha * (1 - $this->alpha);
55+
56+
return new RGBColor($red, $green, $blue, $alpha);
57+
}
58+
59+
/**
60+
* Formula defined here: http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef
61+
*
62+
* @param AbstractColor $background
63+
* @param AbstractColor $foreground
64+
* @return float
65+
*/
66+
public static function calculateContrast(AbstractColor $background, AbstractColor $foreground)
67+
{
68+
if ($background->alpha < 1) {
69+
throw new \InvalidArgumentException('Background can not be translucent');
70+
}
71+
72+
if ($foreground->alpha < 1) {
73+
$foreground = $foreground->composedOn($background);
74+
}
75+
76+
$components = [
77+
$background->getLuminance() + 0.05,
78+
$foreground->getLuminance() + 0.05
79+
];
80+
81+
return max($components) / min($components);
82+
}
83+
84+
public function __get($name)
85+
{
86+
if ($name === 'alpha') {
87+
return $this->getAlphaComponent();
88+
}
89+
90+
return null;
91+
}
92+
93+
public function __set($name, $value)
94+
{
95+
return;
96+
}
97+
}

src/Color/HSLColor.php

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
<?php
2+
3+
namespace marijnvdwerf\palette\Color;
4+
5+
/**
6+
* @property float hue
7+
* @property float saturation
8+
* @property float lightness
9+
*/
10+
class HSLColor extends AbstractColor
11+
{
12+
protected $_hue;
13+
protected $_saturation;
14+
protected $_lightness;
15+
16+
function __construct($hue, $saturation, $lightness, $alpha = 1)
17+
{
18+
$this->_hue = $hue;
19+
$this->_saturation = $saturation;
20+
$this->_lightness = $lightness;
21+
$this->_alpha = $alpha;
22+
}
23+
24+
/** @inheritdoc */
25+
public function asHSLColor()
26+
{
27+
return $this;
28+
}
29+
30+
/** @inheritdoc */
31+
public function asRGBColor()
32+
{
33+
if ($this->lightness <= 0.5) {
34+
$m2 = $this->lightness * ($this->_saturation + 1);
35+
} else {
36+
$m2 = $this->lightness + $this->_saturation - $this->lightness * $this->_saturation;
37+
}
38+
39+
$h = $this->_hue;
40+
$m1 = $this->_lightness * 2 - $m2;
41+
42+
$r = self::hueToRGB($m1, $m2, $h + 1 / 3);
43+
$g = self::hueToRGB($m1, $m2, $h);
44+
$b = self::hueToRGB($m1, $m2, $h - 1 / 3);
45+
46+
return new RGBColor($r, $g, $b, $this->_alpha);
47+
}
48+
49+
private static function hueToRGB($m1, $m2, $h)
50+
{
51+
if ($h) {
52+
$h += 1;
53+
}
54+
if ($h > 1) {
55+
$h -= 1;
56+
}
57+
58+
if ($h * 6 < 1) {
59+
return $m1 + ($m2 - $m1) * $h * 6;
60+
}
61+
62+
if ($h * 2 < 1) {
63+
return $m2;
64+
}
65+
66+
if ($h * 3 < 2) {
67+
return $m1 + ($m2 - $m1) * (2 / 3 - $h) * 6;
68+
}
69+
70+
return $m1;
71+
}
72+
73+
public function __toString()
74+
{
75+
if ($this->_alpha < 1) {
76+
return sprintf('hsla(%f, %f%%, %f%%, %f)', $this->_hue * 360, $this->_saturation * 100, $this->_lightness * 100, $this->_alpha);
77+
}
78+
79+
return sprintf('hsl(%f, %f%%, %f%%)', $this->_hue * 360, $this->_saturation * 100, $this->_lightness * 100);
80+
}
81+
82+
/**
83+
* @param $lightness float [0...1]
84+
* @return HSLColor
85+
*/
86+
public function withLightness($lightness)
87+
{
88+
return new HSLColor($this->_hue, $this->_saturation, $lightness, $this->_alpha);
89+
}
90+
91+
public function getHue()
92+
{
93+
return $this->_hue;
94+
}
95+
96+
public function getSaturation()
97+
{
98+
return $this->_saturation;
99+
}
100+
101+
public function getLightness()
102+
{
103+
return $this->_lightness;
104+
}
105+
106+
function __get($name)
107+
{
108+
switch ($name) {
109+
case 'hue';
110+
return $this->getHue();
111+
112+
case 'saturation';
113+
return $this->getSaturation();
114+
115+
case 'lightness';
116+
return $this->getLightness();
117+
}
118+
119+
return parent::__get($name);
120+
}
121+
}

0 commit comments

Comments
 (0)