@@ -207,6 +207,27 @@ public function color( $color ) {
207207 return $ this ;
208208 }
209209
210+ /**
211+ * Automatically set a font and/or background color based on the supplied name
212+ *
213+ * @param bool $foreground
214+ * @param bool $background
215+ *
216+ * @return $this
217+ */
218+ public function autoColor (bool $ foreground = true , bool $ background = true , int $ saturation = 85 , int $ luminance = 60 )
219+ {
220+
221+ $ hue = (crc32 ($ this ->name ) % 360 ) / 360 ;
222+ $ saturation /= 100 ;
223+ $ luminance /= 100 ;
224+
225+ $ this ->bgColor = $ this ->convertHSLtoRGB ($ hue , $ saturation , $ luminance );
226+ $ this ->fontColor = $ this ->getContrastColor ($ this ->bgColor );
227+
228+ return $ this ;
229+ }
230+
210231 /**
211232 * Set the font file by path or int (1-5).
212233 *
@@ -738,4 +759,116 @@ protected function getFontByScript() {
738759
739760 return $ this ->getFontFile ();
740761 }
762+
763+ /**
764+ * Convert HSL color value produced by autoColor() to RGB value expected by image driver
765+ */
766+ protected function convertHSLtoRGB ($ h , $ s , $ l , $ toHex = true )
767+ {
768+ assert ((0 <= $ h ) && ($ h <= 1 ));
769+
770+ $ red = $ l ;
771+ $ green = $ l ;
772+ $ blue = $ l ;
773+
774+ $ v = ($ l <= 0.5 ) ? ($ l * (1.0 + $ s )) : ($ l + $ s - $ l * $ s );
775+ if ($ v > 0 ) {
776+ $ m = $ l + $ l - $ v ;
777+ $ sv = ($ v - $ m ) / $ v ;
778+ $ h *= 6.0 ;
779+ $ sextant = floor ($ h );
780+ $ fract = $ h - $ sextant ;
781+ $ vsf = $ v * $ sv * $ fract ;
782+ $ mid1 = $ m + $ vsf ;
783+ $ mid2 = $ v - $ vsf ;
784+
785+ switch ($ sextant ) {
786+ case 0 :
787+ $ red = $ v ;
788+ $ green = $ mid1 ;
789+ $ blue = $ m ;
790+ break ;
791+ case 1 :
792+ $ red = $ mid2 ;
793+ $ green = $ v ;
794+ $ blue = $ m ;
795+ break ;
796+ case 2 :
797+ $ red = $ m ;
798+ $ green = $ v ;
799+ $ blue = $ mid1 ;
800+ break ;
801+ case 3 :
802+ $ red = $ m ;
803+ $ green = $ mid2 ;
804+ $ blue = $ v ;
805+ break ;
806+ case 4 :
807+ $ red = $ mid1 ;
808+ $ green = $ m ;
809+ $ blue = $ v ;
810+ break ;
811+ case 5 :
812+ $ red = $ v ;
813+ $ green = $ m ;
814+ $ blue = $ mid2 ;
815+ break ;
816+ }
817+ }
818+
819+ $ red = round ($ red * 255 , 0 );
820+ $ green = round ($ green * 255 , 0 );
821+ $ blue = round ($ blue * 255 , 0 );
822+
823+ if ($ toHex ) {
824+ $ red = ($ red < 15 ) ? '0 ' . dechex ($ red ) : dechex ($ red );
825+ $ green = ($ green < 15 ) ? '0 ' . dechex ($ green ) : dechex ($ green );
826+ $ blue = ($ blue < 15 ) ? '0 ' . dechex ($ blue ) : dechex ($ blue );
827+ return "# {$ red }{$ green }{$ blue }" ;
828+ } else {
829+ return ['red ' => $ red , 'green ' => $ green , 'blue ' => $ blue ];
830+ }
831+ }
832+
833+ /**
834+ * Get contrasting foreground color for autoColor background
835+ */
836+ protected function getContrastColor ($ hexColor )
837+ {
838+
839+ // hexColor RGB
840+ $ R1 = hexdec (substr ($ hexColor , 1 , 2 ));
841+ $ G1 = hexdec (substr ($ hexColor , 3 , 2 ));
842+ $ B1 = hexdec (substr ($ hexColor , 5 , 2 ));
843+
844+ // Black RGB
845+ $ blackColor = "#000000 " ;
846+ $ R2BlackColor = hexdec (substr ($ blackColor , 1 , 2 ));
847+ $ G2BlackColor = hexdec (substr ($ blackColor , 3 , 2 ));
848+ $ B2BlackColor = hexdec (substr ($ blackColor , 5 , 2 ));
849+
850+ // Calc contrast ratio
851+ $ L1 = 0.2126 * pow ($ R1 / 255 , 2.2 ) +
852+ 0.7152 * pow ($ G1 / 255 , 2.2 ) +
853+ 0.0722 * pow ($ B1 / 255 , 2.2 );
854+
855+ $ L2 = 0.2126 * pow ($ R2BlackColor / 255 , 2.2 ) +
856+ 0.7152 * pow ($ G2BlackColor / 255 , 2.2 ) +
857+ 0.0722 * pow ($ B2BlackColor / 255 , 2.2 );
858+
859+ $ contrastRatio = 0 ;
860+ if ($ L1 > $ L2 ) {
861+ $ contrastRatio = (int )(($ L1 + 0.05 ) / ($ L2 + 0.05 ));
862+ } else {
863+ $ contrastRatio = (int )(($ L2 + 0.05 ) / ($ L1 + 0.05 ));
864+ }
865+
866+ // If contrast is more than 5, return black color
867+ if ($ contrastRatio > 5 ) {
868+ return '#000000 ' ;
869+ } else {
870+ // if not, return white color.
871+ return '#FFFFFF ' ;
872+ }
873+ }
741874}
0 commit comments