>
------------------------------------------------------------------------------
See main.inc.php for release information
Provided classes :
* RGB
public functions :
__construct($R, $G, $B)
set($R, $G, $B)
setInt($value)
get($floatValue=false)
getHexString()
getInt()
getHSV()
setHSV(HSV $hsv)
private functions :
setProperty($property, $value)
* HSV
public functions :
__construct($H, $S, $V)
set($H, $S, $V)
get()
getRGB()
setRGB(RGB $rgb)
private functions :
setProperty($property, $value)
* ColorStat
public functions :
static getFileColors($fileName, $colorTable, $quality=1)
static RGBtoHSV(RGB $RGB)
static HSVtoRGB(HSV $HSV)
static IntToRGB($rgb)
static getColorTable($huePrec=10, $prec=10, $returnedType='HSV')
static getColorFromTable(HSV $hsvObject, $colorTable)
--------------------------------------------------------------------------- */
if(!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
/**
* if DEBUG_MODE is set to true, the getFileColors function save a jpg file of
* the 'viewed' image :
* - resampled file
* - color from the color table
*
* use it only for debug, or if you are curious about what the function really
* see
*/
define('DEBUG_MODE', false);
/**
* The RGB class allows to read & write a RGB value
*/
class RGB {
protected $RGB = Array('R' => 0, 'G' => 0, 'B' => 0);
public function __construct($R=0, $G=0, $B=0)
{
$this->set($R, $G, $B);
}
/**
* set the R,G and B values
*
* @param Byte $R : the red value, between [0..255]
* @param Byte $G : the green value, between [0..255]
* @param Byte $B : the blue value, between [0..255]
* @return Array('R'=>$R, 'G'=>$G, 'B'=>$B)
*/
public function set($R, $G, $B)
{
$this->setProperty('R', $R);
$this->setProperty('G', $G);
$this->setProperty('B', $B);
return($this->get());
}
/**
* set RGB values from an Integer (0xFFFFFF : white value)
*
* @param Integer $value : the RGB value
* @return Array('R'=>$R, 'G'=>$G, 'B'=>$B)
*/
public function setInt($value)
{
$tmp=ColorStat::IntToRGB($value);
$tmp2=$tmp->get();
$this->set($tmp2['R'], $tmp2['G'], $tmp2['B']);
unset($tmp2);
unset($tmp);
}
/**
* returns the current RGB values as array
*
* @param Boolean $floatValue : if set to true, values are returned as float
* values between [0..1] otherwise values are
* returned as integer between [0..255]
* @return Array('R'=>$R, 'G'=>$G, 'B'=>$B)
*/
public function get($floatValue=false)
{
if($floatValue)
{
return(
Array(
'R' => $this->RGB['R']/255,
'G' => $this->RGB['G']/255,
'B' => $this->RGB['B']/255,
)
);
}
else
{
return($this->RGB);
}
}
/**
* returns the current RGB values as hex string ('FFFFFF' : white)
*
* @return String
*/
public function getHexString()
{
return(sprintf('%02x%02x%02x', $this->RGB['R'], $this->RGB['G'], $this->RGB['B']));
}
/**
* returns the current RGB values as integer (0xFFFFFF : white)
*
* @return Integer
*/
public function getInt()
{
return( $this->RGB['R']<<16 + $this->RGB['G']<<8 + $this->RGB['B']);
}
/**
* returns the current RGB values as a HSV object
*
* @return HSV
*/
public function getHSV()
{
return(ColorStat::RGBtoHSV($this));
}
/**
* set the RGB values from a HSV ojbect
*
* @param HSV $hsv : a HSV object
*/
public function setHSV(HSV $hsv)
{
$tmp=ColorStat::HSVtoRGB($hsv);
$tmp2=$tmp->get();
$this->set($tmp2['R'], $tmp2['G'], $tmp2['B']);
unset($tmp2);
unset($tmp);
}
/**
* set the RGB property
*
* @param String $property : 'R', 'G', 'B'
* @param Integer $value : value between [0..255]
* @return Integer : value of the property
*/
private function setProperty($property, $value)
{
if($property=='R' or $property=='G' or $property=='B')
{
if($value<0) $value=0;
if($value>255) $value=255;
$this->RGB[$property]=$value;
return($this->RGB[$property]);
}
}
}
/**
* The HSV class allows to read & write a HSV value
*/
class HSV {
protected $HSV = Array('H' => 0, 'S' => 0, 'V' => 0);
public function __construct($H=0, $S=0, $V=0)
{
$this->set($H, $S, $V);
}
/**
* set the H, S and V values
*
* @param Integer $H : the hue value, between [0..360]
* @param Byte $S : the saturation value, between [0..100]
* @param Byte $V : the value value, between [0..100]
* @return Array('H'=>$H, 'S'=>$S, 'V'=>$V)
*/
public function set($H, $S, $V)
{
$this->setProperty('H', $H);
$this->setProperty('S', $S);
$this->setProperty('V', $V);
return($this->get());
}
/**
* returns the current HSV values as array
*
* @return Array('H'=>$H, 'S'=>$S, 'V'=>$V)
*/
public function get()
{
return($this->HSV);
}
/**
* returns the current HSV values as a RGB object
*
* @return RGB
*/
public function getRGB()
{
return(ColorStat::HSVtoRGB($this));
}
/**
* set the HSV values from a RGB ojbect
*
* @param RGB $rgb : a RGB object
*/
public function setRGB(RGB $rgb)
{
$tmp=ColorStat::RGBtoHSV($rgb);
$tmp2=$tmp->get();
$this->set($tmp2['H'], $tmp2['S'], $tmp2['V']);
unset($tmp2);
unset($tmp);
}
/**
* set the HSV property
*
* @param String $property : 'H', 'S', 'V'
* @param Integer $value : value between [0..255]
* @return Integer : value of the property
*/
private function setProperty($property, $value)
{
if($property=='H')
{
$this->HSV['H']=$value%360;
return($this->HSV['H']);
}
elseif($property=='S' or $property=='V')
{
if($value<0) $value=0;
if($value>100) $value=100;
$this->HSV[$property]=$value;
return($this->HSV[$property]);
}
return(false);
}
}
class ColorStat {
static public $fileColorsStat = Array(
'pixels' => 0,
'analyzed' => 0,
'time' => 0,
'colors' =>0,
'fileName' => "",
'quality' => 0,
);
/**
* returns colors of an image file
*
* return :
*
*
*
* @param String $fileName : the name of picture to scan
* @param String $colorTable : the color table model
* @param String $options : Array of options
* 'quality' : set the quality for analyze
* 'maxTime' : set the maximum time for analyze
* 'pps' : pixel per second analyzed
* if 'maxTime' and 'pps' are greater than zero, the
* quality parameter is computed automatically
* @return : -1 if file doesn't exist
* -2 if file is not a PNG, a JPEG or a GIF file
* -3 if a fatal error occurs
* array of HSV objects if everthing is Ok
*/
static function getFileColors($fileName, $colorTable, $options=array())
{
$options=self::checkOptions($options);
self::$fileColorsStat=Array(
'pixels' => 0,
'analyzed' => 0,
'time' => 0,
'pps' =>0,
);
if(file_exists($fileName))
{
$time=microtime(true);
try
{
if(preg_match('/.*\.gif$/i', $fileName))
{
$image = imagecreatefromgif($fileName);
}
elseif(preg_match('/.*\.(jpg|jpeg)$/i', $fileName))
{
$image = imagecreatefromjpeg($fileName);
}
elseif(preg_match('/.*\.png$/i', $fileName))
{
$image = imagecreatefrompng($fileName);
}
else
{
return(-2);
}
$imageWidth=imagesx($image);
$imageHeight=imagesy($image);
if($options['mode']=='numAnalyzed')
{
$quality=round(sqrt($imageWidth*$imageHeight/$options['numAnalyzed']), 0);
}
elseif($options['mode']=='maxTime')
{
$quality=round(sqrt($imageWidth*$imageHeight/($options['pps']*$options['maxTime'])), 0);
}
else
{
$quality=$options['quality'];
}
$imageWorkWidth=round($imageWidth/$quality,0);
$imageWorkHeight=round($imageHeight/$quality,0);
$imageWork=imagecreatetruecolor($imageWorkWidth,$imageWorkHeight);
imagecopyresampled($imageWork, $image, 0, 0, 0, 0, $imageWorkWidth, $imageWorkHeight, $imageWidth, $imageHeight);
//imagecopyresized($imageWork, $image, 0, 0, 0, 0, $imageWorkWidth, $imageWorkHeight, $imageWidth, $imageHeight);
imagedestroy($image);
$returned=Array();
$i=0;
for($px=0;$px<$imageWorkWidth;$px++)
{
for($py=0;$py<$imageWorkHeight;$py++)
{
$i++;
$value=imagecolorat($imageWork, $px, $py);
$rgb=self::IntToRGB($value);
//echo sprintf("%06x", $value)." => ".$rgb->getHexString();
//echo " ($i) ".$color->getHexString()."
";
if(DEBUG_MODE)
{
$color=self::getColorFromTable($rgb->getHSV(), $colorTable);
$newRGB=$color->get();
$col=imagecolorallocate($imageWork, $newRGB['R'], $newRGB['G'], $newRGB['B']);
imagesetpixel($imageWork, $px, $py, $col);
imagecolordeallocate($imageWork, $col);
$color=$color->getHexString();
unset($newRGB);
}
else
{
$color=self::getColorFromTable($rgb->getHSV(), $colorTable)->getHexString();
}
if(array_key_exists($color, $returned))
{
$returned[$color]['num']++;
}
else
{
$returned[$color]=Array(
'hsv' => $rgb->getHSV()->get(),
'num' => 1,
'pct' => 0,
);
}
unset($rgb);
}
}
if(DEBUG_MODE)
{
$fName="q".$quality."_c".$options['numColors']."_nb".count($returned)."_".$fileName.".png";
imagepng($imageWork, $fName);
}
imagedestroy($imageWork);
uasort($returned, Array('ColorStat', 'sortTones'));
if($options['numColors']>0)
{
foreach($returned as $key=>$val)
{
$returnedColors[$key]=$val;
$options['numColors']--;
if($options['numColors']<=0) break;
}
}
else
{
$returnedColors=$returned;
}
self::$fileColorsStat=Array(
'pixels' => $imageWidth*$imageHeight,
'analyzed' => $i,
'time' => microtime(true)-$time,
'colors' => count($returned),
'pps' => $i/(microtime(true)-$time),
'quality' => $quality,
);
if(DEBUG_MODE)
{
self::$fileColorsStat['fileName']=$fName;
}
unset($returned);
foreach($returnedColors as $key => $val)
{
$returnedColors[$key]['pct']=round(100*$val['num']/self::$fileColorsStat['analyzed'],2);
}
return($returnedColors);
}
catch (Exception $e)
{
echo "ERROR!
".print_r($e, true);
return(-3);
}
}
else
{
return(-1);
}
}
/**
* Calculate the HSV value from a RGB value
*
* @param RGB $RGB : RGB object
* @return HSV : new HSV object
*/
static public function RGBtoHSV(RGB $RGB)
{
$rgbValues=$RGB->get(true);
$max=self::max($rgbValues);
$min=self::min($rgbValues);
if($max['value']==$min['value'])
{
$H=0;
}
elseif($max['key']=='R')
{
$H=(60*($rgbValues['G']-$rgbValues['B'])/($max['value']-$min['value'])+360)%360;
}
elseif($max['key']=='G')
{
$H=(60*($rgbValues['B']-$rgbValues['R'])/($max['value']-$min['value'])+120);
}
elseif($max['key']=='B')
{
$H=(60*($rgbValues['R']-$rgbValues['G'])/($max['value']-$min['value'])+240);
}
$S=round(100*(($max['value']==0)?0:1-$min['value']/$max['value']),0);
$V=round(100*$max['value'],0);
return(new HSV($H, $S, $V));
}
/**
* Calculate the RGB value from a HSV value
*
* @param HSV $HSV : HSV object
* @return RGB : new RGB object
*/
static public function HSVtoRGB(HSV $HSV)
{
$hsvValues=$HSV->get();
$h=abs($hsvValues['H']/60)%6;
$f=$hsvValues['H']/60-$h;
$l=round(2.55*$hsvValues['V']*(1-$hsvValues['S']/100),0);
$m=round(2.55*$hsvValues['V']*(1-$f*$hsvValues['S']/100),0);
$n=round(2.55*$hsvValues['V']*(1-(1-$f)*$hsvValues['S']/100),0);
$v=round(2.55*$hsvValues['V'],0);
switch($h)
{
case 0:
return(new RGB($v, $n, $l));
break;
case 1:
return(new RGB($m, $v, $l));
break;
case 2:
return(new RGB($l, $v, $n));
break;
case 3:
return(new RGB($l, $m, $v));
break;
case 4:
return(new RGB($n, $l, $v));
break;
case 5:
return(new RGB($v, $l, $m));
break;
}
}
/**
*
* @param Int $rgb : an integer &hRRGGBB
* @return RGB : a RGB object
*/
static public function IntToRGB($rgb)
{
return(new RGB(($rgb >> 16) & 0xFF, ($rgb >> 8) & 0xFF, $rgb & 0xFF, true));
}
/**
* return a color table
* $table[h][s][v] => HSV object or string 'RRGGBB'
*
* @param Int $huePrec : degree of precision for hue [1..360]
* @param Float $prec : precision step for saturation & value [1..100]
* @param String $returnedType : 'HSV' => return a HSV object
* 'color' => return a color string 'RRGGBB'
* @return Array : the color table
*/
static public function getColorTable($huePrec=10, $prec=10, $returnedType='HSV')
{
$returned=Array();
for($hue=0;$hue<360;$hue+=$huePrec)
{
$hueValues=Array();
for($saturation=0;$saturation<=100;$saturation+=$prec)
{
$saturationValues=Array();
for($value=0;$value<=100;$value+=$prec)
{
$hsv=new HSV($hue, $saturation, $value);
if($returnedType=='HSV')
{
$saturationValues[$value]=$hsv;
}
else
{
$saturationValues[$value]=$hsv->getRGB()->getHexString();
}
unset($hsv);
}
$hueValues[$saturation]=$saturationValues;
unset($saturationValues);
}
$returned[$hue]=$hueValues;
unset($hueValues);
}
return($returned);
}
/**
* @param Array : an array
* @return Array : an array, giving the minimum value and the related key
*/
static protected function min($values)
{
$minKey="";
$minValue=0;
foreach($values as $key => $val)
{
if($minKey=='' or $val<$minValue)
{
$minKey=$key;
$minValue=$val;
}
}
return(Array('key' => $minKey, 'value' => $minValue));
}
/**
* reverted sort color
*
*/
static protected function sortTones($a, $b)
{
if($a['num'] == $b['num'])
{
return(0);
}
return ($a['num'] > $b['num']) ? -1 : 1;
}
/**
* @param Array : an array
* @return Array : an array, giving the maximum value and the related key
*/
static protected function max($values)
{
$maxKey="";
$maxValue=0;
foreach($values as $key => $val)
{
if($maxKey=='' or $val>$maxValue)
{
$maxKey=$key;
$maxValue=$val;
}
}
return(Array('key' => $maxKey, 'value' => $maxValue));
}
/**
* check the validity for getFileColors() options
* if no parameters are given, return the default options values
*
* @param Array $options : an array with given options values
* @return Array : an array with valid options values
*/
static protected function checkOptions($options=Array())
{
if(!is_array($options))
{
$options=Array();
}
if(!array_key_exists('quality', $options)) $options['quality']=1;
if(!array_key_exists('maxTime', $options)) $options['maxTime']=0.5;
if(!array_key_exists('pps', $options)) $options['pps']=1;
if(!array_key_exists('numAnalyzed', $options)) $options['numAnalyzed']=600;
if(!array_key_exists('numColors', $options)) $options['numColors']=0;
if(!array_key_exists('mode', $options)) $options['mode']='quality';
if($options['quality']<=0) $options['quality']=1;
if($options['quality']>20) $options['quality']=20;
if($options['maxTime']<0) $options['maxTime']=0.5;
if($options['pps']<0) $options['pps']=1;
if($options['numAnalyzed']<0) $options['numAnalyzed']=600;
if($options['numColors']<0) $options['numColors']=16;
if($options['mode']!='quality' and
$options['mode']!='numAnalyzed' and
$options['mode']!='maxTime') $options['mode']='quality';
return($options);
}
/**
* for the given color, return the nearest color of the color table
*
* @param HSV $hsvObject : the color, as HSV object
* @param Array $colorTable : the colorTable
* @param String $mode : 'HSV' or 'RGB' to define the returned object
* @return HSV or RGB : the color
*/
static public function getColorFromTable(HSV $hsvObject, $colorTable, $mode='RGB')
{
$hsv=$hsvObject->get();
//echo "*H:".$hsv['H']." ";
//echo "*S:".$hsv['S']." ";
//echo "*V:".$hsv['V']."
";
$hue=360/count($colorTable);
$hueNumber=round($hsv['H']/$hue,0);
$step=100/(count($colorTable[0])-1);
//echo "*H_Step:$hue
";
//echo "*SV_Step:$step
";
$hsv['S']=round((100/$step)*$hsv['S']/100,0)*$step;
$hsv['V']=round((100/$step)*$hsv['V']/100,0)*$step;
$hsv['H']=($hueNumber*$hue)%360;
//echo "*H:".$hsv['H']." ";
//echo "*S:".$hsv['S']." ";
//echo "*V:".$hsv['V']."
";
if($mode=='RGB')
{
return($colorTable[$hsv['H']][$hsv['S']][$hsv['V']]->getRGB());
}
else
{
return($colorTable[$hsv['H']][$hsv['S']][$hsv['V']]);
}
}
}
?>