mirror of
https://github.com/mosbth/cimage.git
synced 2025-08-29 02:19:47 +02:00
Compare commits
34 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
1bd6fc8a2c | ||
|
39b6078d84 | ||
|
e7e73fc38c | ||
|
fa77908616 | ||
|
0f05cd06e5 | ||
|
3d773b502d | ||
|
575c712bd0 | ||
|
cdd159e142 | ||
|
f21cd923f3 | ||
|
18fb271961 | ||
|
1fdc701f3d | ||
|
dc6e9a8708 | ||
|
d9947251ab | ||
|
0fb00df972 | ||
|
f00b2e0cd3 | ||
|
fd2ddadc44 | ||
|
ea4794f4a2 | ||
|
7af0b6ef8a | ||
|
850fb76c8b | ||
|
49f5f66ad3 | ||
|
a787593533 | ||
|
8d6a8a452e | ||
|
1907feffc8 | ||
|
afff3589dc | ||
|
76bc09f2ee | ||
|
c4d3f7cdf6 | ||
|
a50aab9d8e | ||
|
de942268c9 | ||
|
d8090e7531 | ||
|
c94027a752 | ||
|
2959f11f33 | ||
|
cf8bb8973d | ||
|
d8db2b9105 | ||
|
b65b420313 |
212
CAsciiArt.php
Normal file
212
CAsciiArt.php
Normal file
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
/**
|
||||
* Create an ASCII version of an image.
|
||||
*
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set options for processing, defaults are available.
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
43
CHttpGet.php
43
CHttpGet.php
@@ -21,6 +21,33 @@ class CHttpGet
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Build an encoded url.
|
||||
*
|
||||
* @param string $baseUrl This is the original url which will be merged.
|
||||
* @param string $merge Thse parts should be merged into the baseUrl,
|
||||
* the format is as parse_url.
|
||||
*
|
||||
* @return string $url as the modified url.
|
||||
*/
|
||||
public function buildUrl($baseUrl, $merge)
|
||||
{
|
||||
$parts = parse_url($baseUrl);
|
||||
$parts = array_merge($parts, $merge);
|
||||
|
||||
$url = $parts['scheme'];
|
||||
$url .= "://";
|
||||
$url .= $parts['host'];
|
||||
$url .= isset($parts['port'])
|
||||
? ":" . $parts['port']
|
||||
: "" ;
|
||||
$url .= $parts['path'];
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the url for the request.
|
||||
*
|
||||
@@ -30,6 +57,18 @@ class CHttpGet
|
||||
*/
|
||||
public function setUrl($url)
|
||||
{
|
||||
$parts = parse_url($url);
|
||||
|
||||
$path = "";
|
||||
if (isset($parts['path'])) {
|
||||
$pathParts = explode('/', $parts['path']);
|
||||
unset($pathParts[0]);
|
||||
foreach ($pathParts as $value) {
|
||||
$path .= "/" . rawurlencode($value);
|
||||
}
|
||||
}
|
||||
$url = $this->buildUrl($url, array("path" => $path));
|
||||
|
||||
$this->request['url'] = $url;
|
||||
return $this;
|
||||
}
|
||||
@@ -93,6 +132,8 @@ class CHttpGet
|
||||
*
|
||||
* @param boolean $debug set to true to dump headers.
|
||||
*
|
||||
* @throws Exception when curl fails to retrieve url.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function doGet($debug = false)
|
||||
@@ -115,7 +156,7 @@ class CHttpGet
|
||||
$response = curl_exec($ch);
|
||||
|
||||
if (!$response) {
|
||||
return false;
|
||||
throw new Exception("Failed retrieving url, details follows: " . curl_error($ch));
|
||||
}
|
||||
|
||||
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||
|
233
CImage.php
233
CImage.php
@@ -113,13 +113,6 @@ class CImage
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The root folder of images (only used in constructor to create $pathToImage?).
|
||||
*/
|
||||
private $imageFolder;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Image filename, may include subdirectory, relative from $imageFolder
|
||||
*/
|
||||
@@ -193,6 +186,7 @@ class CImage
|
||||
* Path to command for filter optimize, for example optipng or null.
|
||||
*/
|
||||
private $pngFilter;
|
||||
private $pngFilterCmd;
|
||||
|
||||
|
||||
|
||||
@@ -200,13 +194,16 @@ class CImage
|
||||
* Path to command for deflate optimize, for example pngout or null.
|
||||
*/
|
||||
private $pngDeflate;
|
||||
private $pngDeflateCmd;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Path to command to optimize jpeg images, for example jpegtran or null.
|
||||
*/
|
||||
private $jpegOptimize;
|
||||
private $jpegOptimize;
|
||||
private $jpegOptimizeCmd;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@@ -282,6 +279,56 @@ class CImage
|
||||
private $fillToFit;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option scale.
|
||||
*/
|
||||
private $scale;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option.
|
||||
*/
|
||||
private $rotateBefore;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option.
|
||||
*/
|
||||
private $rotateAfter;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option.
|
||||
*/
|
||||
private $autoRotate;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option.
|
||||
*/
|
||||
private $sharpen;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option.
|
||||
*/
|
||||
private $emboss;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option.
|
||||
*/
|
||||
private $blur;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Used with option area to set which parts of the image to use.
|
||||
*/
|
||||
@@ -334,6 +381,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.
|
||||
@@ -348,9 +402,7 @@ class CImage
|
||||
public $crop_x;
|
||||
public $crop_y;
|
||||
public $filters;
|
||||
private $type; // Calculated from source image
|
||||
private $attr; // Calculated from source image
|
||||
private $useOriginal; // Use original image if possible
|
||||
|
||||
|
||||
|
||||
@@ -407,9 +459,7 @@ class CImage
|
||||
/**
|
||||
* Use cache or not.
|
||||
*
|
||||
* @todo clean up how $this->noCache is used in other methods.
|
||||
*
|
||||
* @param string $use true or false to use cache.
|
||||
* @param boolean $use true or false to use cache.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
@@ -421,6 +471,27 @@ class CImage
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create and save a dummy image. Use dimensions as stated in
|
||||
* $this->newWidth, or $width or default to 100 (same for height.
|
||||
*
|
||||
* @param integer $width use specified width for image dimension.
|
||||
* @param integer $height use specified width for image dimension.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function createDummyImage($width = null, $height = null)
|
||||
{
|
||||
$this->newWidth = $this->newWidth ?: $width ?: 100;
|
||||
$this->newHeight = $this->newHeight ?: $height ?: 100;
|
||||
|
||||
$this->image = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Allow or disallow remote image download.
|
||||
*
|
||||
@@ -571,16 +642,18 @@ class CImage
|
||||
|
||||
|
||||
/**
|
||||
* Set src file.
|
||||
* Set source file to use as image source.
|
||||
*
|
||||
* @param string $src of image.
|
||||
* @param string $dir as base directory where images are.
|
||||
* @param string $dir as optional base directory where images are.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSource($src, $dir = null)
|
||||
{
|
||||
if (!isset($src)) {
|
||||
$this->imageSrc = null;
|
||||
$this->pathToImage = null;
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -594,9 +667,9 @@ class CImage
|
||||
$src = basename($src);
|
||||
}
|
||||
|
||||
$this->imageSrc = ltrim($src, '/');
|
||||
$this->imageFolder = rtrim($dir, '/');
|
||||
$this->pathToImage = $this->imageFolder . '/' . $this->imageSrc;
|
||||
$this->imageSrc = ltrim($src, '/');
|
||||
$imageFolder = rtrim($dir, '/');
|
||||
$this->pathToImage = $imageFolder . '/' . $this->imageSrc;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -607,23 +680,23 @@ class CImage
|
||||
* Set target file.
|
||||
*
|
||||
* @param string $src of target image.
|
||||
* @param string $dir as base directory where images are stored.
|
||||
* @param string $dir as optional base directory where images are stored.
|
||||
* Uses $this->saveFolder if null.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setTarget($src = null, $dir = null)
|
||||
{
|
||||
if (!(isset($src) && isset($dir))) {
|
||||
if (!isset($src)) {
|
||||
$this->cacheFileName = null;
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->saveFolder = $dir;
|
||||
$this->cacheFileName = $dir . '/' . $src;
|
||||
if (isset($dir)) {
|
||||
$this->saveFolder = rtrim($dir, '/');
|
||||
}
|
||||
|
||||
/* Allow readonly cache
|
||||
is_writable($this->saveFolder)
|
||||
or $this->raiseError('Target directory is not writable.');
|
||||
*/
|
||||
$this->cacheFileName = $this->saveFolder . '/' . $src;
|
||||
|
||||
// Sanitize filename
|
||||
$this->cacheFileName = preg_replace('/^a-zA-Z0-9\.-_/', '', $this->cacheFileName);
|
||||
@@ -634,6 +707,18 @@ class CImage
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get filename of target file.
|
||||
*
|
||||
* @return Boolean|String as filename of target or false if not set.
|
||||
*/
|
||||
public function getTarget()
|
||||
{
|
||||
return $this->cacheFileName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set options to use when processing image.
|
||||
*
|
||||
@@ -681,11 +766,6 @@ class CImage
|
||||
// Output format
|
||||
'outputFormat' => null,
|
||||
'dpr' => 1,
|
||||
|
||||
// Options for saving
|
||||
//'quality' => null,
|
||||
//'compress' => null,
|
||||
//'saveAs' => null,
|
||||
);
|
||||
|
||||
// Convert crop settings from string to array
|
||||
@@ -1179,13 +1259,15 @@ class CImage
|
||||
/**
|
||||
* Generate filename to save file in cache.
|
||||
*
|
||||
* @param string $base as basepath for storing file.
|
||||
* @param string $base as optional basepath for storing file.
|
||||
* @param boolean $useSubdir use or skip the subdir part when creating the
|
||||
* filename.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function generateFilename($base)
|
||||
public function generateFilename($base = null, $useSubdir = true)
|
||||
{
|
||||
$parts = pathinfo($this->pathToImage);
|
||||
$filename = basename($this->pathToImage);
|
||||
$cropToFit = $this->cropToFit ? '_cf' : null;
|
||||
$fillToFit = $this->fillToFit ? '_ff' : null;
|
||||
$crop_x = $this->crop_x ? "_x{$this->crop_x}" : null;
|
||||
@@ -1214,7 +1296,7 @@ class CImage
|
||||
if (is_array($filter)) {
|
||||
$filters .= "_f{$filter['id']}";
|
||||
for ($i=1; $i<=$filter['argc']; $i++) {
|
||||
$filters .= ":".$filter["arg{$i}"];
|
||||
$filters .= "-".$filter["arg{$i}"];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1227,16 +1309,6 @@ class CImage
|
||||
|
||||
$autoRotate = $this->autoRotate ? 'ar' : null;
|
||||
|
||||
$this->extension = isset($this->extension)
|
||||
? $this->extension
|
||||
: (isset($parts['extension'])
|
||||
? $parts['extension']
|
||||
: null);
|
||||
|
||||
$extension = empty($this->extension)
|
||||
? null
|
||||
: "." . $this->extension;
|
||||
|
||||
$optimize = $this->jpegOptimize ? 'o' : null;
|
||||
$optimize .= $this->pngFilter ? 'f' : null;
|
||||
$optimize .= $this->pngDeflate ? 'd' : null;
|
||||
@@ -1251,14 +1323,20 @@ class CImage
|
||||
$upscale = '_nu';
|
||||
}
|
||||
|
||||
$subdir = str_replace('/', '-', dirname($this->imageSrc));
|
||||
$subdir = ($subdir == '.') ? '_.' : $subdir;
|
||||
$file = $subdir . '_' . $parts['filename'] . '_' . $width . '_'
|
||||
$subdir = null;
|
||||
if ($useSubdir === true) {
|
||||
$subdir = str_replace('/', '-', dirname($this->imageSrc));
|
||||
$subdir = ($subdir == '.') ? '_.' : $subdir;
|
||||
$subdir .= '_';
|
||||
}
|
||||
|
||||
$file = $subdir . $filename . '_' . $width . '_'
|
||||
. $height . $offset . $crop . $cropToFit . $fillToFit
|
||||
. $crop_x . $crop_y . $upscale
|
||||
. $quality . $filters . $sharpen . $emboss . $blur . $palette . $optimize
|
||||
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor . $convolve
|
||||
. $extension;
|
||||
. $quality . $filters . $sharpen . $emboss . $blur . $palette
|
||||
. $optimize . $compress
|
||||
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor
|
||||
. $convolve;
|
||||
|
||||
return $this->setTarget($file, $base);
|
||||
}
|
||||
@@ -2026,7 +2104,10 @@ class CImage
|
||||
imagealphablending($img, false);
|
||||
imagesavealpha($img, true);
|
||||
|
||||
$index = imagecolortransparent($this->image);
|
||||
$index = $this->image
|
||||
? imagecolortransparent($this->image)
|
||||
: -1;
|
||||
|
||||
if ($index != -1) {
|
||||
|
||||
imagealphablending($img, true);
|
||||
@@ -2099,17 +2180,23 @@ class CImage
|
||||
/**
|
||||
* Save image.
|
||||
*
|
||||
* @param string $src as target filename.
|
||||
* @param string $base as base directory where to store images.
|
||||
* @param string $src as target filename.
|
||||
* @param string $base as base directory where to store images.
|
||||
* @param boolean $overwrite or not, default to always overwrite file.
|
||||
*
|
||||
* @return $this or false if no folder is set.
|
||||
*/
|
||||
public function save($src = null, $base = null)
|
||||
public function save($src = null, $base = null, $overwrite = true)
|
||||
{
|
||||
if (isset($src)) {
|
||||
$this->setTarget($src, $base);
|
||||
}
|
||||
|
||||
if ($overwrite === false && is_file($this->cacheFileName)) {
|
||||
$this->Log("Not overwriting file since its already exists and \$overwrite if false.");
|
||||
return;
|
||||
}
|
||||
|
||||
is_writable($this->saveFolder)
|
||||
or $this->raiseError('Target directory is not writable.');
|
||||
|
||||
@@ -2250,6 +2337,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 +2432,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.
|
||||
*
|
||||
|
@@ -147,7 +147,7 @@ class CRemoteImage
|
||||
*/
|
||||
public function setHeaderFields()
|
||||
{
|
||||
$this->http->setHeader("User-Agent", "CImage/0.7.0 (PHP/". phpversion() . " cURL)");
|
||||
$this->http->setHeader("User-Agent", "CImage/0.7.2 (PHP/". phpversion() . " cURL)");
|
||||
$this->http->setHeader("Accept", "image/jpeg,image/png,image/gif");
|
||||
|
||||
if ($this->useCache) {
|
||||
@@ -226,6 +226,8 @@ class CRemoteImage
|
||||
*
|
||||
* @param string $url a remote url.
|
||||
*
|
||||
* @throws Exception when status code does not match 200 or 304.
|
||||
*
|
||||
* @return string as path to downloaded file or false if failed.
|
||||
*/
|
||||
public function download($url)
|
||||
@@ -258,7 +260,7 @@ class CRemoteImage
|
||||
return $this->updateCacheDetails();
|
||||
}
|
||||
|
||||
return false;
|
||||
throw new Exception("Unknown statuscode when downloading remote image: " . $this->status);
|
||||
}
|
||||
|
||||
|
||||
|
14
README.md
14
README.md
@@ -37,7 +37,7 @@ Requirements
|
||||
Installation
|
||||
--------------------------------------
|
||||
|
||||
There are two ways of installing. You either install the whole project which uses the autoloader to include the various files, or you install the all-included bundle that -- for convenience -- contains all code in one script.
|
||||
There are several ways of installing. You either install the whole project which uses the autoloader to include the various files, or you install the all-included bundle that -- for convenience -- contains all code in one script.
|
||||
|
||||
|
||||
|
||||
@@ -45,14 +45,14 @@ There are two ways of installing. You either install the whole project which use
|
||||
|
||||
The [sourcode is available on GitHub](https://github.com/mosbth/cimage). Clone, fork or [download as zip](https://github.com/mosbth/cimage/archive/master.zip).
|
||||
|
||||
**Latest stable version is v0.7.0 released 2015-02-10.**
|
||||
**Latest stable version is v0.7.6 released 2015-10-18.**
|
||||
|
||||
I prefer cloning like this. Do switch to the latest stable version.
|
||||
|
||||
```bash
|
||||
git clone git://github.com/mosbth/cimage.git
|
||||
cd cimage
|
||||
git checkout v0.7.0
|
||||
git checkout v0.7.6
|
||||
```
|
||||
|
||||
Make the cache-directory writable by the webserver.
|
||||
@@ -75,13 +75,19 @@ There are some all-included bundles of `img.php` that can be downloaded and used
|
||||
Dowload the version of your choice like this.
|
||||
|
||||
```bash
|
||||
wget https://github.com/mosbth/cimage/tree/v0.7.0/webroot/imgp.php
|
||||
wget https://github.com/mosbth/cimage/tree/v0.7.6/webroot/imgp.php
|
||||
```
|
||||
|
||||
Open up the file in your editor and edit the array `$config`. Ensure that the paths to the image directory and the cache directory matches your environment, or create an own config-file for the script.
|
||||
|
||||
|
||||
|
||||
###Install from Packagist
|
||||
|
||||
You can install the package [`mos/cimage` from Packagist](https://packagist.org/packages/mos/cimage) using composer.
|
||||
|
||||
|
||||
|
||||
Use cases
|
||||
--------------------------------------
|
||||
|
||||
|
35
REVISION.md
35
REVISION.md
@@ -5,6 +5,41 @@ Revision history
|
||||
[](https://scrutinizer-ci.com/g/mosbth/cimage/build-status/master)
|
||||
|
||||
|
||||
v0.7.6 (2015-10-18)
|
||||
-------------------------------------
|
||||
|
||||
* Adding testpage for dummy images `webroot/test/test_issue101-dummy.php`.
|
||||
* Adding width and height when creating dummy image.
|
||||
|
||||
|
||||
v0.7.5 (2015-10-18)
|
||||
-------------------------------------
|
||||
|
||||
* Adding feature for creating dummy images `src=dummy`, #101.
|
||||
* Add png compression to generated cache filename, fix #103.
|
||||
* Removed file prefix from storing images in cache, breaking filenamestructure for cache images.
|
||||
* Code cleaning in `CImage.php`.
|
||||
|
||||
|
||||
v0.7.4 (2015-09-15)
|
||||
-------------------------------------
|
||||
|
||||
* Add CAsciiArt.php to composer for autoloading, fix #102.
|
||||
* Generate filename with filters, does not work on Windows, fix #100.
|
||||
|
||||
|
||||
v0.7.3 (2015-09-01)
|
||||
-------------------------------------
|
||||
|
||||
* Support output of ascii images, #67.
|
||||
|
||||
|
||||
v0.7.2 (2015-08-17)
|
||||
-------------------------------------
|
||||
|
||||
* Allow space in remote filenames, fix #98.
|
||||
|
||||
|
||||
v0.7.1 (2015-07-25)
|
||||
-------------------------------------
|
||||
|
||||
|
@@ -37,6 +37,7 @@ $ECHO "\n webroot/img_header.php"
|
||||
$ECHO "\n CHttpGet.php"
|
||||
$ECHO "\n CRemoteImage.php"
|
||||
$ECHO "\n CWhitelist.php"
|
||||
$ECHO "\n CAsciiArt.php"
|
||||
$ECHO "\n CImage.php"
|
||||
$ECHO "\n webroot/img.php"
|
||||
$ECHO "\n"
|
||||
@@ -64,10 +65,13 @@ $ECHO "$NEWLINES" | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
tail -n +2 CRemoteImage.php | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
$ECHO "$NEWLINES" | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
|
||||
tail -n +2 CImage.php | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
tail -n +2 CWhitelist.php | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
$ECHO "$NEWLINES" | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
|
||||
tail -n +2 CWhitelist.php | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
tail -n +2 CAsciiArt.php | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
$ECHO "$NEWLINES" | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
|
||||
tail -n +2 CImage.php | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
$ECHO "$NEWLINES" | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
|
||||
tail -n +2 webroot/img.php | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
|
||||
|
1
cache/README.md
vendored
1
cache/README.md
vendored
@@ -1 +0,0 @@
|
||||
This directory must be writable by the webserver.
|
||||
|
0
cache/dummy/README.md
vendored
Normal file
0
cache/dummy/README.md
vendored
Normal file
@@ -25,12 +25,8 @@
|
||||
"CImage.php",
|
||||
"CHttpGet.php",
|
||||
"CRemoteImage.php",
|
||||
"CWhitelist.php"
|
||||
"CWhitelist.php",
|
||||
"CAsciiArt.php"
|
||||
]
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "0.7.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
49
test/CImageDummyTest.php
Normal file
49
test/CImageDummyTest.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/**
|
||||
* A testclass
|
||||
*
|
||||
*/
|
||||
class CImageDummyTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* Test
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testCreate1()
|
||||
{
|
||||
$img = new CImage();
|
||||
|
||||
$img->setSaveFolder(CACHE_PATH . "/dummy");
|
||||
$img->setSource('dummy', CACHE_PATH . "/dummy");
|
||||
$img->createDummyImage();
|
||||
$img->generateFilename(null, false);
|
||||
$img->save(null, null, false);
|
||||
|
||||
$filename = $img->getTarget();
|
||||
|
||||
$this->assertEquals(basename($filename), "dummy_100_100", "Filename not as expected on dummy image.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testCreate2()
|
||||
{
|
||||
$img = new CImage();
|
||||
|
||||
$img->setSaveFolder(CACHE_PATH . "/dummy");
|
||||
$img->setSource('dummy', CACHE_PATH . "/dummy");
|
||||
$img->createDummyImage(200, 400);
|
||||
$img->generateFilename(null, false);
|
||||
$img->save(null, null, false);
|
||||
|
||||
$filename = $img->getTarget();
|
||||
|
||||
$this->assertEquals(basename($filename), "dummy_200_400", "Filename not as expected on dummy image.");
|
||||
}
|
||||
}
|
@@ -4,3 +4,6 @@
|
||||
*
|
||||
*/
|
||||
require __DIR__ . "/../autoload.php";
|
||||
|
||||
define('IMAGE_PATH', __DIR__ . '/../webroot/img/');
|
||||
define('CACHE_PATH', __DIR__ . '/../cache/');
|
||||
|
104
webroot/img.php
104
webroot/img.php
@@ -8,12 +8,12 @@
|
||||
*
|
||||
*/
|
||||
|
||||
$version = "v0.7.1 (2015-07-25)";
|
||||
$version = "v0.7.6 (2015-10-18)";
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Default configuration options, can be overridden in own config-file.
|
||||
* Display error message.
|
||||
*
|
||||
* @param string $msg to display.
|
||||
*
|
||||
@@ -373,10 +373,20 @@ $imagePath = getConfig('image_path', __DIR__ . '/img/');
|
||||
$imagePathConstraint = getConfig('image_path_constraint', true);
|
||||
$validFilename = getConfig('valid_filename', '#^[a-z0-9A-Z-/_ \.:]+$#');
|
||||
|
||||
// Dummy image feature
|
||||
$dummyEnabled = getConfig('dummy_enabled', true);
|
||||
$dummyFilename = getConfig('dummy_filename', 'dummy');
|
||||
$dummyImage = false;
|
||||
|
||||
preg_match($validFilename, $srcImage)
|
||||
or errorPage('Filename contains invalid characters.');
|
||||
|
||||
if ($allowRemote && $img->isRemoteSource($srcImage)) {
|
||||
if ($dummyEnabled && $srcImage === $dummyFilename) {
|
||||
|
||||
// Prepare to create a dummy image and use it as the source image.
|
||||
$dummyImage = true;
|
||||
|
||||
} elseif ($allowRemote && $img->isRemoteSource($srcImage)) {
|
||||
|
||||
// If source is a remote file, ignore local file checks.
|
||||
|
||||
@@ -754,11 +764,51 @@ 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;
|
||||
}
|
||||
|
||||
$img->setAsciiOptions($defaultOptions);
|
||||
}
|
||||
|
||||
verbose("json = $outputFormat");
|
||||
|
||||
|
||||
|
||||
@@ -893,9 +943,47 @@ if ($verboseFile) {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Load, process and output the image
|
||||
*/
|
||||
/**
|
||||
* Set basic options for image processing.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Prepare a dummy image and use it as source image.
|
||||
*/
|
||||
if ($dummyImage === true) {
|
||||
|
||||
$dummyDir = getConfig('dummy_dir', $cachePath. "/" . $dummyFilename);
|
||||
|
||||
is_writable($dummyDir)
|
||||
or verbose("dummy dir not writable = $dummyDir");
|
||||
|
||||
$img->setSaveFolder($dummyDir)
|
||||
->setSource($dummyFilename, $dummyDir)
|
||||
->setOptions(
|
||||
array(
|
||||
'newWidth' => $newWidth,
|
||||
'newHeight' => $newHeight,
|
||||
'bgColor' => $bgColor,
|
||||
)
|
||||
)
|
||||
->setJpegQuality($quality)
|
||||
->setPngCompression($compress)
|
||||
->createDummyImage()
|
||||
->generateFilename(null, false)
|
||||
->save(null, null, false);
|
||||
|
||||
$srcImage = $img->getTarget();
|
||||
$imagePath = null;
|
||||
|
||||
verbose("src (updated) = $srcImage");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Load, process and output the image
|
||||
*/
|
||||
$img->log("Incoming arguments: " . print_r(verbose(), 1))
|
||||
->setSaveFolder($cachePath)
|
||||
->useCache($useCache)
|
||||
|
@@ -13,7 +13,6 @@ return array(
|
||||
* Default values:
|
||||
* mode: 'production'
|
||||
*/
|
||||
'mode' => 'development',
|
||||
//'mode' => 'production', // 'development', 'strict'
|
||||
|
||||
|
||||
@@ -109,6 +108,28 @@ return array(
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The name representing a dummy image which is automatically created
|
||||
* and stored at the defined path. The dummy image can then be used
|
||||
* inplace of an original image as a placeholder.
|
||||
* The dummy_dir must be writable and it defaults to a subdir of the
|
||||
* cache directory.
|
||||
* Write protect the dummy_dir to prevent creation of new dummy images,
|
||||
* but continue to use the existing ones.
|
||||
*
|
||||
* Default value:
|
||||
* dummy_enabled: true as default, disable dummy feature by setting
|
||||
* to false.
|
||||
* dummy_filename: 'dummy' use this as ?src=dummy to create a dummy image.
|
||||
* dummy_dir: Defaults to subdirectory of 'cache_path',
|
||||
* named the same as 'dummy_filename'
|
||||
*/
|
||||
//'dummy_enabled' => true,
|
||||
//'dummy_filename' => 'dummy',
|
||||
//'dummy_dir' => 'some writable directory',
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check that the imagefile is a file below 'image_path' using realpath().
|
||||
* Security constraint to avoid reaching images outside image_path.
|
||||
@@ -299,4 +320,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,
|
||||
);
|
||||
},*/
|
||||
);
|
||||
|
728
webroot/imgd.php
728
webroot/imgd.php
@@ -58,6 +58,33 @@ class CHttpGet
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Build an encoded url.
|
||||
*
|
||||
* @param string $baseUrl This is the original url which will be merged.
|
||||
* @param string $merge Thse parts should be merged into the baseUrl,
|
||||
* the format is as parse_url.
|
||||
*
|
||||
* @return string $url as the modified url.
|
||||
*/
|
||||
public function buildUrl($baseUrl, $merge)
|
||||
{
|
||||
$parts = parse_url($baseUrl);
|
||||
$parts = array_merge($parts, $merge);
|
||||
|
||||
$url = $parts['scheme'];
|
||||
$url .= "://";
|
||||
$url .= $parts['host'];
|
||||
$url .= isset($parts['port'])
|
||||
? ":" . $parts['port']
|
||||
: "" ;
|
||||
$url .= $parts['path'];
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the url for the request.
|
||||
*
|
||||
@@ -67,6 +94,18 @@ class CHttpGet
|
||||
*/
|
||||
public function setUrl($url)
|
||||
{
|
||||
$parts = parse_url($url);
|
||||
|
||||
$path = "";
|
||||
if (isset($parts['path'])) {
|
||||
$pathParts = explode('/', $parts['path']);
|
||||
unset($pathParts[0]);
|
||||
foreach ($pathParts as $value) {
|
||||
$path .= "/" . rawurlencode($value);
|
||||
}
|
||||
}
|
||||
$url = $this->buildUrl($url, array("path" => $path));
|
||||
|
||||
$this->request['url'] = $url;
|
||||
return $this;
|
||||
}
|
||||
@@ -130,6 +169,8 @@ class CHttpGet
|
||||
*
|
||||
* @param boolean $debug set to true to dump headers.
|
||||
*
|
||||
* @throws Exception when curl fails to retrieve url.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function doGet($debug = false)
|
||||
@@ -152,7 +193,7 @@ class CHttpGet
|
||||
$response = curl_exec($ch);
|
||||
|
||||
if (!$response) {
|
||||
return false;
|
||||
throw new Exception("Failed retrieving url, details follows: " . curl_error($ch));
|
||||
}
|
||||
|
||||
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||
@@ -435,7 +476,7 @@ class CRemoteImage
|
||||
*/
|
||||
public function setHeaderFields()
|
||||
{
|
||||
$this->http->setHeader("User-Agent", "CImage/0.7.0 (PHP/". phpversion() . " cURL)");
|
||||
$this->http->setHeader("User-Agent", "CImage/0.7.2 (PHP/". phpversion() . " cURL)");
|
||||
$this->http->setHeader("Accept", "image/jpeg,image/png,image/gif");
|
||||
|
||||
if ($this->useCache) {
|
||||
@@ -514,6 +555,8 @@ class CRemoteImage
|
||||
*
|
||||
* @param string $url a remote url.
|
||||
*
|
||||
* @throws Exception when status code does not match 200 or 304.
|
||||
*
|
||||
* @return string as path to downloaded file or false if failed.
|
||||
*/
|
||||
public function download($url)
|
||||
@@ -546,7 +589,7 @@ class CRemoteImage
|
||||
return $this->updateCacheDetails();
|
||||
}
|
||||
|
||||
return false;
|
||||
throw new Exception("Unknown statuscode when downloading remote image: " . $this->status);
|
||||
}
|
||||
|
||||
|
||||
@@ -597,6 +640,284 @@ class CRemoteImage
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Act as whitelist (or blacklist).
|
||||
*
|
||||
*/
|
||||
class CWhitelist
|
||||
{
|
||||
/**
|
||||
* Array to contain the whitelist options.
|
||||
*/
|
||||
private $whitelist = array();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the whitelist from an array of strings, each item in the
|
||||
* whitelist should be a regexp without the surrounding / or #.
|
||||
*
|
||||
* @param array $whitelist with all valid options,
|
||||
* default is to clear the whitelist.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function set($whitelist = array())
|
||||
{
|
||||
if (!is_array($whitelist)) {
|
||||
throw new Exception("Whitelist is not of a supported format.");
|
||||
}
|
||||
|
||||
$this->whitelist = $whitelist;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check if item exists in the whitelist.
|
||||
*
|
||||
* @param string $item string to check.
|
||||
* @param array $whitelist optional with all valid options, default is null.
|
||||
*
|
||||
* @return boolean true if item is in whitelist, else false.
|
||||
*/
|
||||
public function check($item, $whitelist = null)
|
||||
{
|
||||
if ($whitelist !== null) {
|
||||
$this->set($whitelist);
|
||||
}
|
||||
|
||||
if (empty($item) or empty($this->whitelist)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($this->whitelist as $regexp) {
|
||||
if (preg_match("#$regexp#", $item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create an ASCII version of an image.
|
||||
*
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set options for processing, defaults are available.
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Resize and crop images on the fly, store generated images in a cache.
|
||||
*
|
||||
@@ -711,13 +1032,6 @@ class CImage
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The root folder of images (only used in constructor to create $pathToImage?).
|
||||
*/
|
||||
private $imageFolder;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Image filename, may include subdirectory, relative from $imageFolder
|
||||
*/
|
||||
@@ -791,6 +1105,7 @@ class CImage
|
||||
* Path to command for filter optimize, for example optipng or null.
|
||||
*/
|
||||
private $pngFilter;
|
||||
private $pngFilterCmd;
|
||||
|
||||
|
||||
|
||||
@@ -798,13 +1113,16 @@ class CImage
|
||||
* Path to command for deflate optimize, for example pngout or null.
|
||||
*/
|
||||
private $pngDeflate;
|
||||
private $pngDeflateCmd;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Path to command to optimize jpeg images, for example jpegtran or null.
|
||||
*/
|
||||
private $jpegOptimize;
|
||||
private $jpegOptimize;
|
||||
private $jpegOptimizeCmd;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@@ -880,6 +1198,56 @@ class CImage
|
||||
private $fillToFit;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option scale.
|
||||
*/
|
||||
private $scale;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option.
|
||||
*/
|
||||
private $rotateBefore;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option.
|
||||
*/
|
||||
private $rotateAfter;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option.
|
||||
*/
|
||||
private $autoRotate;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option.
|
||||
*/
|
||||
private $sharpen;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option.
|
||||
*/
|
||||
private $emboss;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option.
|
||||
*/
|
||||
private $blur;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Used with option area to set which parts of the image to use.
|
||||
*/
|
||||
@@ -932,6 +1300,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.
|
||||
@@ -946,9 +1321,7 @@ class CImage
|
||||
public $crop_x;
|
||||
public $crop_y;
|
||||
public $filters;
|
||||
private $type; // Calculated from source image
|
||||
private $attr; // Calculated from source image
|
||||
private $useOriginal; // Use original image if possible
|
||||
|
||||
|
||||
|
||||
@@ -1005,9 +1378,7 @@ class CImage
|
||||
/**
|
||||
* Use cache or not.
|
||||
*
|
||||
* @todo clean up how $this->noCache is used in other methods.
|
||||
*
|
||||
* @param string $use true or false to use cache.
|
||||
* @param boolean $use true or false to use cache.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
@@ -1019,6 +1390,27 @@ class CImage
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create and save a dummy image. Use dimensions as stated in
|
||||
* $this->newWidth, or $width or default to 100 (same for height.
|
||||
*
|
||||
* @param integer $width use specified width for image dimension.
|
||||
* @param integer $height use specified width for image dimension.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function createDummyImage($width = null, $height = null)
|
||||
{
|
||||
$this->newWidth = $this->newWidth ?: $width ?: 100;
|
||||
$this->newHeight = $this->newHeight ?: $height ?: 100;
|
||||
|
||||
$this->image = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Allow or disallow remote image download.
|
||||
*
|
||||
@@ -1169,16 +1561,18 @@ class CImage
|
||||
|
||||
|
||||
/**
|
||||
* Set src file.
|
||||
* Set source file to use as image source.
|
||||
*
|
||||
* @param string $src of image.
|
||||
* @param string $dir as base directory where images are.
|
||||
* @param string $dir as optional base directory where images are.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSource($src, $dir = null)
|
||||
{
|
||||
if (!isset($src)) {
|
||||
$this->imageSrc = null;
|
||||
$this->pathToImage = null;
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -1192,9 +1586,9 @@ class CImage
|
||||
$src = basename($src);
|
||||
}
|
||||
|
||||
$this->imageSrc = ltrim($src, '/');
|
||||
$this->imageFolder = rtrim($dir, '/');
|
||||
$this->pathToImage = $this->imageFolder . '/' . $this->imageSrc;
|
||||
$this->imageSrc = ltrim($src, '/');
|
||||
$imageFolder = rtrim($dir, '/');
|
||||
$this->pathToImage = $imageFolder . '/' . $this->imageSrc;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -1205,23 +1599,23 @@ class CImage
|
||||
* Set target file.
|
||||
*
|
||||
* @param string $src of target image.
|
||||
* @param string $dir as base directory where images are stored.
|
||||
* @param string $dir as optional base directory where images are stored.
|
||||
* Uses $this->saveFolder if null.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setTarget($src = null, $dir = null)
|
||||
{
|
||||
if (!(isset($src) && isset($dir))) {
|
||||
if (!isset($src)) {
|
||||
$this->cacheFileName = null;
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->saveFolder = $dir;
|
||||
$this->cacheFileName = $dir . '/' . $src;
|
||||
if (isset($dir)) {
|
||||
$this->saveFolder = rtrim($dir, '/');
|
||||
}
|
||||
|
||||
/* Allow readonly cache
|
||||
is_writable($this->saveFolder)
|
||||
or $this->raiseError('Target directory is not writable.');
|
||||
*/
|
||||
$this->cacheFileName = $this->saveFolder . '/' . $src;
|
||||
|
||||
// Sanitize filename
|
||||
$this->cacheFileName = preg_replace('/^a-zA-Z0-9\.-_/', '', $this->cacheFileName);
|
||||
@@ -1232,6 +1626,18 @@ class CImage
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get filename of target file.
|
||||
*
|
||||
* @return Boolean|String as filename of target or false if not set.
|
||||
*/
|
||||
public function getTarget()
|
||||
{
|
||||
return $this->cacheFileName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set options to use when processing image.
|
||||
*
|
||||
@@ -1279,11 +1685,6 @@ class CImage
|
||||
// Output format
|
||||
'outputFormat' => null,
|
||||
'dpr' => 1,
|
||||
|
||||
// Options for saving
|
||||
//'quality' => null,
|
||||
//'compress' => null,
|
||||
//'saveAs' => null,
|
||||
);
|
||||
|
||||
// Convert crop settings from string to array
|
||||
@@ -1777,13 +2178,15 @@ class CImage
|
||||
/**
|
||||
* Generate filename to save file in cache.
|
||||
*
|
||||
* @param string $base as basepath for storing file.
|
||||
* @param string $base as optional basepath for storing file.
|
||||
* @param boolean $useSubdir use or skip the subdir part when creating the
|
||||
* filename.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function generateFilename($base)
|
||||
public function generateFilename($base = null, $useSubdir = true)
|
||||
{
|
||||
$parts = pathinfo($this->pathToImage);
|
||||
$filename = basename($this->pathToImage);
|
||||
$cropToFit = $this->cropToFit ? '_cf' : null;
|
||||
$fillToFit = $this->fillToFit ? '_ff' : null;
|
||||
$crop_x = $this->crop_x ? "_x{$this->crop_x}" : null;
|
||||
@@ -1812,7 +2215,7 @@ class CImage
|
||||
if (is_array($filter)) {
|
||||
$filters .= "_f{$filter['id']}";
|
||||
for ($i=1; $i<=$filter['argc']; $i++) {
|
||||
$filters .= ":".$filter["arg{$i}"];
|
||||
$filters .= "-".$filter["arg{$i}"];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1825,16 +2228,6 @@ class CImage
|
||||
|
||||
$autoRotate = $this->autoRotate ? 'ar' : null;
|
||||
|
||||
$this->extension = isset($this->extension)
|
||||
? $this->extension
|
||||
: (isset($parts['extension'])
|
||||
? $parts['extension']
|
||||
: null);
|
||||
|
||||
$extension = empty($this->extension)
|
||||
? null
|
||||
: "." . $this->extension;
|
||||
|
||||
$optimize = $this->jpegOptimize ? 'o' : null;
|
||||
$optimize .= $this->pngFilter ? 'f' : null;
|
||||
$optimize .= $this->pngDeflate ? 'd' : null;
|
||||
@@ -1849,14 +2242,20 @@ class CImage
|
||||
$upscale = '_nu';
|
||||
}
|
||||
|
||||
$subdir = str_replace('/', '-', dirname($this->imageSrc));
|
||||
$subdir = ($subdir == '.') ? '_.' : $subdir;
|
||||
$file = $subdir . '_' . $parts['filename'] . '_' . $width . '_'
|
||||
$subdir = null;
|
||||
if ($useSubdir === true) {
|
||||
$subdir = str_replace('/', '-', dirname($this->imageSrc));
|
||||
$subdir = ($subdir == '.') ? '_.' : $subdir;
|
||||
$subdir .= '_';
|
||||
}
|
||||
|
||||
$file = $subdir . $filename . '_' . $width . '_'
|
||||
. $height . $offset . $crop . $cropToFit . $fillToFit
|
||||
. $crop_x . $crop_y . $upscale
|
||||
. $quality . $filters . $sharpen . $emboss . $blur . $palette . $optimize
|
||||
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor . $convolve
|
||||
. $extension;
|
||||
. $quality . $filters . $sharpen . $emboss . $blur . $palette
|
||||
. $optimize . $compress
|
||||
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor
|
||||
. $convolve;
|
||||
|
||||
return $this->setTarget($file, $base);
|
||||
}
|
||||
@@ -2624,7 +3023,10 @@ class CImage
|
||||
imagealphablending($img, false);
|
||||
imagesavealpha($img, true);
|
||||
|
||||
$index = imagecolortransparent($this->image);
|
||||
$index = $this->image
|
||||
? imagecolortransparent($this->image)
|
||||
: -1;
|
||||
|
||||
if ($index != -1) {
|
||||
|
||||
imagealphablending($img, true);
|
||||
@@ -2697,17 +3099,23 @@ class CImage
|
||||
/**
|
||||
* Save image.
|
||||
*
|
||||
* @param string $src as target filename.
|
||||
* @param string $base as base directory where to store images.
|
||||
* @param string $src as target filename.
|
||||
* @param string $base as base directory where to store images.
|
||||
* @param boolean $overwrite or not, default to always overwrite file.
|
||||
*
|
||||
* @return $this or false if no folder is set.
|
||||
*/
|
||||
public function save($src = null, $base = null)
|
||||
public function save($src = null, $base = null, $overwrite = true)
|
||||
{
|
||||
if (isset($src)) {
|
||||
$this->setTarget($src, $base);
|
||||
}
|
||||
|
||||
if ($overwrite === false && is_file($this->cacheFileName)) {
|
||||
$this->Log("Not overwriting file since its already exists and \$overwrite if false.");
|
||||
return;
|
||||
}
|
||||
|
||||
is_writable($this->saveFolder)
|
||||
or $this->raiseError('Target directory is not writable.');
|
||||
|
||||
@@ -2848,6 +3256,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");
|
||||
@@ -2939,6 +3351,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.
|
||||
*
|
||||
@@ -3028,70 +3472,6 @@ EOD;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Act as whitelist (or blacklist).
|
||||
*
|
||||
*/
|
||||
class CWhitelist
|
||||
{
|
||||
/**
|
||||
* Array to contain the whitelist options.
|
||||
*/
|
||||
private $whitelist = array();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the whitelist from an array of strings, each item in the
|
||||
* whitelist should be a regexp without the surrounding / or #.
|
||||
*
|
||||
* @param array $whitelist with all valid options,
|
||||
* default is to clear the whitelist.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function set($whitelist = array())
|
||||
{
|
||||
if (!is_array($whitelist)) {
|
||||
throw new Exception("Whitelist is not of a supported format.");
|
||||
}
|
||||
|
||||
$this->whitelist = $whitelist;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check if item exists in the whitelist.
|
||||
*
|
||||
* @param string $item string to check.
|
||||
* @param array $whitelist optional with all valid options, default is null.
|
||||
*
|
||||
* @return boolean true if item is in whitelist, else false.
|
||||
*/
|
||||
public function check($item, $whitelist = null)
|
||||
{
|
||||
if ($whitelist !== null) {
|
||||
$this->set($whitelist);
|
||||
}
|
||||
|
||||
if (empty($item) or empty($this->whitelist)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($this->whitelist as $regexp) {
|
||||
if (preg_match("#$regexp#", $item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Resize and crop images on the fly, store generated images in a cache.
|
||||
*
|
||||
@@ -3101,12 +3481,12 @@ class CWhitelist
|
||||
*
|
||||
*/
|
||||
|
||||
$version = "v0.7.1 (2015-07-25)";
|
||||
$version = "v0.7.6 (2015-10-18)";
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Default configuration options, can be overridden in own config-file.
|
||||
* Display error message.
|
||||
*
|
||||
* @param string $msg to display.
|
||||
*
|
||||
@@ -3466,10 +3846,20 @@ $imagePath = getConfig('image_path', __DIR__ . '/img/');
|
||||
$imagePathConstraint = getConfig('image_path_constraint', true);
|
||||
$validFilename = getConfig('valid_filename', '#^[a-z0-9A-Z-/_ \.:]+$#');
|
||||
|
||||
// Dummy image feature
|
||||
$dummyEnabled = getConfig('dummy_enabled', true);
|
||||
$dummyFilename = getConfig('dummy_filename', 'dummy');
|
||||
$dummyImage = false;
|
||||
|
||||
preg_match($validFilename, $srcImage)
|
||||
or errorPage('Filename contains invalid characters.');
|
||||
|
||||
if ($allowRemote && $img->isRemoteSource($srcImage)) {
|
||||
if ($dummyEnabled && $srcImage === $dummyFilename) {
|
||||
|
||||
// Prepare to create a dummy image and use it as the source image.
|
||||
$dummyImage = true;
|
||||
|
||||
} elseif ($allowRemote && $img->isRemoteSource($srcImage)) {
|
||||
|
||||
// If source is a remote file, ignore local file checks.
|
||||
|
||||
@@ -3847,11 +4237,51 @@ 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;
|
||||
}
|
||||
|
||||
$img->setAsciiOptions($defaultOptions);
|
||||
}
|
||||
|
||||
verbose("json = $outputFormat");
|
||||
|
||||
|
||||
|
||||
@@ -3986,9 +4416,47 @@ if ($verboseFile) {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Load, process and output the image
|
||||
*/
|
||||
/**
|
||||
* Set basic options for image processing.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Prepare a dummy image and use it as source image.
|
||||
*/
|
||||
if ($dummyImage === true) {
|
||||
|
||||
$dummyDir = getConfig('dummy_dir', $cachePath. "/" . $dummyFilename);
|
||||
|
||||
is_writable($dummyDir)
|
||||
or verbose("dummy dir not writable = $dummyDir");
|
||||
|
||||
$img->setSaveFolder($dummyDir)
|
||||
->setSource($dummyFilename, $dummyDir)
|
||||
->setOptions(
|
||||
array(
|
||||
'newWidth' => $newWidth,
|
||||
'newHeight' => $newHeight,
|
||||
'bgColor' => $bgColor,
|
||||
)
|
||||
)
|
||||
->setJpegQuality($quality)
|
||||
->setPngCompression($compress)
|
||||
->createDummyImage()
|
||||
->generateFilename(null, false)
|
||||
->save(null, null, false);
|
||||
|
||||
$srcImage = $img->getTarget();
|
||||
$imagePath = null;
|
||||
|
||||
verbose("src (updated) = $srcImage");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Load, process and output the image
|
||||
*/
|
||||
$img->log("Incoming arguments: " . print_r(verbose(), 1))
|
||||
->setSaveFolder($cachePath)
|
||||
->useCache($useCache)
|
||||
|
728
webroot/imgp.php
728
webroot/imgp.php
@@ -58,6 +58,33 @@ class CHttpGet
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Build an encoded url.
|
||||
*
|
||||
* @param string $baseUrl This is the original url which will be merged.
|
||||
* @param string $merge Thse parts should be merged into the baseUrl,
|
||||
* the format is as parse_url.
|
||||
*
|
||||
* @return string $url as the modified url.
|
||||
*/
|
||||
public function buildUrl($baseUrl, $merge)
|
||||
{
|
||||
$parts = parse_url($baseUrl);
|
||||
$parts = array_merge($parts, $merge);
|
||||
|
||||
$url = $parts['scheme'];
|
||||
$url .= "://";
|
||||
$url .= $parts['host'];
|
||||
$url .= isset($parts['port'])
|
||||
? ":" . $parts['port']
|
||||
: "" ;
|
||||
$url .= $parts['path'];
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the url for the request.
|
||||
*
|
||||
@@ -67,6 +94,18 @@ class CHttpGet
|
||||
*/
|
||||
public function setUrl($url)
|
||||
{
|
||||
$parts = parse_url($url);
|
||||
|
||||
$path = "";
|
||||
if (isset($parts['path'])) {
|
||||
$pathParts = explode('/', $parts['path']);
|
||||
unset($pathParts[0]);
|
||||
foreach ($pathParts as $value) {
|
||||
$path .= "/" . rawurlencode($value);
|
||||
}
|
||||
}
|
||||
$url = $this->buildUrl($url, array("path" => $path));
|
||||
|
||||
$this->request['url'] = $url;
|
||||
return $this;
|
||||
}
|
||||
@@ -130,6 +169,8 @@ class CHttpGet
|
||||
*
|
||||
* @param boolean $debug set to true to dump headers.
|
||||
*
|
||||
* @throws Exception when curl fails to retrieve url.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function doGet($debug = false)
|
||||
@@ -152,7 +193,7 @@ class CHttpGet
|
||||
$response = curl_exec($ch);
|
||||
|
||||
if (!$response) {
|
||||
return false;
|
||||
throw new Exception("Failed retrieving url, details follows: " . curl_error($ch));
|
||||
}
|
||||
|
||||
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||
@@ -435,7 +476,7 @@ class CRemoteImage
|
||||
*/
|
||||
public function setHeaderFields()
|
||||
{
|
||||
$this->http->setHeader("User-Agent", "CImage/0.7.0 (PHP/". phpversion() . " cURL)");
|
||||
$this->http->setHeader("User-Agent", "CImage/0.7.2 (PHP/". phpversion() . " cURL)");
|
||||
$this->http->setHeader("Accept", "image/jpeg,image/png,image/gif");
|
||||
|
||||
if ($this->useCache) {
|
||||
@@ -514,6 +555,8 @@ class CRemoteImage
|
||||
*
|
||||
* @param string $url a remote url.
|
||||
*
|
||||
* @throws Exception when status code does not match 200 or 304.
|
||||
*
|
||||
* @return string as path to downloaded file or false if failed.
|
||||
*/
|
||||
public function download($url)
|
||||
@@ -546,7 +589,7 @@ class CRemoteImage
|
||||
return $this->updateCacheDetails();
|
||||
}
|
||||
|
||||
return false;
|
||||
throw new Exception("Unknown statuscode when downloading remote image: " . $this->status);
|
||||
}
|
||||
|
||||
|
||||
@@ -597,6 +640,284 @@ class CRemoteImage
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Act as whitelist (or blacklist).
|
||||
*
|
||||
*/
|
||||
class CWhitelist
|
||||
{
|
||||
/**
|
||||
* Array to contain the whitelist options.
|
||||
*/
|
||||
private $whitelist = array();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the whitelist from an array of strings, each item in the
|
||||
* whitelist should be a regexp without the surrounding / or #.
|
||||
*
|
||||
* @param array $whitelist with all valid options,
|
||||
* default is to clear the whitelist.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function set($whitelist = array())
|
||||
{
|
||||
if (!is_array($whitelist)) {
|
||||
throw new Exception("Whitelist is not of a supported format.");
|
||||
}
|
||||
|
||||
$this->whitelist = $whitelist;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check if item exists in the whitelist.
|
||||
*
|
||||
* @param string $item string to check.
|
||||
* @param array $whitelist optional with all valid options, default is null.
|
||||
*
|
||||
* @return boolean true if item is in whitelist, else false.
|
||||
*/
|
||||
public function check($item, $whitelist = null)
|
||||
{
|
||||
if ($whitelist !== null) {
|
||||
$this->set($whitelist);
|
||||
}
|
||||
|
||||
if (empty($item) or empty($this->whitelist)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($this->whitelist as $regexp) {
|
||||
if (preg_match("#$regexp#", $item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create an ASCII version of an image.
|
||||
*
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set options for processing, defaults are available.
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Resize and crop images on the fly, store generated images in a cache.
|
||||
*
|
||||
@@ -711,13 +1032,6 @@ class CImage
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The root folder of images (only used in constructor to create $pathToImage?).
|
||||
*/
|
||||
private $imageFolder;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Image filename, may include subdirectory, relative from $imageFolder
|
||||
*/
|
||||
@@ -791,6 +1105,7 @@ class CImage
|
||||
* Path to command for filter optimize, for example optipng or null.
|
||||
*/
|
||||
private $pngFilter;
|
||||
private $pngFilterCmd;
|
||||
|
||||
|
||||
|
||||
@@ -798,13 +1113,16 @@ class CImage
|
||||
* Path to command for deflate optimize, for example pngout or null.
|
||||
*/
|
||||
private $pngDeflate;
|
||||
private $pngDeflateCmd;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Path to command to optimize jpeg images, for example jpegtran or null.
|
||||
*/
|
||||
private $jpegOptimize;
|
||||
private $jpegOptimize;
|
||||
private $jpegOptimizeCmd;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@@ -880,6 +1198,56 @@ class CImage
|
||||
private $fillToFit;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option scale.
|
||||
*/
|
||||
private $scale;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option.
|
||||
*/
|
||||
private $rotateBefore;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option.
|
||||
*/
|
||||
private $rotateAfter;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option.
|
||||
*/
|
||||
private $autoRotate;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option.
|
||||
*/
|
||||
private $sharpen;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option.
|
||||
*/
|
||||
private $emboss;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option.
|
||||
*/
|
||||
private $blur;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Used with option area to set which parts of the image to use.
|
||||
*/
|
||||
@@ -932,6 +1300,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.
|
||||
@@ -946,9 +1321,7 @@ class CImage
|
||||
public $crop_x;
|
||||
public $crop_y;
|
||||
public $filters;
|
||||
private $type; // Calculated from source image
|
||||
private $attr; // Calculated from source image
|
||||
private $useOriginal; // Use original image if possible
|
||||
|
||||
|
||||
|
||||
@@ -1005,9 +1378,7 @@ class CImage
|
||||
/**
|
||||
* Use cache or not.
|
||||
*
|
||||
* @todo clean up how $this->noCache is used in other methods.
|
||||
*
|
||||
* @param string $use true or false to use cache.
|
||||
* @param boolean $use true or false to use cache.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
@@ -1019,6 +1390,27 @@ class CImage
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create and save a dummy image. Use dimensions as stated in
|
||||
* $this->newWidth, or $width or default to 100 (same for height.
|
||||
*
|
||||
* @param integer $width use specified width for image dimension.
|
||||
* @param integer $height use specified width for image dimension.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function createDummyImage($width = null, $height = null)
|
||||
{
|
||||
$this->newWidth = $this->newWidth ?: $width ?: 100;
|
||||
$this->newHeight = $this->newHeight ?: $height ?: 100;
|
||||
|
||||
$this->image = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Allow or disallow remote image download.
|
||||
*
|
||||
@@ -1169,16 +1561,18 @@ class CImage
|
||||
|
||||
|
||||
/**
|
||||
* Set src file.
|
||||
* Set source file to use as image source.
|
||||
*
|
||||
* @param string $src of image.
|
||||
* @param string $dir as base directory where images are.
|
||||
* @param string $dir as optional base directory where images are.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSource($src, $dir = null)
|
||||
{
|
||||
if (!isset($src)) {
|
||||
$this->imageSrc = null;
|
||||
$this->pathToImage = null;
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -1192,9 +1586,9 @@ class CImage
|
||||
$src = basename($src);
|
||||
}
|
||||
|
||||
$this->imageSrc = ltrim($src, '/');
|
||||
$this->imageFolder = rtrim($dir, '/');
|
||||
$this->pathToImage = $this->imageFolder . '/' . $this->imageSrc;
|
||||
$this->imageSrc = ltrim($src, '/');
|
||||
$imageFolder = rtrim($dir, '/');
|
||||
$this->pathToImage = $imageFolder . '/' . $this->imageSrc;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -1205,23 +1599,23 @@ class CImage
|
||||
* Set target file.
|
||||
*
|
||||
* @param string $src of target image.
|
||||
* @param string $dir as base directory where images are stored.
|
||||
* @param string $dir as optional base directory where images are stored.
|
||||
* Uses $this->saveFolder if null.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setTarget($src = null, $dir = null)
|
||||
{
|
||||
if (!(isset($src) && isset($dir))) {
|
||||
if (!isset($src)) {
|
||||
$this->cacheFileName = null;
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->saveFolder = $dir;
|
||||
$this->cacheFileName = $dir . '/' . $src;
|
||||
if (isset($dir)) {
|
||||
$this->saveFolder = rtrim($dir, '/');
|
||||
}
|
||||
|
||||
/* Allow readonly cache
|
||||
is_writable($this->saveFolder)
|
||||
or $this->raiseError('Target directory is not writable.');
|
||||
*/
|
||||
$this->cacheFileName = $this->saveFolder . '/' . $src;
|
||||
|
||||
// Sanitize filename
|
||||
$this->cacheFileName = preg_replace('/^a-zA-Z0-9\.-_/', '', $this->cacheFileName);
|
||||
@@ -1232,6 +1626,18 @@ class CImage
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get filename of target file.
|
||||
*
|
||||
* @return Boolean|String as filename of target or false if not set.
|
||||
*/
|
||||
public function getTarget()
|
||||
{
|
||||
return $this->cacheFileName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set options to use when processing image.
|
||||
*
|
||||
@@ -1279,11 +1685,6 @@ class CImage
|
||||
// Output format
|
||||
'outputFormat' => null,
|
||||
'dpr' => 1,
|
||||
|
||||
// Options for saving
|
||||
//'quality' => null,
|
||||
//'compress' => null,
|
||||
//'saveAs' => null,
|
||||
);
|
||||
|
||||
// Convert crop settings from string to array
|
||||
@@ -1777,13 +2178,15 @@ class CImage
|
||||
/**
|
||||
* Generate filename to save file in cache.
|
||||
*
|
||||
* @param string $base as basepath for storing file.
|
||||
* @param string $base as optional basepath for storing file.
|
||||
* @param boolean $useSubdir use or skip the subdir part when creating the
|
||||
* filename.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function generateFilename($base)
|
||||
public function generateFilename($base = null, $useSubdir = true)
|
||||
{
|
||||
$parts = pathinfo($this->pathToImage);
|
||||
$filename = basename($this->pathToImage);
|
||||
$cropToFit = $this->cropToFit ? '_cf' : null;
|
||||
$fillToFit = $this->fillToFit ? '_ff' : null;
|
||||
$crop_x = $this->crop_x ? "_x{$this->crop_x}" : null;
|
||||
@@ -1812,7 +2215,7 @@ class CImage
|
||||
if (is_array($filter)) {
|
||||
$filters .= "_f{$filter['id']}";
|
||||
for ($i=1; $i<=$filter['argc']; $i++) {
|
||||
$filters .= ":".$filter["arg{$i}"];
|
||||
$filters .= "-".$filter["arg{$i}"];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1825,16 +2228,6 @@ class CImage
|
||||
|
||||
$autoRotate = $this->autoRotate ? 'ar' : null;
|
||||
|
||||
$this->extension = isset($this->extension)
|
||||
? $this->extension
|
||||
: (isset($parts['extension'])
|
||||
? $parts['extension']
|
||||
: null);
|
||||
|
||||
$extension = empty($this->extension)
|
||||
? null
|
||||
: "." . $this->extension;
|
||||
|
||||
$optimize = $this->jpegOptimize ? 'o' : null;
|
||||
$optimize .= $this->pngFilter ? 'f' : null;
|
||||
$optimize .= $this->pngDeflate ? 'd' : null;
|
||||
@@ -1849,14 +2242,20 @@ class CImage
|
||||
$upscale = '_nu';
|
||||
}
|
||||
|
||||
$subdir = str_replace('/', '-', dirname($this->imageSrc));
|
||||
$subdir = ($subdir == '.') ? '_.' : $subdir;
|
||||
$file = $subdir . '_' . $parts['filename'] . '_' . $width . '_'
|
||||
$subdir = null;
|
||||
if ($useSubdir === true) {
|
||||
$subdir = str_replace('/', '-', dirname($this->imageSrc));
|
||||
$subdir = ($subdir == '.') ? '_.' : $subdir;
|
||||
$subdir .= '_';
|
||||
}
|
||||
|
||||
$file = $subdir . $filename . '_' . $width . '_'
|
||||
. $height . $offset . $crop . $cropToFit . $fillToFit
|
||||
. $crop_x . $crop_y . $upscale
|
||||
. $quality . $filters . $sharpen . $emboss . $blur . $palette . $optimize
|
||||
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor . $convolve
|
||||
. $extension;
|
||||
. $quality . $filters . $sharpen . $emboss . $blur . $palette
|
||||
. $optimize . $compress
|
||||
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor
|
||||
. $convolve;
|
||||
|
||||
return $this->setTarget($file, $base);
|
||||
}
|
||||
@@ -2624,7 +3023,10 @@ class CImage
|
||||
imagealphablending($img, false);
|
||||
imagesavealpha($img, true);
|
||||
|
||||
$index = imagecolortransparent($this->image);
|
||||
$index = $this->image
|
||||
? imagecolortransparent($this->image)
|
||||
: -1;
|
||||
|
||||
if ($index != -1) {
|
||||
|
||||
imagealphablending($img, true);
|
||||
@@ -2697,17 +3099,23 @@ class CImage
|
||||
/**
|
||||
* Save image.
|
||||
*
|
||||
* @param string $src as target filename.
|
||||
* @param string $base as base directory where to store images.
|
||||
* @param string $src as target filename.
|
||||
* @param string $base as base directory where to store images.
|
||||
* @param boolean $overwrite or not, default to always overwrite file.
|
||||
*
|
||||
* @return $this or false if no folder is set.
|
||||
*/
|
||||
public function save($src = null, $base = null)
|
||||
public function save($src = null, $base = null, $overwrite = true)
|
||||
{
|
||||
if (isset($src)) {
|
||||
$this->setTarget($src, $base);
|
||||
}
|
||||
|
||||
if ($overwrite === false && is_file($this->cacheFileName)) {
|
||||
$this->Log("Not overwriting file since its already exists and \$overwrite if false.");
|
||||
return;
|
||||
}
|
||||
|
||||
is_writable($this->saveFolder)
|
||||
or $this->raiseError('Target directory is not writable.');
|
||||
|
||||
@@ -2848,6 +3256,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");
|
||||
@@ -2939,6 +3351,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.
|
||||
*
|
||||
@@ -3028,70 +3472,6 @@ EOD;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Act as whitelist (or blacklist).
|
||||
*
|
||||
*/
|
||||
class CWhitelist
|
||||
{
|
||||
/**
|
||||
* Array to contain the whitelist options.
|
||||
*/
|
||||
private $whitelist = array();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the whitelist from an array of strings, each item in the
|
||||
* whitelist should be a regexp without the surrounding / or #.
|
||||
*
|
||||
* @param array $whitelist with all valid options,
|
||||
* default is to clear the whitelist.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function set($whitelist = array())
|
||||
{
|
||||
if (!is_array($whitelist)) {
|
||||
throw new Exception("Whitelist is not of a supported format.");
|
||||
}
|
||||
|
||||
$this->whitelist = $whitelist;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check if item exists in the whitelist.
|
||||
*
|
||||
* @param string $item string to check.
|
||||
* @param array $whitelist optional with all valid options, default is null.
|
||||
*
|
||||
* @return boolean true if item is in whitelist, else false.
|
||||
*/
|
||||
public function check($item, $whitelist = null)
|
||||
{
|
||||
if ($whitelist !== null) {
|
||||
$this->set($whitelist);
|
||||
}
|
||||
|
||||
if (empty($item) or empty($this->whitelist)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($this->whitelist as $regexp) {
|
||||
if (preg_match("#$regexp#", $item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Resize and crop images on the fly, store generated images in a cache.
|
||||
*
|
||||
@@ -3101,12 +3481,12 @@ class CWhitelist
|
||||
*
|
||||
*/
|
||||
|
||||
$version = "v0.7.1 (2015-07-25)";
|
||||
$version = "v0.7.6 (2015-10-18)";
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Default configuration options, can be overridden in own config-file.
|
||||
* Display error message.
|
||||
*
|
||||
* @param string $msg to display.
|
||||
*
|
||||
@@ -3466,10 +3846,20 @@ $imagePath = getConfig('image_path', __DIR__ . '/img/');
|
||||
$imagePathConstraint = getConfig('image_path_constraint', true);
|
||||
$validFilename = getConfig('valid_filename', '#^[a-z0-9A-Z-/_ \.:]+$#');
|
||||
|
||||
// Dummy image feature
|
||||
$dummyEnabled = getConfig('dummy_enabled', true);
|
||||
$dummyFilename = getConfig('dummy_filename', 'dummy');
|
||||
$dummyImage = false;
|
||||
|
||||
preg_match($validFilename, $srcImage)
|
||||
or errorPage('Filename contains invalid characters.');
|
||||
|
||||
if ($allowRemote && $img->isRemoteSource($srcImage)) {
|
||||
if ($dummyEnabled && $srcImage === $dummyFilename) {
|
||||
|
||||
// Prepare to create a dummy image and use it as the source image.
|
||||
$dummyImage = true;
|
||||
|
||||
} elseif ($allowRemote && $img->isRemoteSource($srcImage)) {
|
||||
|
||||
// If source is a remote file, ignore local file checks.
|
||||
|
||||
@@ -3847,11 +4237,51 @@ 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;
|
||||
}
|
||||
|
||||
$img->setAsciiOptions($defaultOptions);
|
||||
}
|
||||
|
||||
verbose("json = $outputFormat");
|
||||
|
||||
|
||||
|
||||
@@ -3986,9 +4416,47 @@ if ($verboseFile) {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Load, process and output the image
|
||||
*/
|
||||
/**
|
||||
* Set basic options for image processing.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Prepare a dummy image and use it as source image.
|
||||
*/
|
||||
if ($dummyImage === true) {
|
||||
|
||||
$dummyDir = getConfig('dummy_dir', $cachePath. "/" . $dummyFilename);
|
||||
|
||||
is_writable($dummyDir)
|
||||
or verbose("dummy dir not writable = $dummyDir");
|
||||
|
||||
$img->setSaveFolder($dummyDir)
|
||||
->setSource($dummyFilename, $dummyDir)
|
||||
->setOptions(
|
||||
array(
|
||||
'newWidth' => $newWidth,
|
||||
'newHeight' => $newHeight,
|
||||
'bgColor' => $bgColor,
|
||||
)
|
||||
)
|
||||
->setJpegQuality($quality)
|
||||
->setPngCompression($compress)
|
||||
->createDummyImage()
|
||||
->generateFilename(null, false)
|
||||
->save(null, null, false);
|
||||
|
||||
$srcImage = $img->getTarget();
|
||||
$imagePath = null;
|
||||
|
||||
verbose("src (updated) = $srcImage");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Load, process and output the image
|
||||
*/
|
||||
$img->log("Incoming arguments: " . print_r(verbose(), 1))
|
||||
->setSaveFolder($cachePath)
|
||||
->useCache($useCache)
|
||||
|
728
webroot/imgs.php
728
webroot/imgs.php
@@ -58,6 +58,33 @@ class CHttpGet
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Build an encoded url.
|
||||
*
|
||||
* @param string $baseUrl This is the original url which will be merged.
|
||||
* @param string $merge Thse parts should be merged into the baseUrl,
|
||||
* the format is as parse_url.
|
||||
*
|
||||
* @return string $url as the modified url.
|
||||
*/
|
||||
public function buildUrl($baseUrl, $merge)
|
||||
{
|
||||
$parts = parse_url($baseUrl);
|
||||
$parts = array_merge($parts, $merge);
|
||||
|
||||
$url = $parts['scheme'];
|
||||
$url .= "://";
|
||||
$url .= $parts['host'];
|
||||
$url .= isset($parts['port'])
|
||||
? ":" . $parts['port']
|
||||
: "" ;
|
||||
$url .= $parts['path'];
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the url for the request.
|
||||
*
|
||||
@@ -67,6 +94,18 @@ class CHttpGet
|
||||
*/
|
||||
public function setUrl($url)
|
||||
{
|
||||
$parts = parse_url($url);
|
||||
|
||||
$path = "";
|
||||
if (isset($parts['path'])) {
|
||||
$pathParts = explode('/', $parts['path']);
|
||||
unset($pathParts[0]);
|
||||
foreach ($pathParts as $value) {
|
||||
$path .= "/" . rawurlencode($value);
|
||||
}
|
||||
}
|
||||
$url = $this->buildUrl($url, array("path" => $path));
|
||||
|
||||
$this->request['url'] = $url;
|
||||
return $this;
|
||||
}
|
||||
@@ -130,6 +169,8 @@ class CHttpGet
|
||||
*
|
||||
* @param boolean $debug set to true to dump headers.
|
||||
*
|
||||
* @throws Exception when curl fails to retrieve url.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function doGet($debug = false)
|
||||
@@ -152,7 +193,7 @@ class CHttpGet
|
||||
$response = curl_exec($ch);
|
||||
|
||||
if (!$response) {
|
||||
return false;
|
||||
throw new Exception("Failed retrieving url, details follows: " . curl_error($ch));
|
||||
}
|
||||
|
||||
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||
@@ -435,7 +476,7 @@ class CRemoteImage
|
||||
*/
|
||||
public function setHeaderFields()
|
||||
{
|
||||
$this->http->setHeader("User-Agent", "CImage/0.7.0 (PHP/". phpversion() . " cURL)");
|
||||
$this->http->setHeader("User-Agent", "CImage/0.7.2 (PHP/". phpversion() . " cURL)");
|
||||
$this->http->setHeader("Accept", "image/jpeg,image/png,image/gif");
|
||||
|
||||
if ($this->useCache) {
|
||||
@@ -514,6 +555,8 @@ class CRemoteImage
|
||||
*
|
||||
* @param string $url a remote url.
|
||||
*
|
||||
* @throws Exception when status code does not match 200 or 304.
|
||||
*
|
||||
* @return string as path to downloaded file or false if failed.
|
||||
*/
|
||||
public function download($url)
|
||||
@@ -546,7 +589,7 @@ class CRemoteImage
|
||||
return $this->updateCacheDetails();
|
||||
}
|
||||
|
||||
return false;
|
||||
throw new Exception("Unknown statuscode when downloading remote image: " . $this->status);
|
||||
}
|
||||
|
||||
|
||||
@@ -597,6 +640,284 @@ class CRemoteImage
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Act as whitelist (or blacklist).
|
||||
*
|
||||
*/
|
||||
class CWhitelist
|
||||
{
|
||||
/**
|
||||
* Array to contain the whitelist options.
|
||||
*/
|
||||
private $whitelist = array();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the whitelist from an array of strings, each item in the
|
||||
* whitelist should be a regexp without the surrounding / or #.
|
||||
*
|
||||
* @param array $whitelist with all valid options,
|
||||
* default is to clear the whitelist.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function set($whitelist = array())
|
||||
{
|
||||
if (!is_array($whitelist)) {
|
||||
throw new Exception("Whitelist is not of a supported format.");
|
||||
}
|
||||
|
||||
$this->whitelist = $whitelist;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check if item exists in the whitelist.
|
||||
*
|
||||
* @param string $item string to check.
|
||||
* @param array $whitelist optional with all valid options, default is null.
|
||||
*
|
||||
* @return boolean true if item is in whitelist, else false.
|
||||
*/
|
||||
public function check($item, $whitelist = null)
|
||||
{
|
||||
if ($whitelist !== null) {
|
||||
$this->set($whitelist);
|
||||
}
|
||||
|
||||
if (empty($item) or empty($this->whitelist)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($this->whitelist as $regexp) {
|
||||
if (preg_match("#$regexp#", $item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create an ASCII version of an image.
|
||||
*
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set options for processing, defaults are available.
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Resize and crop images on the fly, store generated images in a cache.
|
||||
*
|
||||
@@ -711,13 +1032,6 @@ class CImage
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The root folder of images (only used in constructor to create $pathToImage?).
|
||||
*/
|
||||
private $imageFolder;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Image filename, may include subdirectory, relative from $imageFolder
|
||||
*/
|
||||
@@ -791,6 +1105,7 @@ class CImage
|
||||
* Path to command for filter optimize, for example optipng or null.
|
||||
*/
|
||||
private $pngFilter;
|
||||
private $pngFilterCmd;
|
||||
|
||||
|
||||
|
||||
@@ -798,13 +1113,16 @@ class CImage
|
||||
* Path to command for deflate optimize, for example pngout or null.
|
||||
*/
|
||||
private $pngDeflate;
|
||||
private $pngDeflateCmd;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Path to command to optimize jpeg images, for example jpegtran or null.
|
||||
*/
|
||||
private $jpegOptimize;
|
||||
private $jpegOptimize;
|
||||
private $jpegOptimizeCmd;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@@ -880,6 +1198,56 @@ class CImage
|
||||
private $fillToFit;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option scale.
|
||||
*/
|
||||
private $scale;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option.
|
||||
*/
|
||||
private $rotateBefore;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option.
|
||||
*/
|
||||
private $rotateAfter;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option.
|
||||
*/
|
||||
private $autoRotate;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option.
|
||||
*/
|
||||
private $sharpen;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option.
|
||||
*/
|
||||
private $emboss;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* To store value for option.
|
||||
*/
|
||||
private $blur;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Used with option area to set which parts of the image to use.
|
||||
*/
|
||||
@@ -932,6 +1300,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.
|
||||
@@ -946,9 +1321,7 @@ class CImage
|
||||
public $crop_x;
|
||||
public $crop_y;
|
||||
public $filters;
|
||||
private $type; // Calculated from source image
|
||||
private $attr; // Calculated from source image
|
||||
private $useOriginal; // Use original image if possible
|
||||
|
||||
|
||||
|
||||
@@ -1005,9 +1378,7 @@ class CImage
|
||||
/**
|
||||
* Use cache or not.
|
||||
*
|
||||
* @todo clean up how $this->noCache is used in other methods.
|
||||
*
|
||||
* @param string $use true or false to use cache.
|
||||
* @param boolean $use true or false to use cache.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
@@ -1019,6 +1390,27 @@ class CImage
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create and save a dummy image. Use dimensions as stated in
|
||||
* $this->newWidth, or $width or default to 100 (same for height.
|
||||
*
|
||||
* @param integer $width use specified width for image dimension.
|
||||
* @param integer $height use specified width for image dimension.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function createDummyImage($width = null, $height = null)
|
||||
{
|
||||
$this->newWidth = $this->newWidth ?: $width ?: 100;
|
||||
$this->newHeight = $this->newHeight ?: $height ?: 100;
|
||||
|
||||
$this->image = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Allow or disallow remote image download.
|
||||
*
|
||||
@@ -1169,16 +1561,18 @@ class CImage
|
||||
|
||||
|
||||
/**
|
||||
* Set src file.
|
||||
* Set source file to use as image source.
|
||||
*
|
||||
* @param string $src of image.
|
||||
* @param string $dir as base directory where images are.
|
||||
* @param string $dir as optional base directory where images are.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSource($src, $dir = null)
|
||||
{
|
||||
if (!isset($src)) {
|
||||
$this->imageSrc = null;
|
||||
$this->pathToImage = null;
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -1192,9 +1586,9 @@ class CImage
|
||||
$src = basename($src);
|
||||
}
|
||||
|
||||
$this->imageSrc = ltrim($src, '/');
|
||||
$this->imageFolder = rtrim($dir, '/');
|
||||
$this->pathToImage = $this->imageFolder . '/' . $this->imageSrc;
|
||||
$this->imageSrc = ltrim($src, '/');
|
||||
$imageFolder = rtrim($dir, '/');
|
||||
$this->pathToImage = $imageFolder . '/' . $this->imageSrc;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -1205,23 +1599,23 @@ class CImage
|
||||
* Set target file.
|
||||
*
|
||||
* @param string $src of target image.
|
||||
* @param string $dir as base directory where images are stored.
|
||||
* @param string $dir as optional base directory where images are stored.
|
||||
* Uses $this->saveFolder if null.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setTarget($src = null, $dir = null)
|
||||
{
|
||||
if (!(isset($src) && isset($dir))) {
|
||||
if (!isset($src)) {
|
||||
$this->cacheFileName = null;
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->saveFolder = $dir;
|
||||
$this->cacheFileName = $dir . '/' . $src;
|
||||
if (isset($dir)) {
|
||||
$this->saveFolder = rtrim($dir, '/');
|
||||
}
|
||||
|
||||
/* Allow readonly cache
|
||||
is_writable($this->saveFolder)
|
||||
or $this->raiseError('Target directory is not writable.');
|
||||
*/
|
||||
$this->cacheFileName = $this->saveFolder . '/' . $src;
|
||||
|
||||
// Sanitize filename
|
||||
$this->cacheFileName = preg_replace('/^a-zA-Z0-9\.-_/', '', $this->cacheFileName);
|
||||
@@ -1232,6 +1626,18 @@ class CImage
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get filename of target file.
|
||||
*
|
||||
* @return Boolean|String as filename of target or false if not set.
|
||||
*/
|
||||
public function getTarget()
|
||||
{
|
||||
return $this->cacheFileName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set options to use when processing image.
|
||||
*
|
||||
@@ -1279,11 +1685,6 @@ class CImage
|
||||
// Output format
|
||||
'outputFormat' => null,
|
||||
'dpr' => 1,
|
||||
|
||||
// Options for saving
|
||||
//'quality' => null,
|
||||
//'compress' => null,
|
||||
//'saveAs' => null,
|
||||
);
|
||||
|
||||
// Convert crop settings from string to array
|
||||
@@ -1777,13 +2178,15 @@ class CImage
|
||||
/**
|
||||
* Generate filename to save file in cache.
|
||||
*
|
||||
* @param string $base as basepath for storing file.
|
||||
* @param string $base as optional basepath for storing file.
|
||||
* @param boolean $useSubdir use or skip the subdir part when creating the
|
||||
* filename.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function generateFilename($base)
|
||||
public function generateFilename($base = null, $useSubdir = true)
|
||||
{
|
||||
$parts = pathinfo($this->pathToImage);
|
||||
$filename = basename($this->pathToImage);
|
||||
$cropToFit = $this->cropToFit ? '_cf' : null;
|
||||
$fillToFit = $this->fillToFit ? '_ff' : null;
|
||||
$crop_x = $this->crop_x ? "_x{$this->crop_x}" : null;
|
||||
@@ -1812,7 +2215,7 @@ class CImage
|
||||
if (is_array($filter)) {
|
||||
$filters .= "_f{$filter['id']}";
|
||||
for ($i=1; $i<=$filter['argc']; $i++) {
|
||||
$filters .= ":".$filter["arg{$i}"];
|
||||
$filters .= "-".$filter["arg{$i}"];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1825,16 +2228,6 @@ class CImage
|
||||
|
||||
$autoRotate = $this->autoRotate ? 'ar' : null;
|
||||
|
||||
$this->extension = isset($this->extension)
|
||||
? $this->extension
|
||||
: (isset($parts['extension'])
|
||||
? $parts['extension']
|
||||
: null);
|
||||
|
||||
$extension = empty($this->extension)
|
||||
? null
|
||||
: "." . $this->extension;
|
||||
|
||||
$optimize = $this->jpegOptimize ? 'o' : null;
|
||||
$optimize .= $this->pngFilter ? 'f' : null;
|
||||
$optimize .= $this->pngDeflate ? 'd' : null;
|
||||
@@ -1849,14 +2242,20 @@ class CImage
|
||||
$upscale = '_nu';
|
||||
}
|
||||
|
||||
$subdir = str_replace('/', '-', dirname($this->imageSrc));
|
||||
$subdir = ($subdir == '.') ? '_.' : $subdir;
|
||||
$file = $subdir . '_' . $parts['filename'] . '_' . $width . '_'
|
||||
$subdir = null;
|
||||
if ($useSubdir === true) {
|
||||
$subdir = str_replace('/', '-', dirname($this->imageSrc));
|
||||
$subdir = ($subdir == '.') ? '_.' : $subdir;
|
||||
$subdir .= '_';
|
||||
}
|
||||
|
||||
$file = $subdir . $filename . '_' . $width . '_'
|
||||
. $height . $offset . $crop . $cropToFit . $fillToFit
|
||||
. $crop_x . $crop_y . $upscale
|
||||
. $quality . $filters . $sharpen . $emboss . $blur . $palette . $optimize
|
||||
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor . $convolve
|
||||
. $extension;
|
||||
. $quality . $filters . $sharpen . $emboss . $blur . $palette
|
||||
. $optimize . $compress
|
||||
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor
|
||||
. $convolve;
|
||||
|
||||
return $this->setTarget($file, $base);
|
||||
}
|
||||
@@ -2624,7 +3023,10 @@ class CImage
|
||||
imagealphablending($img, false);
|
||||
imagesavealpha($img, true);
|
||||
|
||||
$index = imagecolortransparent($this->image);
|
||||
$index = $this->image
|
||||
? imagecolortransparent($this->image)
|
||||
: -1;
|
||||
|
||||
if ($index != -1) {
|
||||
|
||||
imagealphablending($img, true);
|
||||
@@ -2697,17 +3099,23 @@ class CImage
|
||||
/**
|
||||
* Save image.
|
||||
*
|
||||
* @param string $src as target filename.
|
||||
* @param string $base as base directory where to store images.
|
||||
* @param string $src as target filename.
|
||||
* @param string $base as base directory where to store images.
|
||||
* @param boolean $overwrite or not, default to always overwrite file.
|
||||
*
|
||||
* @return $this or false if no folder is set.
|
||||
*/
|
||||
public function save($src = null, $base = null)
|
||||
public function save($src = null, $base = null, $overwrite = true)
|
||||
{
|
||||
if (isset($src)) {
|
||||
$this->setTarget($src, $base);
|
||||
}
|
||||
|
||||
if ($overwrite === false && is_file($this->cacheFileName)) {
|
||||
$this->Log("Not overwriting file since its already exists and \$overwrite if false.");
|
||||
return;
|
||||
}
|
||||
|
||||
is_writable($this->saveFolder)
|
||||
or $this->raiseError('Target directory is not writable.');
|
||||
|
||||
@@ -2848,6 +3256,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");
|
||||
@@ -2939,6 +3351,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.
|
||||
*
|
||||
@@ -3028,70 +3472,6 @@ EOD;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Act as whitelist (or blacklist).
|
||||
*
|
||||
*/
|
||||
class CWhitelist
|
||||
{
|
||||
/**
|
||||
* Array to contain the whitelist options.
|
||||
*/
|
||||
private $whitelist = array();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the whitelist from an array of strings, each item in the
|
||||
* whitelist should be a regexp without the surrounding / or #.
|
||||
*
|
||||
* @param array $whitelist with all valid options,
|
||||
* default is to clear the whitelist.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function set($whitelist = array())
|
||||
{
|
||||
if (!is_array($whitelist)) {
|
||||
throw new Exception("Whitelist is not of a supported format.");
|
||||
}
|
||||
|
||||
$this->whitelist = $whitelist;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check if item exists in the whitelist.
|
||||
*
|
||||
* @param string $item string to check.
|
||||
* @param array $whitelist optional with all valid options, default is null.
|
||||
*
|
||||
* @return boolean true if item is in whitelist, else false.
|
||||
*/
|
||||
public function check($item, $whitelist = null)
|
||||
{
|
||||
if ($whitelist !== null) {
|
||||
$this->set($whitelist);
|
||||
}
|
||||
|
||||
if (empty($item) or empty($this->whitelist)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($this->whitelist as $regexp) {
|
||||
if (preg_match("#$regexp#", $item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Resize and crop images on the fly, store generated images in a cache.
|
||||
*
|
||||
@@ -3101,12 +3481,12 @@ class CWhitelist
|
||||
*
|
||||
*/
|
||||
|
||||
$version = "v0.7.1 (2015-07-25)";
|
||||
$version = "v0.7.6 (2015-10-18)";
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Default configuration options, can be overridden in own config-file.
|
||||
* Display error message.
|
||||
*
|
||||
* @param string $msg to display.
|
||||
*
|
||||
@@ -3466,10 +3846,20 @@ $imagePath = getConfig('image_path', __DIR__ . '/img/');
|
||||
$imagePathConstraint = getConfig('image_path_constraint', true);
|
||||
$validFilename = getConfig('valid_filename', '#^[a-z0-9A-Z-/_ \.:]+$#');
|
||||
|
||||
// Dummy image feature
|
||||
$dummyEnabled = getConfig('dummy_enabled', true);
|
||||
$dummyFilename = getConfig('dummy_filename', 'dummy');
|
||||
$dummyImage = false;
|
||||
|
||||
preg_match($validFilename, $srcImage)
|
||||
or errorPage('Filename contains invalid characters.');
|
||||
|
||||
if ($allowRemote && $img->isRemoteSource($srcImage)) {
|
||||
if ($dummyEnabled && $srcImage === $dummyFilename) {
|
||||
|
||||
// Prepare to create a dummy image and use it as the source image.
|
||||
$dummyImage = true;
|
||||
|
||||
} elseif ($allowRemote && $img->isRemoteSource($srcImage)) {
|
||||
|
||||
// If source is a remote file, ignore local file checks.
|
||||
|
||||
@@ -3847,11 +4237,51 @@ 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;
|
||||
}
|
||||
|
||||
$img->setAsciiOptions($defaultOptions);
|
||||
}
|
||||
|
||||
verbose("json = $outputFormat");
|
||||
|
||||
|
||||
|
||||
@@ -3986,9 +4416,47 @@ if ($verboseFile) {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Load, process and output the image
|
||||
*/
|
||||
/**
|
||||
* Set basic options for image processing.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Prepare a dummy image and use it as source image.
|
||||
*/
|
||||
if ($dummyImage === true) {
|
||||
|
||||
$dummyDir = getConfig('dummy_dir', $cachePath. "/" . $dummyFilename);
|
||||
|
||||
is_writable($dummyDir)
|
||||
or verbose("dummy dir not writable = $dummyDir");
|
||||
|
||||
$img->setSaveFolder($dummyDir)
|
||||
->setSource($dummyFilename, $dummyDir)
|
||||
->setOptions(
|
||||
array(
|
||||
'newWidth' => $newWidth,
|
||||
'newHeight' => $newHeight,
|
||||
'bgColor' => $bgColor,
|
||||
)
|
||||
)
|
||||
->setJpegQuality($quality)
|
||||
->setPngCompression($compress)
|
||||
->createDummyImage()
|
||||
->generateFilename(null, false)
|
||||
->save(null, null, false);
|
||||
|
||||
$srcImage = $img->getTarget();
|
||||
$imagePath = null;
|
||||
|
||||
verbose("src (updated) = $srcImage");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Load, process and output the image
|
||||
*/
|
||||
$img->log("Incoming arguments: " . print_r(verbose(), 1))
|
||||
->setSaveFolder($cachePath)
|
||||
->useCache($useCache)
|
||||
|
36
webroot/test/test_issue101-dummy.php
Normal file
36
webroot/test/test_issue101-dummy.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
// Include config for all testcases
|
||||
include __DIR__ . "/config.php";
|
||||
|
||||
|
||||
|
||||
// The title of the test case
|
||||
$title = "Testing issue 100 - Dummy images";
|
||||
|
||||
|
||||
|
||||
// Provide a short description of the testcase.
|
||||
$description = "Create dummy images.";
|
||||
|
||||
|
||||
|
||||
// Use these images in the test
|
||||
$images = array(
|
||||
'dummy',
|
||||
);
|
||||
|
||||
|
||||
|
||||
// For each image, apply these testcases
|
||||
$testcase = array(
|
||||
'&nc&so',
|
||||
'&nc&width=300',
|
||||
'&nc&height=300',
|
||||
'&nc&width=300&height=300',
|
||||
'&nc&bgc=006600',
|
||||
);
|
||||
|
||||
|
||||
|
||||
// Apply testcases and present results
|
||||
include __DIR__ . "/template.php";
|
Reference in New Issue
Block a user