@@ -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}
0 commit comments