From 2959f11f339ece467db1a22da41b2cf7f119806f Mon Sep 17 00:00:00 2001 From: Mikael Roos <mikael.t.h.roos@gmail.com> Date: Tue, 1 Sep 2015 16:45:10 +0200 Subject: [PATCH] Adding support for AsciiArt of an image. --- CAsciiArt.php | 213 +++++++++++++++++++++++++++++++++++++++++ CImage.php | 43 +++++++++ webroot/img.php | 48 +++++++++- webroot/img_config.php | 21 ++++ 4 files changed, 323 insertions(+), 2 deletions(-) create mode 100644 CAsciiArt.php diff --git a/CAsciiArt.php b/CAsciiArt.php new file mode 100644 index 0000000..ac3535b --- /dev/null +++ b/CAsciiArt.php @@ -0,0 +1,213 @@ +<?php +/** + * Create an ASCII version of an image. + * Inspired by https://gist.github.com/donatj/1353237 and various sources. + * + */ +class CAsciiArt +{ + /** + * Character set to use. + */ + private $characterSet = array( + 'one' => "#0XT|:,.' ", + 'two' => "@%#*+=-:. ", + 'three' => "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. " + ); + + + + /** + * Current character set. + */ + private $characters = null; + + + + /** + * Length of current character set. + */ + private $charCount = null; + + + + /** + * Scale of the area to swap to a character. + */ + private $scale = null; + + + + /** + * Strategy to calculate luminance. + */ + private $luminanceStrategy = null; + + + + /** + * Constructor which sets default options. + */ + public function __construct() + { + $this->setOptions(); + } + + + + /** + * Add a custom character set. + * + * @param string $key for the character set. + * @param string $value for the character set. + * + * @return $this + */ + public function addCharacterSet($key, $value) + { + $this->characterSet[$key] = $value; + return $this; + } + + + + /** + * Length of current character set. + * + * @param array $options to use as default settings. + * + * @return $this + */ + public function setOptions($options = array()) + { + $default = array( + "characterSet" => 'two', + "scale" => 14, + "luminanceStrategy" => 3, + "customCharacterSet" => null, + ); + $default = array_merge($default, $options); + + if (!is_null($default['customCharacterSet'])) { + $this->addCharacterSet('custom', $default['customCharacterSet']); + $default['characterSet'] = 'custom'; + } + + $this->scale = $default['scale']; + $this->characters = $this->characterSet[$default['characterSet']]; + $this->charCount = strlen($this->characters); + $this->luminanceStrategy = $default['luminanceStrategy']; + + return $this; + } + + + + /** + * Create an Ascii image from an image file. + * + * @param string $filename of the image to use. + * + * @return string $ascii with the ASCII image. + */ + public function createFromFile($filename) + { + $img = imagecreatefromstring(file_get_contents($filename)); + list($width, $height) = getimagesize($filename); + + $ascii = null; + $incY = $this->scale; + $incX = $this->scale / 2; + + for ($y = 0; $y < $height - 1; $y += $incY) { + for ($x = 0; $x < $width - 1; $x += $incX) { + $toX = min($x + $this->scale / 2, $width - 1); + $toY = min($y + $this->scale, $height - 1); + $luminance = $this->luminanceAreaAverage($img, $x, $y, $toX, $toY); + $ascii .= $this->luminance2character($luminance); + } + $ascii .= PHP_EOL; + } + + return $ascii; + } + + + + /** + * Get the luminance from a region of an image using average color value. + * + * @param string $img the image. + * @param integer $x1 the area to get pixels from. + * @param integer $y1 the area to get pixels from. + * @param integer $x2 the area to get pixels from. + * @param integer $y2 the area to get pixels from. + * + * @return integer $luminance with a value between 0 and 100. + */ + public function luminanceAreaAverage($img, $x1, $y1, $x2, $y2) + { + $numPixels = ($x2 - $x1 + 1) * ($y2 - $y1 + 1); + $luminance = 0; + + for ($x = $x1; $x <= $x2; $x++) { + for ($y = $y1; $y <= $y2; $y++) { + $rgb = imagecolorat($img, $x, $y); + $red = (($rgb >> 16) & 0xFF); + $green = (($rgb >> 8) & 0xFF); + $blue = ($rgb & 0xFF); + $luminance += $this->getLuminance($red, $green, $blue); + } + } + + return $luminance / $numPixels; + } + + + + /** + * Calculate luminance value with different strategies. + * + * @param integer $red The color red. + * @param integer $green The color green. + * @param integer $blue The color blue. + * + * @return float $luminance with a value between 0 and 1. + */ + public function getLuminance($red, $green, $blue) + { + switch($this->luminanceStrategy) { + case 1: + $luminance = ($red * 0.2126 + $green * 0.7152 + $blue * 0.0722) / 255; + break; + case 2: + $luminance = ($red * 0.299 + $green * 0.587 + $blue * 0.114) / 255; + break; + case 3: + $luminance = sqrt(0.299 * pow($red, 2) + 0.587 * pow($green, 2) + 0.114 * pow($blue, 2)) / 255; + break; + case 0: + default: + $luminance = ($red + $green + $blue) / (255 * 3); + } + + return $luminance; + } + + + + /** + * Translate the luminance value to a character. + * + * @param string $position a value between 0-100 representing the + * luminance. + * + * @return string with the ascii character. + */ + public function luminance2character($luminance) + { + $position = (int) round($luminance * ($this->charCount - 1)); + $char = $this->characters[$position]; + return $char; + } +} diff --git a/CImage.php b/CImage.php index 24be590..80bd97a 100644 --- a/CImage.php +++ b/CImage.php @@ -334,6 +334,13 @@ class CImage + /* + * output to ascii can take som options as an array. + */ + private $asciiOptions = array(); + + + /** * Properties, the class is mutable and the method setOptions() * decides (partly) what properties are created. @@ -2250,6 +2257,10 @@ class CImage header('Content-type: application/json'); echo $this->json($file); exit; + } elseif ($format == 'ascii') { + header('Content-type: text/plain'); + echo $this->ascii($file); + exit; } $this->log("Outputting image: $file"); @@ -2341,6 +2352,38 @@ class CImage + /** + * Set options for creating ascii version of image. + * + * @param array $options empty to use default or set options to change. + * + * @return void. + */ + public function setAsciiOptions($options = array()) + { + $this->asciiOptions = $options; + } + + + + /** + * Create an ASCII version from the image details. + * + * @param string $file the file to output. + * + * @return string ASCII representation of the image. + */ + public function ascii($file = null) + { + $file = $file ? $file : $this->cacheFileName; + + $asciiArt = new CAsciiArt(); + $asciiArt->setOptions($this->asciiOptions); + return $asciiArt->createFromFile($file); + } + + + /** * Log an event if verbose mode. * diff --git a/webroot/img.php b/webroot/img.php index 350c0d8..7efe537 100644 --- a/webroot/img.php +++ b/webroot/img.php @@ -754,11 +754,55 @@ verbose("filters = " . print_r($filters, 1)); /** - * json - output the image as a JSON object with details on the image. +* json - output the image as a JSON object with details on the image. +* ascii - output the image as ASCII art. */ $outputFormat = getDefined('json', 'json', null); +$outputFormat = getDefined('ascii', 'ascii', $outputFormat); + +verbose("outputformat = $outputFormat"); + +if ($outputFormat == 'ascii') { + $defaultOptions = getConfig( + 'ascii-options', + array( + "characterSet" => 'two', + "scale" => 14, + "luminanceStrategy" => 3, + "customCharacterSet" => null, + ) + ); + $options = get('ascii'); + $options = explode(',', $options); + + if (isset($options[0]) && !empty($options[0])) { + $defaultOptions['characterSet'] = $options[0]; + } + + if (isset($options[1]) && !empty($options[1])) { + $defaultOptions['scale'] = $options[1]; + } + + if (isset($options[2]) && !empty($options[2])) { + $defaultOptions['luminanceStrategy'] = $options[2]; + } + + if (count($options) > 3) { + // Last option is custom character string + unset($options[0]); + unset($options[1]); + unset($options[2]); + $characterString = implode($options); + $defaultOptions['customCharacterSet'] = $characterString; + } + + //var_dump($options); + //var_dump($defaultOptions); + //exit; + + $img->setAsciiOptions($defaultOptions); +} -verbose("json = $outputFormat"); diff --git a/webroot/img_config.php b/webroot/img_config.php index d071cac..64223a2 100644 --- a/webroot/img_config.php +++ b/webroot/img_config.php @@ -299,4 +299,25 @@ return array( 'golden' => 1.618, ); },*/ + + + + /** + * default options for ascii image. + * + * Default values as specified below in the array. + * ascii-options: + * characterSet: Choose any character set available in CAsciiArt. + * scale: How many pixels should each character + * translate to. + * luminanceStrategy: Choose any strategy available in CAsciiArt. + * customCharacterSet: Define your own character set. + */ + /*'ascii-options' => array( + "characterSet" => 'two', + "scale" => 14, + "luminanceStrategy" => 3, + "customCharacterSet" => null, + ); + },*/ );