Created
October 3, 2018 12:25
-
-
Save alex-phillips/1836029fcd0f6cb7c483f62c88fc9136 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
$converter = new img2ansi(); | |
$converter->run(); | |
class img2ansi | |
{ | |
private $_image; | |
private $_colors_array = array( | |
"black" => array(0, 0, 0), | |
"red" => array(205, 0, 0), | |
"green" => array(0, 205, 0), | |
"yellow" => array(205, 205, 0), | |
"blue" => array(0, 0, 238), | |
"magenta" => array(205, 0, 205), | |
"cyan" => array(0, 205, 205), | |
"gray" => array(229, 229, 229), | |
"dark gray" => array(127, 127, 127), | |
"bright red" => array(255, 0, 0), | |
"bright green" => array(0, 255, 0), | |
"bright yellow" => array(255, 255, 0), | |
"bright blue" => array(92, 92, 255), | |
"bright magenta" => array(255, 0, 255), | |
"bright cyan" => array(0, 255, 255), | |
"white" => array(255, 255, 255), | |
); | |
private $ansi_array = array( | |
"reset" => '0', # reset | |
"black" => '00;30', # black | |
"red" => '00;31', # red | |
"green" => '00;32', # green | |
"yellow" => '00;33', # yellow | |
"blue" => '00;34', # blue | |
"magenta" => '00;35', # magenta | |
"cyan" => '00;36', # cyan | |
"gray" => '00;37', # gray | |
"dark gray" => '01;30', # dark gray | |
"bright red" => '01;31', # bright red | |
"bright green" => '01;32', # bright green | |
"bright yellow" => '01;33', # bright yellow | |
"bright blue" => '01;34', # bright blue | |
"bright magenta" => '01;35', # bright magenta | |
"bright cyan" => '01;36', # bright cyan | |
"white" => '01;37', # white | |
); | |
public function __construct() | |
{ | |
$args = getopt('i:'); | |
if (isset($args['i'])) { | |
$this->_image = $args['i']; | |
} | |
else { | |
print "\nUsage:\n -i input file path to file for conversion\n\n"; | |
exit; | |
} | |
} | |
public function run() | |
{ | |
$this->_image = file_get_contents($this->_image); | |
$img = imagecreatefromstring($this->_image); | |
$width = imagesx($img); | |
$height = imagesy($img); | |
$fill_char = "##"; | |
$output = ''; | |
$last = ''; | |
for($h = 0; $h < $height; $h++){ | |
for($w = 0; $w < $width; $w++){ | |
$rgb = imagecolorat($img, $w, $h); | |
$vals = imagecolorsforindex($img, $rgb); | |
$r = $vals['red']; | |
$g = $vals['green']; | |
$b = $vals['blue']; | |
$a = $vals['alpha']; | |
if ($w == $width/2) { | |
$var = 'test'; | |
} | |
$color = $this->find_closest_color($r, $g, $b); | |
if($w == $width - 1){ | |
$output .= "\n"; | |
} | |
// else if ($a == 0) { | |
// $output .= " " * sizeof($fill_char); | |
// } | |
else { | |
$output .= $this->get_colored_string($fill_char, $color); | |
} | |
} | |
} | |
$output .= $this->get_colored_string('', 'reset'); | |
$output .= "\n\n"; | |
echo $output; | |
} | |
// Returns colored string | |
private function get_colored_string($string, $color = null) { | |
$colored_string = ""; | |
if (isset($this->ansi_array[$color])) { | |
$colored_string .= "\033[" . $this->ansi_array[$color] . "m"; | |
} | |
// Add string and end coloring | |
$colored_string .= $string . "\033[0m"; | |
return $colored_string; | |
} | |
// private function find_closest_color($r, $g, $b) | |
// { | |
// $closest_distance = null; | |
// $match = ''; | |
// foreach ($this->_colors_array as $name => $color) { | |
// $distance = sqrt(($color[0]-$r)^2+($color[1]-$g)^2+($color[2]-$b)^2); | |
// if ($closest_distance === null || $distance < $closest_distance) { | |
// $closest_distance = $distance; | |
// $match = $name; | |
// } | |
// } | |
// return $match; | |
// } | |
// private function find_closest_color($r, $g, $b){ | |
// $differencearray = array(); | |
// $names = array(); | |
// foreach ($this->_colors_array as $name => $value) { | |
// $names[] = $name; | |
// $pow = pow($r-$value[0],2)+pow($g-$value[1],2)+pow($b-$value[2],2); | |
// $difference = sqrt(abs($pow)); | |
// if ($pow < 0) { | |
// $difference = $difference * -1; | |
// } | |
// $differencearray[] = $difference; | |
// } | |
// $smallest = min($differencearray); | |
// $key = array_search($smallest, $differencearray); | |
// return $names[$key]; | |
// } | |
private function find_closest_color($r, $g, $b) | |
{ | |
return $this->getNearestColor(array($r, $g, $b), $this->_colors_array); | |
$diff = new color_difference(); | |
$names = array(); | |
$diffs = array(); | |
foreach ($this->_colors_array as $name => $vals) { | |
$names[] = $name; | |
$diffs[] = $diff->deltaECIE2000(array($r, $g, $b), $vals); | |
} | |
$smallest = min($diffs); | |
$key = array_search($smallest, $diffs); | |
return $names[$key]; | |
} | |
/* | |
* Returns the index of the palette-color which is most similar | |
* to $givenColor. | |
* | |
* $givenColor and the colors in $palette should be either | |
* formatted as (#)rrggbb | |
* (e. g. "ff0000", "4da4f3" or "#b5d7f3") | |
* or arrays with values for red, green and blue | |
* (e. g. $givenColor = array( 0xff, 0x00, 0x00 ) ) | |
* | |
* References: | |
* function rgb2lab | |
* - http://www.f4.fhtw-berlin.de/~barthel/ImageJ/ImageJ.htm | |
* | |
* function rgb2lab & function deltaE | |
* - http://www.brucelindbloom.com | |
*/ | |
private function getNearestColor( | |
$givenColor, | |
$palette = array( 'blue' => '43aafd','red' => 'fe6256','green' => '64b949','yellow' => 'fcf357', | |
'black' => '656565','white' => 'fdfdfd','orange' => 'fea800','purple' => '9773fe') | |
) { | |
if(!function_exists('rgb2lab')) { | |
function rgb2lab($rgb) { | |
$eps = 216/24389; $k = 24389/27; | |
// reference white D50 | |
$xr = 0.964221; $yr = 1.0; $zr = 0.825211; | |
$rgb[0] = $rgb[0]/255; //R 0..1 | |
$rgb[1] = $rgb[1]/255; //G 0..1 | |
$rgb[2] = $rgb[2]/255; //B 0..1 | |
// assuming sRGB (D65) | |
$rgb[0] = ($rgb[0] <= 0.04045)?($rgb[0]/12.92):pow(($rgb[0]+0.055)/1.055,2.4); | |
$rgb[1] = ($rgb[1] <= 0.04045)?($rgb[1]/12.92):pow(($rgb[1]+0.055)/1.055,2.4); | |
$rgb[2] = ($rgb[2] <= 0.04045)?($rgb[2]/12.92):pow(($rgb[2]+0.055)/1.055,2.4); | |
// sRGB D50 | |
$x = 0.4360747*$rgb[0] + 0.3850649*$rgb[1] + 0.1430804 *$rgb[2]; | |
$y = 0.2225045*$rgb[0] + 0.7168786*$rgb[1] + 0.0606169 *$rgb[2]; | |
$z = 0.0139322*$rgb[0] + 0.0971045*$rgb[1] + 0.7141733 *$rgb[2]; | |
$xr = $x/$xr; $yr = $y/$yr; $zr = $z/$zr; | |
$fx = ($xr > $eps)?pow($xr, 1/3):($fx = ($k * $xr + 16) / 116); | |
$fy = ($yr > $eps)?pow($yr, 1/3):($fy = ($k * $yr + 16) / 116); | |
$fz = ($zr > $eps)?pow($zr, 1/3):($fz = ($k * $zr + 16) / 116); | |
$lab = array(); | |
$lab[] = round(( 116 * $fy ) - 16); | |
$lab[] = round(500*($fx-$fy)); | |
$lab[] = round(200*($fy-$fz)); | |
return $lab; | |
} | |
} | |
if(!function_exists('deltaE')) { | |
function deltaE($lab1, $lab2) { | |
// CMC 1:1 | |
$l = 1; $c = 1; | |
$c1 = sqrt($lab1[1]*$lab1[1]+$lab1[2]*$lab1[2]); | |
$c2 = sqrt($lab2[1]*$lab2[1]+$lab2[2]*$lab2[2]); | |
$h1 = (((180000000/M_PI) * atan2($lab1[1],$lab1[2]) + 360000000) % 360000000)/1000000; | |
$t = (164 <= $h1 AND $h1 <= 345)?(0.56 + abs(0.2 * cos($h1+168))):(0.36 + abs(0.4 * cos($h1+35))); | |
$f = sqrt(pow($c1,4)/(pow($c1,4) + 1900)); | |
$sl = ($lab1[0] < 16)?(0.511):((0.040975*$lab1[0])/(1 + 0.01765*$lab1[0])); | |
$sc = (0.0638 * $c1)/(1 + 0.0131 * $c1) + 0.638; | |
$sh = $sc * ($f * $t + 1 -$f); | |
return sqrt( | |
pow(($lab1[0]-$lab2[0])/($l * $sl),2) + | |
pow(($c1-$c2)/($c * $sc),2) + | |
pow(sqrt( | |
($lab1[1]-$lab2[1])*($lab1[1]-$lab2[1]) + | |
($lab1[2]-$lab2[2])*($lab1[2]-$lab2[2]) + | |
($c1-$c2)*($c1-$c2) | |
)/$sh,2) | |
); | |
} | |
} | |
if(!function_exists('str2rgb')) { | |
function str2rgb($str) | |
{ | |
$str = preg_replace('~[^0-9a-f]~','',$str); | |
$rgb = str_split($str,2); | |
for($i=0;$i<3;$i++) | |
$rgb[$i] = intval($rgb[$i],16); | |
return $rgb; | |
} | |
} | |
$givenColorRGB = is_array($givenColor)?$givenColor:str2rgb($givenColor); | |
$min = 0xffff; | |
$return = NULL; | |
foreach($palette as $key => $color) { | |
$color = is_array($color)?$color:str2rgb($color); | |
if($min >= ($deltaE = deltaE(rgb2lab($color),rgb2lab($givenColorRGB)))) | |
{ | |
$min = $deltaE; | |
$return = $key; | |
} | |
} | |
return $return; | |
} | |
} | |
class color_difference { | |
public function deltaECIE2000 ($rgb1, $rgb2) { | |
list($l1, $a1, $b1) = $this->_rgb2lab($rgb1); | |
list($l2, $a2, $b2) = $this->_rgb2lab($rgb2); | |
$avg_lp = ($l1 + $l2) / 2; | |
$c1 = sqrt(pow($a1, 2) + pow($b1, 2)); | |
$c2 = sqrt(pow($a2, 2) + pow($b2, 2)); | |
$avg_c = ($c1 + $c2) / 2; | |
$g = (1 - sqrt(pow($avg_c , 7) / (pow($avg_c, 7) + pow(25, 7)))) / 2; | |
$a1p = $a1 * (1 + $g); | |
$a2p = $a2 * (1 + $g); | |
$c1p = sqrt(pow($a1p, 2) + pow($b1, 2)); | |
$c2p = sqrt(pow($a2p, 2) + pow($b2, 2)); | |
$avg_cp = ($c1p + $c2p) / 2; | |
$h1p = rad2deg(atan2($b1, $a1p)); | |
if ($h1p < 0) { | |
$h1p += 360; | |
} | |
$h2p = rad2deg(atan2($b2, $a2p)); | |
if ($h2p < 0) { | |
$h2p += 360; | |
} | |
$avg_hp = abs($h1p - $h2p) > 180 ? ($h1p + $h2p + 360) / 2 : ($h1p + $h2p) / 2; | |
$t = 1 - 0.17 * cos(deg2rad($avg_hp - 30)) + 0.24 * cos(deg2rad(2 * $avg_hp)) + 0.32 * cos(deg2rad(3 * $avg_hp + 6)) - 0.2 * cos(deg2rad(4 * $avg_hp - 63)); | |
$delta_hp = $h2p - $h1p; | |
if (abs($delta_hp) > 180) { | |
if ($h2p <= $h1p) { | |
$delta_hp += 360; | |
} | |
else { | |
$delta_hp -= 360; | |
} | |
} | |
$delta_lp = $l2 - $l1; | |
$delta_cp = $c2p - $c1p; | |
$delta_hp = 2 * sqrt($c1p * $c2p) * sin(deg2rad($delta_hp) / 2); | |
$s_l = 1 + ((0.015 * pow($avg_lp - 50, 2)) / sqrt(20 + pow($avg_lp - 50, 2))); | |
$s_c = 1 + 0.045 * $avg_cp; | |
$s_h = 1 + 0.015 * $avg_cp * $t; | |
$delta_ro = 30 * exp(-(pow(($avg_hp - 275) / 25, 2))); | |
$r_c = 2 * sqrt(pow($avg_cp, 7) / (pow($avg_cp, 7) + pow(25, 7))); | |
$r_t = -$r_c * sin(2 * deg2rad($delta_ro)); | |
$kl = $kc = $kh = 1; | |
$delta_e = sqrt(pow($delta_lp / ($s_l * $kl), 2) + pow($delta_cp / ($s_c * $kc), 2) + pow($delta_hp / ($s_h * $kh), 2) + $r_t * ($delta_cp / ($s_c * $kc)) * ($delta_hp / ($s_h * $kh))); | |
return $delta_e; | |
} | |
private function _rgb2lab ($rgb) { | |
return $this->_xyz2lab($this->_rgb2xyz($rgb)); | |
} | |
private function _rgb2xyz ($rgb) { | |
list($r, $g, $b) = $rgb; | |
$r = $r <= 0.04045 ? $r / 12.92 : pow(($r + 0.055) / 1.055, 2.4); | |
$g = $g <= 0.04045 ? $g / 12.92 : pow(($g + 0.055) / 1.055, 2.4); | |
$b = $b <= 0.04045 ? $b / 12.92 : pow(($b + 0.055) / 1.055, 2.4); | |
$r *= 100; | |
$g *= 100; | |
$b *= 100; | |
$x = $r * 0.412453 + $g * 0.357580 + $b * 0.180423; | |
$y = $r * 0.212671 + $g * 0.715160 + $b * 0.072169; | |
$z = $r * 0.019334 + $g * 0.119193 + $b * 0.950227; | |
return array($x, $y, $z); | |
} | |
private function _xyz2lab ($xyz) { | |
list ($x, $y, $z) = $xyz; | |
$x /= 95.047; | |
$y /= 100; | |
$z /= 108.883; | |
$x = $x > 0.008856 ? pow($x, 1 / 3) : $x * 7.787 + 16 / 116; | |
$y = $y > 0.008856 ? pow($y, 1 / 3) : $y * 7.787 + 16 / 116; | |
$z = $z > 0.008856 ? pow($z, 1 / 3) : $z * 7.787 + 16 / 116; | |
$l = $y * 116 - 16; | |
$a = ($x - $y) * 500; | |
$b = ($y - $z) * 200; | |
return array($l, $a, $b); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment