Skip to content

Commit ffe43d8

Browse files
authored
Merge pull request #50 from yakatz/feature/autocolor
Generate a pseudorandom color based on the user's name
2 parents 1a81fea + 48fe299 commit ffe43d8

File tree

4 files changed

+179
-0
lines changed

4 files changed

+179
-0
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ $image = $avatar->background('#ff0000')->generate();
111111
$image = $avatar->color('#ff0000')->generate();
112112
````
113113

114+
### Auto Color
115+
````php
116+
// Will choose a background color based on `name` and a contrasting font color. The color for a specific name will always be the same.
117+
$image = $avatar->autoColor()->generate();
118+
````
119+
114120
### Font file - default: /fonts/OpenSans-Regular.ttf
115121
Two fonts with two variants are included:
116122
* /fonts/OpenSans-Regular.ttf

src/InitialAvatar.php

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,26 @@ public function color($color)
219219
return $this;
220220
}
221221

222+
/**
223+
* Automatically set a font and/or background color based on the supplied name.
224+
*
225+
* @param bool $foreground
226+
* @param bool $background
227+
*
228+
* @return $this
229+
*/
230+
public function autoColor(bool $foreground = true, bool $background = true, int $saturation = 85, int $luminance = 60)
231+
{
232+
$hue = (crc32($this->name) % 360) / 360;
233+
$saturation /= 100;
234+
$luminance /= 100;
235+
236+
$this->bgColor = $this->convertHSLtoRGB($hue, $saturation, $luminance);
237+
$this->fontColor = $this->getContrastColor($this->bgColor);
238+
239+
return $this;
240+
}
241+
222242
/**
223243
* Set the font file by path or int (1-5).
224244
*
@@ -782,4 +802,116 @@ protected function getFontByScript()
782802

783803
return $this->getFontFile();
784804
}
805+
806+
/**
807+
* Convert HSL color value produced by autoColor() to RGB value expected by image driver.
808+
*/
809+
protected function convertHSLtoRGB($h, $s, $l, $toHex = true)
810+
{
811+
assert((0 <= $h) && ($h <= 1));
812+
813+
$red = $l;
814+
$green = $l;
815+
$blue = $l;
816+
817+
$v = ($l <= 0.5) ? ($l * (1.0 + $s)) : ($l + $s - $l * $s);
818+
if ($v > 0) {
819+
$m = $l + $l - $v;
820+
$sv = ($v - $m) / $v;
821+
$h *= 6.0;
822+
$sextant = floor($h);
823+
$fract = $h - $sextant;
824+
$vsf = $v * $sv * $fract;
825+
$mid1 = $m + $vsf;
826+
$mid2 = $v - $vsf;
827+
828+
switch ($sextant) {
829+
case 0:
830+
$red = $v;
831+
$green = $mid1;
832+
$blue = $m;
833+
break;
834+
case 1:
835+
$red = $mid2;
836+
$green = $v;
837+
$blue = $m;
838+
break;
839+
case 2:
840+
$red = $m;
841+
$green = $v;
842+
$blue = $mid1;
843+
break;
844+
case 3:
845+
$red = $m;
846+
$green = $mid2;
847+
$blue = $v;
848+
break;
849+
case 4:
850+
$red = $mid1;
851+
$green = $m;
852+
$blue = $v;
853+
break;
854+
case 5:
855+
$red = $v;
856+
$green = $m;
857+
$blue = $mid2;
858+
break;
859+
}
860+
}
861+
862+
$red = round($red * 255, 0);
863+
$green = round($green * 255, 0);
864+
$blue = round($blue * 255, 0);
865+
866+
if ($toHex) {
867+
$red = ($red < 15) ? '0'.dechex($red) : dechex($red);
868+
$green = ($green < 15) ? '0'.dechex($green) : dechex($green);
869+
$blue = ($blue < 15) ? '0'.dechex($blue) : dechex($blue);
870+
871+
return "#{$red}{$green}{$blue}";
872+
} else {
873+
return ['red' => $red, 'green' => $green, 'blue' => $blue];
874+
}
875+
}
876+
877+
/**
878+
* Get contrasting foreground color for autoColor background.
879+
*/
880+
protected function getContrastColor($hexColor)
881+
{
882+
// hexColor RGB
883+
$R1 = hexdec(substr($hexColor, 1, 2));
884+
$G1 = hexdec(substr($hexColor, 3, 2));
885+
$B1 = hexdec(substr($hexColor, 5, 2));
886+
887+
// Black RGB
888+
$blackColor = '#000000';
889+
$R2BlackColor = hexdec(substr($blackColor, 1, 2));
890+
$G2BlackColor = hexdec(substr($blackColor, 3, 2));
891+
$B2BlackColor = hexdec(substr($blackColor, 5, 2));
892+
893+
// Calc contrast ratio
894+
$L1 = 0.2126 * pow($R1 / 255, 2.2) +
895+
0.7152 * pow($G1 / 255, 2.2) +
896+
0.0722 * pow($B1 / 255, 2.2);
897+
898+
$L2 = 0.2126 * pow($R2BlackColor / 255, 2.2) +
899+
0.7152 * pow($G2BlackColor / 255, 2.2) +
900+
0.0722 * pow($B2BlackColor / 255, 2.2);
901+
902+
$contrastRatio = 0;
903+
if ($L1 > $L2) {
904+
$contrastRatio = (int) (($L1 + 0.05) / ($L2 + 0.05));
905+
} else {
906+
$contrastRatio = (int) (($L2 + 0.05) / ($L1 + 0.05));
907+
}
908+
909+
// If contrast is more than 5, return black color
910+
if ($contrastRatio > 5) {
911+
return '#000000';
912+
} else {
913+
// if not, return white color.
914+
return '#FFFFFF';
915+
}
916+
}
785917
}

tests/AutoColorUtilsTest.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
use LasseRafn\InitialAvatarGenerator\InitialAvatar;
4+
use PHPUnit\Framework\TestCase;
5+
6+
class AutoColorUtilsTest extends TestCase
7+
{
8+
/** @test */
9+
public function can_create_all_colors()
10+
{
11+
$avatar = new InitialAvatar();
12+
13+
$avatar->name('A')->autoColor();
14+
$this->assertEquals('#f0a742', $avatar->getBackgroundColor());
15+
$this->assertEquals('#000000', $avatar->getColor());
16+
17+
$avatar->name('B')->autoColor();
18+
$this->assertEquals('#42caf0', $avatar->getBackgroundColor());
19+
$this->assertEquals('#000000', $avatar->getColor());
20+
21+
$avatar->name('C')->autoColor();
22+
$this->assertEquals('#42f085', $avatar->getBackgroundColor());
23+
$this->assertEquals('#000000', $avatar->getColor());
24+
25+
$avatar->name('D')->autoColor();
26+
$this->assertEquals('#f04293', $avatar->getBackgroundColor());
27+
$this->assertEquals('#FFFFFF', $avatar->getColor());
28+
}
29+
}

tests/ParameterTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,16 @@ public function can_set_auto_font()
9898

9999
$this->assertNotTrue($avatar->getAutoFont());
100100
}
101+
102+
/** @test */
103+
public function can_set_auto_color()
104+
{
105+
$avatar = new InitialAvatar();
106+
107+
$avatar->autoColor();
108+
109+
$this->assertEquals('#eaf042', $avatar->getBackgroundColor());
110+
111+
$this->assertEquals('#000000', $avatar->getColor());
112+
}
101113
}

0 commit comments

Comments
 (0)