lib/Ajde/Document/Processor/Css/lib/maximizer/inc/ColorSpace.php
<?php
/*
Color Space : v1.25 : 2009.04.20
————————————————————————————————
XYZ <-> Luv <-> LCHuv
XYZ <-> Lab <-> LCHab
RGB <-> XYZ <-> xyY
RGB <-> HSL
RGB <-> HSV <-> RYB
RGB <-> CMY <-> CMYK
RGB <-> HEX <-> STRING
*/
class ColorSpace
{
private $RYB_H = [];
private $H_RYB = [];
private $_XYZ_RGB = [];
private $White;
private $_xyY;
public function __construct()
{
$wheel = [
[0, 0],
[15, 8], // Red
[30, 17],
[45, 26], // Orange
[60, 34],
[75, 41], // Yellow
[90, 48],
[105, 54], // Lime
[120, 60],
[135, 81], // Green
[150, 103],
[165, 123], // Teal
[180, 138],
[195, 155], // Cyan
[210, 171],
[225, 187], // Azure
[240, 204],
[255, 219], // Blue
[270, 234],
[285, 251], // Indigo
[300, 267],
[315, 282], // Purple
[330, 298],
[345, 329], // Pink
[360, 0],
];
$a;
$b;
$i;
$H;
$_H;
$H_;
for ($H = 0; $H < 360; $H++) {
$H_ = false;
$_H = false;
for ($i = 0; $i < 24; $i++) {
$a = $wheel[$i];
$b = $wheel[$i + 1];
if ($b && $b[1] < $a[1]) {
$b[1] += 360;
}
if (!$H_ && $a[0] <= $H && $b[0] > $H) {
$this->H_RYB[$H] = (($a[1] + ($b[1] - $a[1]) * ($H - $a[0]) / ($b[0] - $a[0])) % 360);
$H_ = true;
}
if (!$_H && $a[1] <= $H && $b[1] > $H) {
$this->RYB_H[$H] = (($a[0] + ($b[0] - $a[0]) * ($H - $a[1]) / ($b[1] - $a[1])) % 360);
$_H = true;
}
if ($H_ == true && _H == true) {
break;
}
}
}
$this->White = $this->illuminant('2', 'D65');
$this->profile('sRGB');
// echo "this->White = ";
// print_r($this->White);
}
public function RYB_HSV($o)
{
$n = floor($o['H']);
$x = $n > 0 ? $o['H'] % $n : 0;
$a = $this->RYB_H[$n % 360];
$b = $this->RYB_H[ceil($o['H']) % 360];
return [
'H' => $a + ($b - $a) * $x,
'S' => $o['S'],
'V' => $o['V'],
];
}
public function HSV_RYB($o)
{
$n = floor($o['H']);
$x = $n > 0 ? $o['H'] % $n : 0;
$a = $this->H_RYB[$n % 360];
$b = $this->H_RYB[ceil($o['H']) % 360];
return [
'H' => $a + ($b - $a) * $x,
'S' => $o['S'],
'V' => $o['V'],
];
}
public function STRING_HEX($o)
{
return 0 + ('0x'.$o);
}
public function HEX_STRING($o)
{
$str = sprintf('%X', $o);
$n = strlen($str);
while ($n < 6) {
$str = '0'.$str;
$n++;
}
return $str;
}
public function HEX_RGB($o)
{
return [
'R' => ($o >> 16),
'G' => ($o >> 8) & 0xFF,
'B' => $o & 0xFF,
];
}
public function HEX32_RGBA($o)
{
return [
'R' => $o >> 16 & 0xFF,
'G' => $o >> 9 & 0xFF,
'B' => $o & 0xFF,
'A' => $o >> 24,
];
}
public function RGBA_HEX32($o)
{
return ($o['A'] << 24 | $o['R'] << 16 | $o['G'] << 8 | $o['B']) >> 0;
}
public function HEX32_rgbaa($o)
{
return 'rgba('.($o >> 16 & 0xFF).','.
($o >> 8 & 0xFF).','.($o & 0xFF).','.
(($o >> 24) / 255).')';
}
/*
function RGB_STRING($o)
{
return $this->HEX_STRING($this->RGB_HEX($o));
}
function RGB_rgbaa($o)
{
return 'rgba('. $o['R'] .','.$o['G'].','.$o['B'].','.$o['A'].')';
}
function HEX_rgba($o)
{
return $this->HEX32_rgbaa($o);
}
*/
public function RGB_HEX($o)
{
return $o['R'] << 16 | $o['G'] << 8 | $o['B'];
}
public function RGB_CMY($o)
{
return [
'C' => 1 - ($o['R'] / 255),
'M' => 1 - ($o['G'] / 255),
'Y' => 1 - ($o['B'] / 255),
];
}
public function RGB_HSL($o)
{
$_R = $o['R'] / 255;
$_G = $o['G'] / 255;
$_B = $o['B'] / 255;
$min = min($_R, $_G, $_B);
$max = max($_R, $_G, $_B);
$D = $max - $min;
$L = ($max + $min) / 2;
if ($D == 0) {
$H = 0;
$S = 0;
} // No Chroma
else {
if ($L < 0.5) {
$S = $D / ($max + $min);
} else {
$S = $D / (2 - $max - $min);
}
$DR = ((($max - $_R) / 6) + ($D / 2)) / $D;
$DG = ((($max - $_G) / 6) + ($D / 2)) / $D;
$DB = ((($max - $_B) / 6) + ($D / 2)) / $D;
if ($_R == $max) {
$H = $DB - $DG;
} else {
if ($_G == $max) {
$H = (1 / 3) + $DR - $DB;
} else {
if ($_B == $max) {
$H = (2 / 3) + $DG - $DR;
}
}
}
if ($H < 0) {
$H += 1;
}
if ($H > 1) {
$H -= 1;
}
}
return [
'H' => $H * 360,
'S' => $S * 100,
'L' => $L * 100,
];
}
public function RGB_HSV($o)
{
$_R = $o['R'] / 255;
$_G = $o['G'] / 255;
$_B = $o['B'] / 255;
$min = min($_R, $_G, $_B);
$max = max($_R, $_G, $_B);
$D = $max - $min;
$V = $max;
if ($D == 0) {
$H = 0;
$S = 0;
} // No chroma
else { // Chromatic data
$S = $D / $max;
$DR = ((($max - $_R) / 6) + ($D / 2)) / $D;
$DG = ((($max - $_G) / 6) + ($D / 2)) / $D;
$DB = ((($max - $_B) / 6) + ($D / 2)) / $D;
if ($_R == $max) {
$H = $DB - $DG;
} else {
if ($_G == $max) {
$H = (1 / 3) + $DR - $DB;
} else {
if ($_B == $max) {
$H = (2 / 3) + $DG - $DR;
}
}
}
if ($H < 0) {
$H += 1;
}
if ($H > 1) {
$H -= 1;
}
}
return ['H' => $H * 360, 'S' => $S * 100, 'V' => $V * 100];
}
public function RGB_XYZ($o)
{
$M = $this->_RGB_XYZ;
$z = [];
$R = $o['R'] / 255;
$G = $o['G'] / 255;
$B = $o['B'] / 255;
if ($this->_Space == 'sRGB') {
$R = ($R > 0.04045) ? pow((($R + 0.055) / 1.055), 2.4) : $R / 12.92;
$G = ($G > 0.04045) ? pow((($G + 0.055) / 1.055), 2.4) : $G / 12.92;
$B = ($B > 0.04045) ? pow((($B + 0.055) / 1.055), 2.4) : $B / 12.92;
} else {
$R = pow($R, $this->_Gamma);
$G = pow($G, $this->_Gamma);
$B = pow($B, $this->_Gamma);
}
$z['X'] = $R * $M[0] + $G * $M[3] + $B * $M[6];
$z['Y'] = $R * $M[1] + $G * $M[4] + $B * $M[7];
$z['Z'] = $R * $M[2] + $G * $M[5] + $B * $M[8];
return $z;
}
public function CMY_RGB($o)
{
return [
'R' => max(0, (1 - $o['C']) * 255),
'G' => max(0, (1 - $o['M']) * 255),
'B' => max(0, (1 - $o['Y']) * 255),
];
}
public function CMY_CMYK($o)
{
$C = $o['C'];
$M = $o['M'];
$Y = $o['Y'];
$K = min($Y, min($M, min($C, 1)));
$C = round(($C - $K) / (1 - $K) * 100);
$M = round(($M - $K) / (1 - $K) * 100);
$Y = round(($Y - $K) / (1 - $K) * 100);
$K = round($K * 100);
return ['C' => $C, 'M' => $M, 'Y' => $Y, 'K' => $K];
}
// CMYK = C: Cyan / M: Magenta / Y: Yellow / K: Key (black)
public function CMYK_CMY($o)
{
return [
'C' => ($o['C'] * (1 - $o['K']) + $o['K']),
'M' => ($o['M'] * (1 - $o['K']) + $o['K']),
'Y' => ($o['Y'] * (1 - $o['K']) + $o['K']),
];
}
// HSL (1978) = H: Hue / S: Saturation / L: Lightess
public function Hue_2_RGB($v1, $v2, $vH)
{
if ($vH < 0) {
$vH += 1;
}
if ($vH > 1) {
$vH -= 1;
}
if ((6 * $vH) < 1) {
return $v1 + ($v2 - $v1) * 6 * $vH;
}
if ((2 * $vH) < 1) {
return $v2;
}
if ((3 * $vH) < 2) {
return $v1 + ($v2 - $v1) * ((2 / 3) - $vH) * 6;
}
return $v1;
}
public function HSL_RGB($o)
{
$H = $o['H'] / 360;
$S = $o['S'] / 100;
$L = $o['L'] / 100;
$R;
$G;
$B;
$_1;
$_2;
if ($S == 0) { // HSL from 0 to 1
$R = $L * 255;
$G = $L * 255;
$B = $L * 255;
} else {
if ($L < 0.5) {
$_2 = $L * (1 + $S);
} else {
$_2 = ($L + $S) - ($S * $L);
}
$_1 = 2 * $L - $_2;
$R = 255 * $this->Hue_2_RGB($_1, $_2, $H + (1 / 3));
$G = 255 * $this->Hue_2_RGB($_1, $_2, $H);
$B = 255 * $this->Hue_2_RGB($_1, $_2, $H - (1 / 3));
}
return ['R' => $R, 'G' => $G, 'B' => $B];
}
// HSV (1978) = H: Hue / S: Saturation / V: Value
public function HSV_RGB($o)
{
$H = $o['H'] / 360;
$S = $o['S'] / 100;
$V = $o['V'] / 100;
$R;
$G;
$B;
if ($S == 0) {
$R = $G = $B = round($V * 255);
} else {
if ($H >= 1) {
$H = 0;
}
$H = 6 * $H;
$D = $H - floor($H);
$A = round(255 * $V * (1 - $S));
$B = round(255 * $V * (1 - ($S * $D)));
$C = round(255 * $V * (1 - ($S * (1 - $D))));
$V = round(255 * $V);
switch (floor($H)) {
case 0:
$R = $V;
$G = $C;
$B = $A;
break;
case 1:
$R = $B;
$G = $V;
$B = $A;
break;
case 2:
$R = $A;
$G = $V;
$B = $C;
break;
case 3:
$R = $A;
$G = $B;
$B = $V;
break;
case 4:
$R = $C;
$G = $A;
$B = $V;
break;
case 5:
$R = $V;
$G = $A;
$B = $B;
break;
}
}
return ['R' => $R, 'G' => $G, 'B' => $B];
}
// CIE (Commission International de L’Eclairage)
// CIE-XYZ (1931) = Y: Luminescence / XZ: Spectral Weighting Curves (Spectral Locus)
public function XYZ_RGB($o)
{
$M = $this->_XYZ_RGB;
$z = [];
$z['R'] = $o['X'] * $M[0] + $o['Y'] * $M[3] + $o['Z'] * $M[6];
$z['G'] = $o['X'] * $M[1] + $o['Y'] * $M[4] + $o['Z'] * $M[7];
$z['B'] = $o['X'] * $M[2] + $o['Y'] * $M[5] + $o['Z'] * $M[8];
if ($this->_Space == 'sRGB') {
$z['R'] = ($z['R'] > 0.0031308) ? (1.055 * pow($z['R'], 1 / 2.4)) - 0.055 : 12.92 * $z['R'];
$z['G'] = ($z['G'] > 0.0031308) ? (1.055 * pow($z['G'], 1 / 2.4)) - 0.055 : 12.92 * $z['G'];
$z['B'] = ($z['B'] > 0.0031308) ? (1.055 * pow($z['B'], 1 / 2.4)) - 0.055 : 12.92 * $z['B'];
} else {
$z['R'] = pow($z['R'], 1 / $this->_Gamma);
$z['G'] = pow($z['G'], 1 / $this->_Gamma);
$z['B'] = pow($z['B'], 1 / $this->_Gamma);
}
return ['R' => round($z['R'] * 255), 'G' => round($z['G'] * 255), 'B' => round($z['B'] * 255)];
}
public function XYZ_xyY($o)
{
$n = $o['X'] + $o['Y'] + $o['Z'];
if ($n == 0) {
return ['x' => 0, 'y' => 0, 'Y' => $o['Y']];
}
return ['x' => $o['X'] / $n, 'y' => $o['Y'] / $n, 'Y' => $o['Y']];
}
public function XYZ_HLab($o)
{
$n = sqrt($o['Y']);
return [
'L' => 10 * $n,
'a' => 17.5 * (((1.02 * $o['X']) - $o['Y']) / $n),
'b' => 7 * (($o['Y'] - (0.847 * $o['Z'])) / $n),
];
}
public function XYZ_Lab($o)
{
$r = $this->White;
function fu($n)
{
if ($n > 0.008856) {
return pow($n, 1 / 3);
} else {
return (7.787 * $n) + (16 / 116);
}
}
$X = fu($o['X'] / $r['X']);
$Y = fu($o['Y'] / $r['Y']);
$Z = fu($o['Z'] / $r['Z']);
return ['L' => (116 * $Y) - 16, 'a' => 500 * ($X - $Y), 'b' => 200 * ($Y - $Z)];
}
public function XYZ_Luv($o)
{
$r = $this->White;
$U = (4 * $o['X']) / ($o['X'] + (15 * $o['Y']) + (3 * $o['Z']));
$V = (9 * $o['Y']) / ($o['X'] + (15 * $o['Y']) + (3 * $o['Z']));
if ($o['Y'] > 0.008856) {
$o['Y'] = pow($o['Y'], 1 / 3);
} else {
$o['Y'] = (7.787 * $o['Y']) + (16 / 116);
}
$_L = (116 * $o['Y']) - 16;
$_U = (4 * $r['X']) / ($r['X'] + (15 * $r['Y']) + (3 * $r['Z']));
$_V = (9 * $r['Y']) / ($r['X'] + (15 * $r['Y']) + (3 * $r['Z']));
return ['L' => $_L, 'u' => 13 * $_L * ($U - $_U), 'v' => 13 * $_L * ($V - $_V)];
}
// CIE-xyY (1931) = Y: Luminescence / xy: Chromaticity Co-ordinates (Spectral Locus)
public function xyY_XYZ($o)
{
return [
'X' => ($o['x'] * $o['Y']) / $o['y'],
'Y' => $o['Y'],
'Z' => ((1 - $o['x'] - $o['y']) * $o['Y']) / $o['y'],
];
}
// Hunter-L*ab (1948) = L: Lightness / ab: Color-opponent Dimensions
public function HLab_XYZ($o)
{
$_Y = $o['L'] / 10;
$_X = ($o['a'] / 17.5) * ($o['L'] / 10);
$_Z = ($o['b'] / 7) * ($o['L'] / 10);
$Y = pow($_Y, 2);
$X = ($_X + $Y) / 1.02;
$Z = -1 * ($_Z - $Y) / 0.847;
return ['X' => $X, 'Y' => $Y, 'Z' => $Z];
}
// CIE-L*ab (1976) = L: Luminescence / a: Red / Green / b: Blue / Yellow
public function Lab_XYZ($o)
{
$r = $this->White;
$Y = ($o['L'] + 16) / 116;
$X = $o['a'] / 500 + $Y;
$Z = $Y - $o['b'] / 200;
$Y = pow($Y, 3) > 0.008856 ? pow($Y, 3) : ($Y - 16 / 116) / 7.787;
$X = pow($X, 3) > 0.008856 ? pow($X, 3) : ($X - 16 / 116) / 7.787;
$Z = pow($Z, 3) > 0.008856 ? pow($Z, 3) : ($Z - 16 / 116) / 7.787;
return ['X' => $r['X'] * $X, 'Y' => $r['Y'] * $Y, $Z => $r['Z'] * $Z];
}
public function Lab_LCHab($o)
{
$H = atan2($o['b'], $o['a']) * (180 / PI);
if ($H < 0) {
$H += 360;
} else {
if ($H > 360) {
$H -= 360;
}
}
return ['L' => $o['L'], 'C' => sqrt($o['a'] * $o['a'] + $o['b'] * $o['b']), 'H' => $H];
}
// CIE-L*uv (1976) = L: Luminescence / u: Saturation / v: Hue
public function Luv_XYZ($o)
{
$r = $White;
$Y = ($o['L'] + 16) / 116;
$Y = (pow($Y, 3) > 0.008856) ? pow($Y, 3) : (($Y - 16 / 116) / 7.787);
$_U = (4 * $r['X']) / ($r['X'] + (15 * $r['Y']) + (3 * $r['Z']));
$_V = (9 * $r['Y']) / ($r['X'] + (15 * $r['Y']) + (3 * $r['Z']));
$U = $o['u'] / (13 * $o['L']) + $_U;
$V = $o['v'] / (13 * $o['L']) + $_V;
$X = -(9 * $Y * $U) / (($U - 4) * $V - $U * $V);
$Z = (9 * $Y - (15 * $V * $Y) - ($V * $X)) / (3 * $V);
return ['X' => $X, 'Y' => $Y, 'Z' => $Z];
}
public function Luv_LCHuv($o)
{
$H = atan2($o['v'], $o['u']) * (180 / PI);
if ($H < 0) {
$H += 360;
} else {
if ($H > 360) {
$H -= 360;
}
}
return ['L' => $o['L'], 'C' => sqrt($o['u'] * $o['u'] + $o['v'] * $o['v']), 'H' => $H];
}
// CIE-L*CH (1986) = L: Luminescece / C: Chromacity / H: Hue
public function LCHab_Lab($o)
{
$rad = $o['H'] * (PI / 180);
return ['L' => $o['L'], 'a' => cos($rad) * $o['C'], 'b' => sin($rad) * $o['C']];
}
public function LCHuv_Luv($o)
{
$rad = $o['H'] * (PI / 180);
return ['L' => $o['L'], 'u' => cos($rad) * $o['C'], 'v' => sin($rad) * $o['C']];
}
public function adapt($o, $type)
{
$r = [ // Adaption methods
'XYZ scaling' => [
'A' => [[1, 0, 0], [0, 1, 0], [0, 0, 1]],
'Z' => [[1, 0, 0], [0, 1, 0], [0, 0, 1]],
],
'Von Kries' => [
'A' => [[0.400240, -0.226300, 0], [0.707600, 1.165320, 0], [-0.080810, 0.045700, 0.918220]],
'Z' => [[1.859936, 0.361191, 0], [-1.129382, 0.638812, 0], [0.219897, -0.000006, 1.089064]],
],
'Bradford' => [
'A' => [
[0.895100, 0.26640000, -0.16139900],
[-0.75019900, 1.71350, 0.0367000],
[0.03889900, -0.0685000, 1.02960000],
],
'Z' => [
[0.986993, -0.14705399, 0.15996299],
[0.43230499, 0.51836, 0.0492912],
[-0.00852866, 0.0400428, 0.96848699],
],
],
];
$WS = $this->_xyY;
$WD = $this->White; // White Point Source + Destination
// echo 'WS = ';
// print_r($WS);
// echo 'WD = ';
// print_r($WD);
$A = $r[$type]['A'];
$Z = $r[$type]['Z']; // Load Matrices
$CRD = $this->multiply($A, [[$WD['X']], [$WD['Y']], [$WD['Z']]]); // Convert to cone responce domain
$CRS = $this->multiply($A, [[$WS['X']], [$WS['Y']], [$WS['Z']]]);
//print_r($CRD);
//print_r($CRS);
$M = [
[$CRD[0][0] / $CRS[0][0], 0, 0],
[0, $CRD[1][0] / $CRS[1][0], 0],
[0, 0, $CRD[2][0] / $CRS[2][0]],
]; // Scale Vectors
$z = $this->multiply($Z,
$this->multiply($M, $this->multiply($A, [[$o['X']], [$o['Y']], [$o['Z']]]))); // Back to XYZ
return ['X' => $z[0][0], 'Y' => $z[1][0], 'Z' => $z[2][0]];
}
public function f($o)
{
$x = $this->xyY_XYZ($o);
// echo 'o = ';
// print_r($o);
// echo 'x = ';
// print_r($x);
return $this->adapt($x, 'Bradford');
}
public function illuminant($observer, $type)
{
$o = $this->_illuminant[$type];
$o = ($observer == 2) ? ['x' => $o[0], 'y' => $o[1], 'Y' => 1] : ['x' => $o[2], 'y' => $o[3], 'Y' => 1];
//print_r($o);
return $this->xyY_XYZ($o);
}
private $_Space;
private $_Gamma;
private $_White;
private $_Matrix;
public function profile($i)
{
$m = $this->_profile[$i];
//print_r($m);
$this->_Space = $i;
$this->_Gamma = $m[0];
$this->_White = $m[1];
$this->_Matrix = $m;
// Input Illuminant
$this->_xyY = $this->illuminant('2', $m[1]);
//print_r($this->_xyY);
$R = $this->f(['x' => $m[2], 'y' => $m[3], 'Y' => $m[4]]);
$G = $this->f(['x' => $m[5], 'y' => $m[6], 'Y' => $m[7]]);
$B = $this->f(['x' => $m[8], 'y' => $m[9], 'Y' => $m[10]]);
// print_r($R);
// print_r($G);
// print_r($B);
$this->_RGB_XYZ = [$R['X'], $R['Y'], $R['Z'], $G['X'], $G['Y'], $G['Z'], $B['X'], $B['Y'], $B['Z']];
// print_r($this->_RGB_XYZ);
$this->_XYZ_RGB = $this->inverse($this->_RGB_XYZ);
}
private $_RGB_XYZ;
private $_profile = [ // [ Gamma, Illuminant, Matrix ]
'Adobe (1998)' => [2.2, 'D65', 0.64, 0.33, 0.297361, 0.21, 0.71, 0.627355, 0.15, 0.06, 0.075285],
// Adobe
'Apple RGB' => [1.8, 'D65', 0.625, 0.34, 0.244634, 0.28, 0.595, 0.672034, 0.155, 0.07, 0.083332],
// Apple, a.k.a. SGI
'BestRGB' => [2.2, 'D50', 0.7347, 0.2653, 0.228457, 0.215, 0.775, 0.737352, 0.13, 0.035, 0.034191],
// Don Hutcheson
'Beta RGB' => [2.2, 'D50', 0.6888, 0.3112, 0.303273, 0.1986, 0.7551, 0.663786, 0.1265, 0.0352, 0.032941],
// Bruce Lindbloom
'Bruce RGB' => [2.2, 'D65', 0.64, 0.33, 0.240995, 0.28, 0.65, 0.683554, 0.15, 0.06, 0.075452],
// Bruce Fraser
'CIE RGB' => [2.2, 'E', 0.735, 0.265, 0.176204, 0.274, 0.717, 0.812985, 0.167, 0.009, 0.010811],
// CIE
'ColorMatch' => [1.8, 'D50', 0.63, 0.34, 0.274884, 0.295, 0.605, 0.658132, 0.15, 0.075, 0.066985],
// Radius
'DonRGB4' => [2.2, 'D50', 0.696, 0.3, 0.27835, 0.215, 0.765, 0.68797, 0.13, 0.035, 0.03368],
'eciRGB' => [1.8, 'D50', 0.67, 0.33, 0.32025, 0.21, 0.71, 0.602071, 0.14, 0.08, 0.077679],
// European Colour Initiative
'Ekta Space PS5' => [2.2, 'D50', 0.695, 0.305, 0.260629, 0.26, 0.7, 0.734946, 0.11, 0.005, 0.004425],
// Joseph Holmes
'Generic RGB' => [1.8, 'D65', 0.6295, 0.3407, 0.232546, 0.2949, 0.6055, 0.672501, 0.1551, 0.0762, 0.094952],
'HDTV (HD-CIF)' => [1.95, 'D65', 0.64, 0.33, 0.212673, 0.3, 0.6, 0.715152, 0.15, 0.06, 0.072175],
// a.k.a. ITU-R BT.701
'NTSC' => [2.2, 'C', 0.67, 0.33, 0.298839, 0.21, 0.71, 0.586811, 0.14, 0.08, 0.11435],
// National Television System Committee (NTSC), a.k.a. Y'I'Q'
'PAL / SECAM' => [2.2, 'D65', 0.64, 0.33, 0.222021, 0.29, 0.6, 0.706645, 0.15, 0.06, 0.071334],
// European Broadcasting Union (EBU), a.k.a. Y'U'V'
'ProPhoto' => [1.8, 'D50', 0.7347, 0.2653, 0.28804, 0.1596, 0.8404, 0.711874, 0.0366, 0.0001, 0.000086],
// Kodak, a.k.a. ROMM RGB
'SGI' => [1.47, 'D65', 0.625, 0.34, 0.244651, 0.28, 0.595, 0.672030, 0.155, 0.07, 0.083319],
'SMPTE-240M' => [1.92, 'D65', 0.63, 0.34, 0.212413, 0.31, 0.595, 0.701044, 0.155, 0.07, 0.086543],
'SMPTE-C' => [2.2, 'D65', 0.63, 0.34, 0.212395, 0.31, 0.595, 0.701049, 0.155, 0.07, 0.086556],
// Society of Motion Picture and Television Engineers (SMPTE)
'sRGB' => [2.2, 'D65', 0.64, 0.33, 0.212656, 0.3, 0.6, 0.715158, 0.15, 0.06, 0.072186],
// Microsoft & Hewlett - Packard
'Wide Gamut' => [2.2, 'D50', 0.7347, 0.2653, 0.258187, 0.1152, 0.8264, 0.724938, 0.1566, 0.0177, 0.016875],
// Adobe
];
private $_illuminant = [ // [ x2°, y2°, x10°, y10°, CCT (Kelvin) ]
'A' => [0.44757, 0.40745, 0.45117, 0.40594, 2856], // Incandescent tungsten
'B' => [0.34842, 0.35161, 0.3498, 0.3527, 4874], // Obsolete, direct sunlight at noon
'C' => [0.31006, 0.31616, 0.31039, 0.31905, 6774], // Obsolete, north sky daylight
'D50' => [0.34567, 0.35850, 0.34773, 0.35952, 5003], // ICC Profile PCS. Horizon light.
'D55' => [0.33242, 0.34743, 0.33411, 0.34877, 5503], // Compromise between incandescent and daylight
'D65' => [0.31271, 0.32902, 0.31382, 0.33100, 6504], // Daylight, sRGB color space
'D75' => [0.29902, 0.31485, 0.29968, 0.31740, 7504], // North sky day light
'E' => [0.33333, 0.33333, 0.33333, 0.33333, 5454], // Equal energy
'F1' => [0.31310, 0.33727, 0.31811, 0.33559, 6430], // Daylight Fluorescent
'F2' => [0.37208, 0.37529, 0.37925, 0.36733, 4230], // Cool White Fluorescent
'F3' => [0.40910, 0.39430, 0.41761, 0.38324, 3450], // White Fluorescent
'F4' => [0.44018, 0.40329, 0.44920, 0.39074, 2940], // Warm White Fluorescent
'F5' => [0.31379, 0.34531, 0.31975, 0.34246, 6350], // Daylight Fluorescent
'F6' => [0.37790, 0.38835, 0.38660, 0.37847, 4150], // Lite White Fluorescent
'F7' => [0.31292, 0.32933, 0.31569, 0.32960, 6500], // D65 simulator, day light simulator
'F8' => [0.34588, 0.35875, 0.34902, 0.35939, 5000], // D50 simulator, Sylvania F40 Design
'F9' => [0.37417, 0.37281, 0.37829, 0.37045, 4150], // Cool White Deluxe Fluorescent
'F10' => [0.34609, 0.35986, 0.35090, 0.35444, 5000], // Philips TL85, Ultralume 50
'F11' => [0.38052, 0.37713, 0.38541, 0.37123, 4000], // Philips TL84, Ultralume 40
'F12' => [0.43695, 0.40441, 0.44256, 0.39717, 3000],
]; // Philips TL83, Ultralume 30
public function multiply($m1, $m2)
{
$ni = count($m1);
$ki = $ni;
$i;
$nj;
$kj = count($m2[0]);
$j;
$cols = count($m1[0]);
$M = [];
$sum;
$nc;
$c;
do {
$i = $ki - $ni;
$M[$i] = [];
$nj = $kj;
do {
$j = $kj - $nj;
$sum = 0;
$nc = $cols;
do {
$c = $cols - $nc;
$sum += $m1[$i][$c] * $m2[$c][$j];
} while (($nc -= 1));
$M[$i][$j] = $sum;
} while (($nj -= 1));
} while (($ni -= 1));
return $M;
}
public function determinant($m)
{ // 3x3
// print_r($m);
return $m[0] * ($m[4] * $m[8] - $m[5] * $m[7]) -
$m[1] * ($m[3] * $m[8] - $m[5] * $m[6]) +
$m[2] * ($m[3] * $m[7] - $m[4] * $m[6]);
}
public function inverse($m)
{ // 3x3
$d = 1.0 / $this->determinant($m);
return [
$d * ($m[4] * $m[8] - $m[5] * $m[7]),
$d * (-1 * ($m[1] * $m[8] - $m[2] * $m[7])),
$d * ($m[1] * $m[5] - $m[2] * $m[4]),
$d * (-1 * ($m[3] * $m[8] - $m[5] * $m[6])),
$d * ($m[0] * $m[8] - $m[2] * $m[6]),
$d * (-1 * ($m[0] * $m[5] - $m[2] * $m[3])),
$d * ($m[3] * $m[7] - $m[4] * $m[6]),
$d * (-1 * ($m[0] * $m[7] - $m[1] * $m[6])),
$d * ($m[0] * $m[4] - $m[1] * $m[3]),
];
}
}