Last active
December 15, 2015 14:08
-
-
Save oranj/5271841 to your computer and use it in GitHub Desktop.
This file contains 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
#!/usr/bin/php | |
<?php | |
/** | |
* Calibration: depending on your fonts and terminal colors, you may want to change these | |
*/ | |
global $PIXELS, $COLORS, $HSV_COLORS; | |
$YSCALE = 12; | |
$XSCALE = 5; | |
$COLORS = array( | |
'd95136' => '1', // red | |
'e953e9' => '5', // purple | |
'6f4bf9' => '4', // blue | |
'42c9d6' => '6', // cyan | |
'38cb36' => '2', // green | |
'bcbb36' => '3' // yellow | |
); | |
$PIXELS = array( | |
'0.9' => '▓', | |
'0.8' => '▒', | |
'0.7' => '░', | |
'0.6' => '#', | |
'0.5' => 'X', | |
'0.4' => 'T', | |
'0.3' => '>', | |
'0.2' => '-', | |
'0.1' => '.', | |
'0' => ' ' | |
); | |
if ($argc != 2) { | |
echo "Missing URL"; | |
die(1); | |
} | |
foreach ($COLORS as $rgb => $code) { | |
$r = hexdec($rgb[0].$rgb[1]); | |
$g = hexdec($rgb[2].$rgb[3]); | |
$b = hexdec($rgb[4].$rgb[5]); | |
$hsv = rgb_to_hsv($r, $g, $b); | |
$degrees = 60 * $hsv[0]; | |
$HSV_COLORS[$degrees] = $code; | |
} | |
ksort($HSV_COLORS); | |
$HSV_COLORS[360 + key($HSV_COLORS)] = current($HSV_COLORS); | |
#drop($HSV_COLORS); | |
$url = $argv[1]; | |
if ($url == 'calibrate') { | |
echo "These are your available colors. Please set the \$COLOR variable accordingly\n"; | |
foreach ($COLORS as $color) { | |
echo "\033[0;3".$color."m▓▓▓▓▓▓▓▓▓▓ (3".$color.")\033[0m\n"; | |
} | |
exit; | |
} | |
// Stolen from http://stackoverflow.com/a/13887939 | |
function rgb_to_hsv($r, $g, $b) { | |
$R = (int)$r; | |
$G = (int)$g; | |
$B = (int)$b; | |
$key = sprintf("%x%x%x", $R, $G, $B); | |
static $cache = array(); | |
if (! (isset($cache[$key]) && $out = $cache[$key])) { | |
// Convert the RGB byte-values to percentages | |
$R = ($R / 255); | |
$G = ($G / 255); | |
$B = ($B / 255); | |
// Calculate a few basic values, the maximum value of R,G,B, the | |
// minimum value, and the difference of the two (chroma). | |
$maxRGB = max($R, $G, $B); | |
$minRGB = min($R, $G, $B); | |
$chroma = $maxRGB - $minRGB; | |
// Value (also called Brightness) is the easiest component to calculate, | |
// and is simply the highest value among the R,G,B components. | |
// We multiply by 100 to turn the decimal into a readable percent value. | |
$computedV = $maxRGB; | |
// Special case if hueless (equal parts RGB make black, white, or grays) | |
// Note that Hue is technically undefined when chroma is zero, as | |
// attempting to calculate it would cause division by zero (see | |
// below), so most applications simply substitute a Hue of zero. | |
// Saturation will always be zero in this case, see below for details. | |
if ($chroma == 0) | |
return array(0, 0, $computedV); | |
// Saturation is also simple to compute, and is simply the chroma | |
// over the Value (or Brightness) | |
// Again, multiplied by 100 to get a percentage. | |
$computedS = ($chroma / $maxRGB); | |
// Calculate Hue component | |
// Hue is calculated on the "chromacity plane", which is represented | |
// as a 2D hexagon, divided into six 60 degree sectors. We calculate | |
// the bisecting angle as a value 0 <= x < 6, that represents which | |
// portion of which sector the line falls on. | |
if ($R == $minRGB) | |
$h = 3 - (($G - $B) / $chroma); | |
elseif ($B == $minRGB) | |
$h = 1 - (($R - $G) / $chroma); | |
else | |
$h = 5 - (($B - $R) / $chroma); | |
// After we have the sector position, we multiply it by the size of | |
// each sector's arc (60 degrees) to obtain the angle in degrees. | |
$computedH = $h; | |
$out = array($computedH, $computedS, $computedV); | |
} | |
return $out; | |
} | |
function see() { | |
print_r(func_get_args()); | |
} | |
function drop() { | |
print_r(func_get_args()); | |
exit; | |
} | |
$image = file_get_contents($url); | |
if (! $image) { | |
echo "Could not fetch image $url\n"; | |
die(1); | |
} | |
$img = imagecreatefromstring($image); | |
#imagefilter($img, IMG_FILTER_EDGEDETECT); | |
$image_width = imagesx($img); | |
$image_height = imagesy($img); | |
$ascii_w_h_scale = $XSCALE / $YSCALE; | |
$img_scale = $image_width/$image_height; | |
$target_width = get_tty_width(); | |
$target_height = ($target_width * $ascii_w_h_scale) / ($img_scale); | |
$ascii_x_scale = $image_width / $target_width; | |
$ascii_y_scale = $image_height / $target_height; | |
function brightness_from_index($rgb, &$_r, &$_g, &$_b) { | |
$r = (($rgb >> 16) & 0xFF); | |
$g = (($rgb >> 8) & 0xFF); | |
$b = (($rgb) & 0xFF); | |
$_r += $r; | |
$_g += $g; | |
$_b += $b; | |
$r /= 256; | |
$g /= 256; | |
$b /= 256; | |
// based on perceived brightness | |
$out = sqrt((0.241*$r*$r) + (0.691*$g*$g) + (0.068*$b*$b)); | |
return $out; | |
} | |
function get_tty_width() { | |
$output = exec('tput cols'); | |
return $output; | |
} | |
function get_ascii_pixel($img, $x0, $x1, $y0, $y1) { | |
global $HSV_COLORS, $PIXELS; | |
$total = 0; | |
$count = 0; | |
$r = $g = $b = 0; | |
for ($x = round($x0); $x < round($x1); $x++) { | |
for ($y = round($y0); $y < round($y1); $y++) { | |
$total += brightness_from_index(imagecolorat($img, $x, $y), $r, $g, $b); | |
$count++; | |
} | |
} | |
$r /= $count; | |
$g /= $count; | |
$b /= $count; | |
$hsv = rgb_to_hsv($r, $g, $b); | |
$hue = ($hsv[0] * 60) % 360; | |
$color_distances = array(); | |
foreach ($HSV_COLORS as $_hue => $value) { | |
$color_distances[$value] []= abs($hue - $_hue); | |
$color_distances[$value] []= 360 - abs($hue - $_hue); | |
} | |
$color_distances = array_map('min', $color_distances); | |
asort($color_distances); | |
$nearest_hue = key($color_distances); | |
next($color_distances); | |
$next_nearest_hue = key($color_distances); | |
$next_nearest_distance = current($color_distances); | |
$lightness = $hsv[2]; | |
if ($next_nearest_distance < 60 && $lightness < 0.8 && $lightness > 0.4) { | |
$back_hue = $nearest_hue; | |
$nearest_hue = $next_nearest_hue; | |
$saturation_glyph = (string)min(round($hsv[2] * $hsv[1] * 5) / 10 + 0.5, 0.9); | |
} else { | |
$back_hue = ($lightness > 0.6) ? "7" : "0"; | |
$saturation_glyph = (string)min(round($hsv[2] * $hsv[1] * 10) / 10, 0.9); | |
} | |
$glyph = $PIXELS[$saturation_glyph]; | |
return "\033[0;3" . $nearest_hue . ";4".$back_hue."m".$glyph; | |
} | |
for ($y = 0; $y < $target_height - 1; $y++) { | |
for ($x = 0; $x < $target_width - 1; $x++) { | |
echo get_ascii_pixel($img, $x * $ascii_x_scale, ($x+1) * $ascii_x_scale, $y * $ascii_y_scale, ($y + 1) * $ascii_y_scale); | |
} | |
echo "\n"; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment