167 lines
3.5 KiB
PHP
167 lines
3.5 KiB
PHP
<?php
|
|
/**
|
|
* @brief Letter photo generator for member accounts
|
|
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
|
* @copyright (c) Invision Power Services, Inc.
|
|
* @license https://www.invisioncommunity.com/legal/standards/
|
|
* @package Invision Community
|
|
* @since 3 Feb 2017
|
|
*/
|
|
|
|
namespace IPS\Member;
|
|
|
|
/* To prevent PHP errors (extending class does not exist) revealing path */
|
|
|
|
use function defined;
|
|
use function mb_strtolower;
|
|
use function ord;
|
|
|
|
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
|
{
|
|
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Letter photo generator for member accounts
|
|
*/
|
|
class LetterPhoto
|
|
{
|
|
/**
|
|
* @brief Member name
|
|
*/
|
|
protected ?string $memberName = NULL;
|
|
|
|
/**
|
|
* Create a new photo object
|
|
*
|
|
* @param string $name Member name
|
|
* @return void
|
|
*/
|
|
public function __construct( string $name )
|
|
{
|
|
$this->memberName = $name;
|
|
}
|
|
|
|
/**
|
|
* @brief Color saturation to use for HSV colors
|
|
*/
|
|
protected float $colorCodeSaturation = .45;
|
|
|
|
/**
|
|
* @brief Color value to use for HSV colors
|
|
*/
|
|
protected float $colorCodeValue = 0.575;
|
|
|
|
/**
|
|
* @brief If we have just generated a hue on this page load, store it to better randomize the next color
|
|
*/
|
|
protected static ?float $lastHue = NULL;
|
|
|
|
/**
|
|
* Return a unique hex color code based on the name.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function generateColorCode() : string
|
|
{
|
|
/* If we've already generated a hue on this page load, use the golden ratio to find a number sufficiently distinct */
|
|
if( static::$lastHue )
|
|
{
|
|
$hue = static::$lastHue + 0.618033988749895;
|
|
|
|
if( $hue > 1.0 )
|
|
{
|
|
$hue -= 1.0;
|
|
}
|
|
|
|
static::$lastHue = $hue;
|
|
|
|
return $this->convertRgbToHex( $this->convertHsvToRgb( $hue, $this->colorCodeSaturation, $this->colorCodeValue ) );
|
|
}
|
|
|
|
$hue = ( ( ord( mb_strtolower( $this->memberName ) ) - 97 ) / 25.0 ) + 0.25;
|
|
$hue *= 1.61803398875;
|
|
$hue *= (float) ( '1.' . rand() ) / 1;
|
|
|
|
if( rand( 0, 1 ) )
|
|
{
|
|
$float = (float) ( "1." . ord( array_rand( range( 'a', 'z' ) ) ) );
|
|
$hue = abs( $float - $hue );
|
|
}
|
|
|
|
while( $hue > 1.0 )
|
|
{
|
|
$hue -= 1.0;
|
|
}
|
|
|
|
static::$lastHue = $hue;
|
|
|
|
return $this->convertRgbToHex( $this->convertHsvToRgb( $hue, $this->colorCodeSaturation, $this->colorCodeValue ) );
|
|
}
|
|
|
|
/**
|
|
* Convert the HSV value to RGB
|
|
*
|
|
* @param float $h Hue
|
|
* @param float $s Saturation
|
|
* @param float $v Value
|
|
* @return array
|
|
*/
|
|
protected function convertHsvToRgb( float $h, float $s, float $v ): array
|
|
{
|
|
$rgb = array( $v, $v, $v );
|
|
$diff = ( $v <= 0.5 ) ? ( $v * ( 1.0 + $s ) ) : ( $v + $s - $v * $s );
|
|
|
|
if( $diff )
|
|
{
|
|
$m = $v + $v - $diff;
|
|
$sv = ( $diff - $m ) / $diff;
|
|
$h *= 6.0;
|
|
$fract = $h - floor( $h );
|
|
$vsf = $diff * $sv * $fract;
|
|
$mid1 = $m + $vsf;
|
|
$mid2 = $diff - $vsf;
|
|
|
|
switch( floor( $h ) )
|
|
{
|
|
case 0:
|
|
$rgb = array( $diff, $mid1, $m );
|
|
break;
|
|
|
|
case 1:
|
|
$rgb = array( $mid2, $diff, $m );
|
|
break;
|
|
|
|
case 2:
|
|
$rgb = array( $m, $diff, $mid1 );
|
|
break;
|
|
|
|
case 3:
|
|
$rgb = array( $m, $mid2, $diff );
|
|
break;
|
|
|
|
case 4:
|
|
$rgb = array( $mid1, $m, $diff );
|
|
break;
|
|
|
|
case 5:
|
|
$rgb = array( $diff, $m, $mid2 );
|
|
break;
|
|
}
|
|
}
|
|
|
|
return array_map( function( $value ) { return round( $value * 256.0 ); }, $rgb );
|
|
}
|
|
|
|
/**
|
|
* Convert an RGB color value to hex
|
|
*
|
|
* @param array $rgb RGB color values
|
|
* @return string
|
|
*/
|
|
protected function convertRgbToHex( array $rgb ): string
|
|
{
|
|
return sprintf( "%02x%02x%02x", $rgb[0], $rgb[1], $rgb[2] );
|
|
}
|
|
} |