1
0
mirror of https://github.com/mosbth/cimage.git synced 2025-08-29 18:39:53 +02:00

Compare commits

..

29 Commits

Author SHA1 Message Date
Mikael Roos
c2b037af0d preparing to release v0.7.0-rc-1 2015-02-10 22:45:20 +01:00
Mikael Roos
889dba1ddb Always use password, setting in img_config.php, fix #78. 2015-02-10 22:41:24 +01:00
Mikael Roos
0baea7c346 adding transparent images for test 2015-02-09 08:03:31 +01:00
Mikael Roos
ab4e8a6fae Resize gif keeping transparency #81. 2015-02-09 00:43:38 +01:00
Mikael Roos
641d67d7a0 Resize gif keeping transparency #81. 2015-02-09 00:42:49 +01:00
Mikael Roos
aa009510be Resize gif keeping transparency #81. 2015-02-09 00:40:55 +01:00
Mikael Roos
9348141e65 rename 2015-02-09 00:37:25 +01:00
Mikael Roos
800dcbc248 rename 2015-02-08 19:53:34 +01:00
Mikael Roos
7b18030580 replacing with other testimage 2015-02-08 19:52:51 +01:00
Mikael Roos
e5738c02b1 adding animated gif 2015-02-08 19:52:20 +01:00
Mikael Roos
6478915f3c adding testimage for gif animation 2015-02-08 19:20:10 +01:00
Mikael Roos
ba58ce80c0 adding testimage png transparent 2015-02-08 19:19:42 +01:00
Mikael Roos
d4d645a00e adding transparent gif for test 2015-02-08 19:04:02 +01:00
Mikael Roos
011148b0e8 correcting mode-setting in config 2015-02-02 12:43:55 +01:00
Mikael Roos
eb0fc69036 correcting mode-setting in config 2015-02-02 12:43:01 +01:00
Mikael Roos
c012cb2537 testing before release v0.7.0 2015-02-02 12:39:58 +01:00
Mikael Roos
16a7a3dad5 * Now returns statuscode 500 when something fails #55.
* Three different modes: strict, production, development #44.
* Three files for all-in-one `imgs.php`, `imgp.php`, `imgd.php` #73.
2015-01-29 21:16:32 +01:00
Mikael Roos
bc4e04c3cb change name of all-in-one-file to imgs.php #73 2015-01-28 19:52:10 +01:00
Mikael Roos
3452ea1908 Add all code into one single script #73 2015-01-27 22:40:28 +01:00
Mikael Roos
5e08e5ed80 Enable in config to disallow hotlinking/leeching #46 2015-01-19 00:00:54 +01:00
Mikael Roos
4fae208c4c alias now requires password to work. alias filename is without extension #47. 2015-01-17 19:16:39 +01:00
Mikael Roos
f87dc2967f adding support for alias #47 2015-01-15 23:29:18 +01:00
Mikael Roos
c35587c7e2 create caache directory for remote download if it does not exists #43 2015-01-14 21:00:08 +01:00
Mikael Roos
81e70b7acd Introduced default values for almost all confguration options #72 2015-01-14 20:47:48 +01:00
Mikael Roos
8e9a3b68f0 ready for test of remote images #43 2015-01-14 19:33:35 +01:00
Mikael Roos
61afe445f1 ready for test of remote images #43 2015-01-14 19:32:01 +01:00
Mikael Roos
be98ae8979 ready for merge #43 2015-01-14 19:28:52 +01:00
Mikael Roos
f9704a4fbc remote download #43 2015-01-10 20:17:12 +01:00
Mikael Roos
cae7a49d21 adding class for remote access 2014-12-23 10:46:00 +01:00
17 changed files with 13454 additions and 399 deletions

240
CHttpGet.php Normal file
View File

@@ -0,0 +1,240 @@
<?php
/**
* Get a image from a remote server using HTTP GET and If-Modified-Since.
*
*/
class CHttpGet
{
private $request = array();
private $response = array();
/**
* Constructor
*
*/
public function __construct()
{
$this->request['header'] = array();
}
/**
* Set the url for the request.
*
* @param string $url
*
* @return $this
*/
public function setUrl($url)
{
$this->request['url'] = $url;
return $this;
}
/**
* Set custom header field for the request.
*
* @param string $field
* @param string $value
*
* @return $this
*/
public function setHeader($field, $value)
{
$this->request['header'][] = "$field: $value";
return $this;
}
/**
* Set header fields for the request.
*
* @param string $field
* @param string $value
*
* @return $this
*/
public function parseHeader()
{
$header = explode("\r\n", rtrim($this->response['headerRaw'], "\r\n"));
$output = array();
if ('HTTP' === substr($header[0], 0, 4)) {
list($output['version'], $output['status']) = explode(' ', $header[0]);
unset($header[0]);
}
foreach ($header as $entry) {
$pos = strpos($entry, ':');
$output[trim(substr($entry, 0, $pos))] = trim(substr($entry, $pos + 1));
}
$this->response['header'] = $output;
return $this;
}
/**
* Perform the request.
*
* @param boolean $debug set to true to dump headers.
*
* @return boolean
*/
public function doGet($debug = false)
{
$options = array(
CURLOPT_URL => $this->request['url'],
CURLOPT_HEADER => 1,
CURLOPT_HTTPHEADER => $this->request['header'],
CURLOPT_AUTOREFERER => true,
CURLOPT_RETURNTRANSFER => true,
CURLINFO_HEADER_OUT => $debug,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_TIMEOUT => 5,
);
$ch = curl_init();
curl_setopt_array($ch, $options);
$response = curl_exec($ch);
if (!$response) {
return false;
}
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$this->response['headerRaw'] = substr($response, 0, $headerSize);
$this->response['body'] = substr($response, $headerSize);
$this->parseHeader();
if ($debug) {
$info = curl_getinfo($ch);
echo "Request header<br><pre>", var_dump($info['request_header']), "</pre>";
echo "Response header (raw)<br><pre>", var_dump($this->response['headerRaw']), "</pre>";
echo "Response header (parsed)<br><pre>", var_dump($this->response['header']), "</pre>";
}
curl_close($ch);
return true;
}
/**
* Get HTTP code of response.
*
* @return integer as HTTP status code or null if not available.
*/
public function getStatus()
{
return isset($this->response['header']['status'])
? (int) $this->response['header']['status']
: null;
}
/**
* Get file modification time of response.
*
* @return int as timestamp.
*/
public function getLastModified()
{
return isset($this->response['header']['Last-Modified'])
? strtotime($this->response['header']['Last-Modified'])
: null;
}
/**
* Get content type.
*
* @return string as the content type or null if not existing or invalid.
*/
public function getContentType()
{
$type = isset($this->response['header']['Content-Type'])
? $this->response['header']['Content-Type']
: null;
return preg_match('#[a-z]+/[a-z]+#', $type)
? $type
: null;
}
/**
* Get file modification time of response.
*
* @param mixed $default as default value (int seconds) if date is
* missing in response header.
*
* @return int as timestamp or $default if Date is missing in
* response header.
*/
public function getDate($default = false)
{
return isset($this->response['header']['Date'])
? strtotime($this->response['header']['Date'])
: $default;
}
/**
* Get max age of cachable item.
*
* @param mixed $default as default value if date is missing in response
* header.
*
* @return int as timestamp or false if not available.
*/
public function getMaxAge($default = false)
{
$cacheControl = isset($this->response['header']['Cache-Control'])
? $this->response['header']['Cache-Control']
: null;
$maxAge = null;
if ($cacheControl) {
// max-age=2592000
$part = explode('=', $cacheControl);
$maxAge = ($part[0] == "max-age")
? (int) $part[1]
: null;
}
if ($maxAge) {
return $maxAge;
}
$expire = isset($this->response['header']['Expires'])
? strtotime($this->response['header']['Expires'])
: null;
return $expire ? $expire : $default;
}
/**
* Get body of response.
*
* @return string as body.
*/
public function getBody()
{
return $this->response['body'];
}
}

View File

@@ -2,9 +2,9 @@
/** /**
* Resize and crop images on the fly, store generated images in a cache. * Resize and crop images on the fly, store generated images in a cache.
* *
* @author Mikael Roos mos@dbwebb.se * @author Mikael Roos mos@dbwebb.se
* @example http://dbwebb.se/opensource/cimage * @example http://dbwebb.se/opensource/cimage
* @link https://github.com/mosbth/cimage * @link https://github.com/mosbth/cimage
*/ */
class CImage class CImage
{ {
@@ -17,7 +17,7 @@ class CImage
const PNG_RGB_PALETTE = 3; const PNG_RGB_PALETTE = 3;
const PNG_GREYSCALE_ALPHA = 4; const PNG_GREYSCALE_ALPHA = 4;
const PNG_RGB_ALPHA = 6; const PNG_RGB_ALPHA = 6;
/** /**
@@ -224,7 +224,7 @@ class CImage
private $newHeight; private $newHeight;
private $newHeightOrig; // Save original value private $newHeightOrig; // Save original value
/** /**
* Change target height & width when different dpr, dpr 2 means double image dimensions. * Change target height & width when different dpr, dpr 2 means double image dimensions.
*/ */
@@ -250,13 +250,13 @@ class CImage
* String with details on how to do image convolution. String * String with details on how to do image convolution. String
* should map a key in the $convolvs array or be a string of * should map a key in the $convolvs array or be a string of
* 11 float values separated by comma. The first nine builds * 11 float values separated by comma. The first nine builds
* up the matrix, then divisor and last offset. * up the matrix, then divisor and last offset.
*/ */
private $convolve; private $convolve;
/** /**
* Custom convolution expressions, matrix 3x3, divisor and offset. * Custom convolution expressions, matrix 3x3, divisor and offset.
*/ */
private $convolves = array( private $convolves = array(
'lighten' => '0,0,0, 0,12,0, 0,0,0, 9, 0', 'lighten' => '0,0,0, 0,12,0, 0,0,0, 9, 0',
@@ -276,30 +276,51 @@ class CImage
/** /**
* Resize strategy to fill extra area with background color. * Resize strategy to fill extra area with background color.
* True or false. * True or false.
*/ */
private $fillToFit; private $fillToFit;
/** /**
* Used with option area to set which parts of the image to use. * Used with option area to set which parts of the image to use.
*/ */
private $offset; private $offset;
/** /**
* Calculate target dimension for image when using fill-to-fit resize strategy. * Calculate target dimension for image when using fill-to-fit resize strategy.
*/ */
private $fillWidth; private $fillWidth;
private $fillHeight; private $fillHeight;
/**
* Allow remote file download, default is to disallow remote file download.
*/
private $allowRemote = false;
/**
* Pattern to recognize a remote file.
*/
//private $remotePattern = '#^[http|https]://#';
private $remotePattern = '#^https?://#';
/**
* Use the cache if true, set to false to ignore the cached file.
*/
private $useCache = true;
/** /**
* Properties, the class is mutable and the method setOptions() * Properties, the class is mutable and the method setOptions()
* decides (partly) what properties are created. * decides (partly) what properties are created.
* *
* @todo Clean up these and check if and how they are used * @todo Clean up these and check if and how they are used
*/ */
@@ -313,7 +334,6 @@ class CImage
public $filters; public $filters;
private $type; // Calculated from source image private $type; // Calculated from source image
private $attr; // Calculated from source image private $attr; // Calculated from source image
private $useCache; // Use the cache if true, set to false to ignore the cached file.
private $useOriginal; // Use original image if possible private $useOriginal; // Use original image if possible
@@ -338,7 +358,8 @@ class CImage
/** /**
* Set verbose mode. * Set verbose mode.
* *
* @param boolean $mode true or false to enable and disable versbose mode, default is true. * @param boolean $mode true or false to enable and disable verbose mode,
* default is true.
* *
* @return $this * @return $this
*/ */
@@ -347,8 +368,81 @@ class CImage
$this->verbose = $mode; $this->verbose = $mode;
return $this; return $this;
} }
/**
* Set save folder, base folder for saving cache files.
*
* @todo clean up how $this->saveFolder is used in other methods.
*
* @param string $path where to store cached files.
*
* @return $this
*/
public function setSaveFolder($path)
{
$this->saveFolder = $path;
return $this;
}
/**
* Use cache or not.
*
* @todo clean up how $this->noCache is used in other methods.
*
* @param string $use true or false to use cache.
*
* @return $this
*/
public function useCache($use = true)
{
$this->useCache = $use;
return $this;
}
/**
* Allow or disallow remote image download.
*
* @param boolean $allow true or false to enable and disable.
* @param string $pattern to use to detect if its a remote file.
*
* @return $this
*/
public function setRemoteDownload($allow, $pattern = null)
{
$this->allowRemote = $allow;
$this->remotePattern = $pattern ? $pattern : $this->remotePattern;
$this->log("Set remote download to: "
. ($this->allowRemote ? "true" : "false")
. " using pattern "
. $this->remotePattern);
return $this;
}
/**
* Check if the image resource is a remote file or not.
*
* @param string $src check if src is remote.
*
* @return boolean true if $src is a remote file, else false.
*/
public function isRemoteSource($src)
{
$remote = preg_match($this->remotePattern, $src);
$this->log("Detected remote image: " . ($remote ? "true" : "false"));
return $remote;
}
/** /**
* Check if file extension is valid as a file extension. * Check if file extension is valid as a file extension.
@@ -366,9 +460,46 @@ class CImage
return $this; return $this;
} }
/**
* Download a remote image and return path to its local copy.
*
* @param string $src remote path to image.
*
* @return string as path to downloaded remote source.
*/
public function downloadRemoteSource($src)
{
$remote = new CRemoteImage();
$cache = $this->saveFolder . "/remote/";
if (!is_dir($cache)) {
if (!is_writable($this->saveFolder)) {
throw new Exception("Can not create remote cache, cachefolder not writable.");
}
mkdir($cache);
$this->log("The remote cache does not exists, creating it.");
}
if (!is_writable($cache)) {
$this->log("The remote cache is not writable.");
}
$remote->setCache($cache);
$remote->useCache($this->useCache);
$src = $remote->download($src);
$this->log("Remote HTTP status: " . $remote->getStatus());
$this->log("Remote item has local cached file: $src");
$this->log("Remote details on cache:" . print_r($remote->getDetails(), true));
return $src;
}
/** /**
* Set src file. * Set src file.
* *
@@ -381,7 +512,14 @@ class CImage
{ {
if (!isset($src)) { if (!isset($src)) {
return $this; return $this;
} else if (!isset($dir)) { }
if ($this->allowRemote && $this->isRemoteSource($src)) {
$src = $this->downloadRemoteSource($src);
$dir = null;
}
if (!isset($dir)) {
$dir = dirname($src); $dir = dirname($src);
$src = basename($src); $src = basename($src);
} }
@@ -391,14 +529,14 @@ class CImage
$this->pathToImage = $this->imageFolder . '/' . $this->imageSrc; $this->pathToImage = $this->imageFolder . '/' . $this->imageSrc;
$this->fileExtension = strtolower(pathinfo($this->pathToImage, PATHINFO_EXTENSION)); $this->fileExtension = strtolower(pathinfo($this->pathToImage, PATHINFO_EXTENSION));
//$this->extension = $this->fileExtension; //$this->extension = $this->fileExtension;
$this->checkFileExtension($this->fileExtension); $this->checkFileExtension($this->fileExtension);
return $this; return $this;
} }
/** /**
* Set target file. * Set target file.
* *
@@ -424,12 +562,12 @@ class CImage
// Sanitize filename // Sanitize filename
$this->cacheFileName = preg_replace('/^a-zA-Z0-9\.-_/', '', $this->cacheFileName); $this->cacheFileName = preg_replace('/^a-zA-Z0-9\.-_/', '', $this->cacheFileName);
$this->log("The cache file name is: " . $this->cacheFileName); $this->log("The cache file name is: " . $this->cacheFileName);
return $this; return $this;
} }
/** /**
* Set options to use when processing image. * Set options to use when processing image.
* *
@@ -517,7 +655,7 @@ class CImage
$filter["arg{$i}"] = $parts[$i]; $filter["arg{$i}"] = $parts[$i];
} else { } else {
throw new Exception( throw new Exception(
'Missing arg to filter, review how many arguments are needed at 'Missing arg to filter, review how many arguments are needed at
http://php.net/manual/en/function.imagefilter.php' http://php.net/manual/en/function.imagefilter.php'
); );
} }
@@ -553,7 +691,7 @@ class CImage
* @param string $name the name of the filter. * @param string $name the name of the filter.
* *
* @return array with filter settings * @return array with filter settings
* @throws Exception * @throws Exception
*/ */
private function mapFilter($name) private function mapFilter($name)
{ {
@@ -578,8 +716,8 @@ class CImage
throw new Exception('No such filter.'); throw new Exception('No such filter.');
} }
} }
/** /**
* Load image details from original image file. * Load image details from original image file.
@@ -612,8 +750,8 @@ class CImage
/** /**
* Init new width and height and do some sanity checks on constraints, before any * Init new width and height and do some sanity checks on constraints, before any
* processing can be done. * processing can be done.
* *
* @return $this * @return $this
* @throws Exception * @throws Exception
@@ -746,12 +884,12 @@ class CImage
// Crop-to-fit and both new width and height are set. // Crop-to-fit and both new width and height are set.
if (($this->cropToFit || $this->fillToFit) && isset($this->newWidth) && isset($this->newHeight)) { if (($this->cropToFit || $this->fillToFit) && isset($this->newWidth) && isset($this->newHeight)) {
// Use newWidth and newHeigh as width/height, image should fit in box. // Use newWidth and newHeigh as width/height, image should fit in box.
$this->log("Use newWidth and newHeigh as width/height, image should fit in box."); $this->log("Use newWidth and newHeigh as width/height, image should fit in box.");
} elseif (isset($this->newWidth) && isset($this->newHeight)) { } elseif (isset($this->newWidth) && isset($this->newHeight)) {
// Both new width and height are set. // Both new width and height are set.
// Use newWidth and newHeigh as max width/height, image should not be larger. // Use newWidth and newHeigh as max width/height, image should not be larger.
$ratioWidth = $width / $this->newWidth; $ratioWidth = $width / $this->newWidth;
@@ -760,23 +898,23 @@ class CImage
$this->newWidth = round($width / $ratio); $this->newWidth = round($width / $ratio);
$this->newHeight = round($height / $ratio); $this->newHeight = round($height / $ratio);
$this->log("New width and height was set."); $this->log("New width and height was set.");
} elseif (isset($this->newWidth)) { } elseif (isset($this->newWidth)) {
// Use new width as max-width // Use new width as max-width
$factor = (float)$this->newWidth / (float)$width; $factor = (float)$this->newWidth / (float)$width;
$this->newHeight = round($factor * $height); $this->newHeight = round($factor * $height);
$this->log("New width was set."); $this->log("New width was set.");
} elseif (isset($this->newHeight)) { } elseif (isset($this->newHeight)) {
// Use new height as max-hight // Use new height as max-hight
$factor = (float)$this->newHeight / (float)$height; $factor = (float)$this->newHeight / (float)$height;
$this->newWidth = round($factor * $width); $this->newWidth = round($factor * $width);
$this->log("New height was set."); $this->log("New height was set.");
} }
// Get image dimensions for pre-resize image. // Get image dimensions for pre-resize image.
if ($this->cropToFit || $this->fillToFit) { if ($this->cropToFit || $this->fillToFit) {
@@ -785,7 +923,7 @@ class CImage
$ratioHeight = $height / $this->newHeight; $ratioHeight = $height / $this->newHeight;
if ($this->cropToFit) { if ($this->cropToFit) {
// Use newWidth and newHeigh as defined width/height, // Use newWidth and newHeigh as defined width/height,
// image should fit the area. // image should fit the area.
$this->log("Crop to fit."); $this->log("Crop to fit.");
@@ -793,9 +931,9 @@ class CImage
$this->cropWidth = round($width / $ratio); $this->cropWidth = round($width / $ratio);
$this->cropHeight = round($height / $ratio); $this->cropHeight = round($height / $ratio);
$this->log("Crop width, height, ratio: $this->cropWidth x $this->cropHeight ($ratio)."); $this->log("Crop width, height, ratio: $this->cropWidth x $this->cropHeight ($ratio).");
} else if ($this->fillToFit) { } else if ($this->fillToFit) {
// Use newWidth and newHeigh as defined width/height, // Use newWidth and newHeigh as defined width/height,
// image should fit the area. // image should fit the area.
$this->log("Fill to fit."); $this->log("Fill to fit.");
@@ -834,7 +972,7 @@ class CImage
/** /**
* Re-calculate image dimensions when original image dimension has changed. * Re-calculate image dimensions when original image dimension has changed.
* *
* @return $this * @return $this
*/ */
public function reCalculateDimensions() public function reCalculateDimensions()
{ {
@@ -857,7 +995,7 @@ class CImage
* *
* @param string $saveas extension to save image as * @param string $saveas extension to save image as
* *
* @return $this * @return $this
*/ */
public function setSaveAsExtension($saveAs = null) public function setSaveAsExtension($saveAs = null)
{ {
@@ -879,7 +1017,7 @@ class CImage
* Set JPEG quality to use when saving image * Set JPEG quality to use when saving image
* *
* @param int $quality as the quality to set. * @param int $quality as the quality to set.
* *
* @return $this * @return $this
*/ */
public function setJpegQuality($quality = null) public function setJpegQuality($quality = null)
@@ -906,7 +1044,7 @@ class CImage
* Set PNG compressen algorithm to use when saving image * Set PNG compressen algorithm to use when saving image
* *
* @param int $compress as the algorithm to use. * @param int $compress as the algorithm to use.
* *
* @return $this * @return $this
*/ */
public function setPngCompression($compress = null) public function setPngCompression($compress = null)
@@ -967,7 +1105,7 @@ class CImage
return $this; return $this;
} }
/** /**
* Generate filename to save file in cache. * Generate filename to save file in cache.
@@ -1000,7 +1138,7 @@ class CImage
$crop = $this->crop $crop = $this->crop
? '_c' . $this->crop['width'] . '-' . $this->crop['height'] . '-' . $this->crop['start_x'] . '-' . $this->crop['start_y'] ? '_c' . $this->crop['width'] . '-' . $this->crop['height'] . '-' . $this->crop['start_x'] . '-' . $this->crop['start_y']
: null; : null;
$filters = null; $filters = null;
if (isset($this->filters)) { if (isset($this->filters)) {
foreach ($this->filters as $filter) { foreach ($this->filters as $filter) {
@@ -1017,7 +1155,7 @@ class CImage
$emboss = $this->emboss ? 'e' : null; $emboss = $this->emboss ? 'e' : null;
$blur = $this->blur ? 'b' : null; $blur = $this->blur ? 'b' : null;
$palette = $this->palette ? 'p' : null; $palette = $this->palette ? 'p' : null;
$autoRotate = $this->autoRotate ? 'ar' : null; $autoRotate = $this->autoRotate ? 'ar' : null;
$this->extension = isset($this->extension) $this->extension = isset($this->extension)
@@ -1058,7 +1196,7 @@ class CImage
/** /**
* Use cached version of image, if possible. * Use cached version of image, if possible.
* *
* @param boolean $useCache is default true, set to false to avoid using cached object. * @param boolean $useCache is default true, set to false to avoid using cached object.
* *
* @return $this * @return $this
@@ -1068,7 +1206,7 @@ class CImage
if ($useCache && is_readable($this->cacheFileName)) { if ($useCache && is_readable($this->cacheFileName)) {
$fileTime = filemtime($this->pathToImage); $fileTime = filemtime($this->pathToImage);
$cacheTime = filemtime($this->cacheFileName); $cacheTime = filemtime($this->cacheFileName);
if ($fileTime <= $cacheTime) { if ($fileTime <= $cacheTime) {
if ($this->useCache) { if ($this->useCache) {
if ($this->verbose) { if ($this->verbose) {
@@ -1090,7 +1228,7 @@ class CImage
} }
/** /**
* Error message when failing to load somehow corrupt image. * Error message when failing to load somehow corrupt image.
* *
@@ -1107,11 +1245,11 @@ class CImage
case 'jpeg': case 'jpeg':
$this->image = imagecreatefromjpeg($this->pathToImage); $this->image = imagecreatefromjpeg($this->pathToImage);
break; break;
case 'gif': case 'gif':
$this->image = imagecreatefromgif($this->pathToImage); $this->image = imagecreatefromgif($this->pathToImage);
break; break;
case 'png': case 'png':
$this->image = imagecreatefrompng($this->pathToImage); $this->image = imagecreatefrompng($this->pathToImage);
break; break;
@@ -1145,19 +1283,19 @@ class CImage
$this->image = @imagecreatefromjpeg($this->pathToImage); $this->image = @imagecreatefromjpeg($this->pathToImage);
$this->image or $this->failedToLoad(); $this->image or $this->failedToLoad();
break; break;
case 'gif': case 'gif':
$this->image = @imagecreatefromgif($this->pathToImage); $this->image = @imagecreatefromgif($this->pathToImage);
$this->image or $this->failedToLoad(); $this->image or $this->failedToLoad();
break; break;
case 'png': case 'png':
$this->image = @imagecreatefrompng($this->pathToImage); $this->image = @imagecreatefrompng($this->pathToImage);
$this->image or $this->failedToLoad(); $this->image or $this->failedToLoad();
$type = $this->getPngType(); $type = $this->getPngType();
$hasFewColors = imagecolorstotal($this->image); $hasFewColors = imagecolorstotal($this->image);
if ($type == self::PNG_RGB_PALETTE || ($hasFewColors > 0 && $hasFewColors <= 256)) { if ($type == self::PNG_RGB_PALETTE || ($hasFewColors > 0 && $hasFewColors <= 256)) {
if ($this->verbose) { if ($this->verbose) {
$this->log("Handle this image as a palette image."); $this->log("Handle this image as a palette image.");
@@ -1175,6 +1313,8 @@ class CImage
$this->log("imageistruecolor() : " . (imageistruecolor($this->image) ? 'true' : 'false')); $this->log("imageistruecolor() : " . (imageistruecolor($this->image) ? 'true' : 'false'));
$this->log("imagecolorstotal() : " . imagecolorstotal($this->image)); $this->log("imagecolorstotal() : " . imagecolorstotal($this->image));
$this->log("Number of colors in image = " . $this->colorsTotal($this->image)); $this->log("Number of colors in image = " . $this->colorsTotal($this->image));
$index = imagecolortransparent($this->image);
$this->log("Detected transparent color = " . ($index > 0 ? implode(", ", imagecolorsforindex($this->image, $index)) : "NONE") . " at index = $index");
} }
return $this; return $this;
@@ -1193,7 +1333,7 @@ class CImage
$pngType = ord(file_get_contents($this->pathToImage, false, null, 25, 1)); $pngType = ord(file_get_contents($this->pathToImage, false, null, 25, 1));
switch ($pngType) { switch ($pngType) {
case self::PNG_GREYSCALE: case self::PNG_GREYSCALE:
$this->log("PNG is type 0, Greyscale."); $this->log("PNG is type 0, Greyscale.");
break; break;
@@ -1209,7 +1349,7 @@ class CImage
case self::PNG_GREYSCALE_ALPHA: case self::PNG_GREYSCALE_ALPHA:
$this->Log("PNG is type 4, Greyscale with alpha channel"); $this->Log("PNG is type 4, Greyscale with alpha channel");
break; break;
case self::PNG_RGB_ALPHA: case self::PNG_RGB_ALPHA:
$this->Log("PNG is type 6, RGB with alpha channel (PNG 32-bit)"); $this->Log("PNG is type 6, RGB with alpha channel (PNG 32-bit)");
break; break;
@@ -1223,12 +1363,12 @@ class CImage
/** /**
* Calculate number of colors in an image. * Calculate number of colors in an image.
* *
* @param resource $im the image. * @param resource $im the image.
* *
* @return int * @return int
*/ */
private function colorsTotal($im) private function colorsTotal($im)
{ {
@@ -1304,7 +1444,7 @@ class CImage
// Only use a specified area of the image, $this->offset is defining the area to use // Only use a specified area of the image, $this->offset is defining the area to use
if (isset($this->offset)) { if (isset($this->offset)) {
$this->log("Offset for area to use, cropping it width={$this->offset['width']}, height={$this->offset['height']}, start_x={$this->offset['left']}, start_y={$this->offset['top']}"); $this->log("Offset for area to use, cropping it width={$this->offset['width']}, height={$this->offset['height']}, start_x={$this->offset['left']}, start_y={$this->offset['top']}");
$img = $this->CreateImageKeepTransparency($this->offset['width'], $this->offset['height']); $img = $this->CreateImageKeepTransparency($this->offset['width'], $this->offset['height']);
imagecopy($img, $this->image, 0, 0, $this->offset['left'], $this->offset['top'], $this->offset['width'], $this->offset['height']); imagecopy($img, $this->image, 0, 0, $this->offset['left'], $this->offset['top'], $this->offset['width'], $this->offset['height']);
@@ -1312,7 +1452,7 @@ class CImage
$this->width = $this->offset['width']; $this->width = $this->offset['width'];
$this->height = $this->offset['height']; $this->height = $this->offset['height'];
} }
if ($this->crop) { if ($this->crop) {
// Do as crop, take only part of image // Do as crop, take only part of image
@@ -1329,15 +1469,15 @@ class CImage
// likely to be more readable code. // likely to be more readable code.
// The code is more or leass equal in below crop-to-fit, fill-to-fit and stretch // The code is more or leass equal in below crop-to-fit, fill-to-fit and stretch
} }
if ($this->cropToFit) { if ($this->cropToFit) {
// Resize by crop to fit // Resize by crop to fit
$this->log("Resizing using strategy - Crop to fit"); $this->log("Resizing using strategy - Crop to fit");
if (!$this->upscale && ($this->width < $this->newWidth || $this->height < $this->newHeight)) { if (!$this->upscale && ($this->width < $this->newWidth || $this->height < $this->newHeight)) {
$this->log("Resizing - smaller image, do not upscale."); $this->log("Resizing - smaller image, do not upscale.");
$cropX = round(($this->cropWidth/2) - ($this->newWidth/2)); $cropX = round(($this->cropWidth/2) - ($this->newWidth/2));
$cropY = round(($this->cropHeight/2) - ($this->newHeight/2)); $cropY = round(($this->cropHeight/2) - ($this->newHeight/2));
@@ -1347,7 +1487,7 @@ class CImage
if ($this->newWidth > $this->width) { if ($this->newWidth > $this->width) {
$posX = round(($this->newWidth - $this->width) / 2); $posX = round(($this->newWidth - $this->width) / 2);
} }
if ($this->newHeight > $this->height) { if ($this->newHeight > $this->height) {
$posY = round(($this->newHeight - $this->height) / 2); $posY = round(($this->newHeight - $this->height) / 2);
} }
@@ -1366,9 +1506,9 @@ class CImage
$this->image = $imageResized; $this->image = $imageResized;
$this->width = $this->newWidth; $this->width = $this->newWidth;
$this->height = $this->newHeight; $this->height = $this->newHeight;
} else if ($this->fillToFit) { } else if ($this->fillToFit) {
// Resize by fill to fit // Resize by fill to fit
$this->log("Resizing using strategy - Fill to fit"); $this->log("Resizing using strategy - Fill to fit");
@@ -1388,13 +1528,13 @@ class CImage
if (!$this->upscale if (!$this->upscale
&& ($this->width < $this->newWidth || $this->height < $this->newHeight) && ($this->width < $this->newWidth || $this->height < $this->newHeight)
) { ) {
$this->log("Resizing - smaller image, do not upscale."); $this->log("Resizing - smaller image, do not upscale.");
$posX = round(($this->fillWidth - $this->width) / 2); $posX = round(($this->fillWidth - $this->width) / 2);
$posY = round(($this->fillHeight - $this->height) / 2); $posY = round(($this->fillHeight - $this->height) / 2);
$imageResized = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight); $imageResized = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight);
imagecopy($imageResized, $this->image, $posX, $posY, 0, 0, $this->fillWidth, $this->fillHeight); imagecopy($imageResized, $this->image, $posX, $posY, 0, 0, $this->fillWidth, $this->fillHeight);
} else { } else {
$imgPreFill = $this->CreateImageKeepTransparency($this->fillWidth, $this->fillHeight); $imgPreFill = $this->CreateImageKeepTransparency($this->fillWidth, $this->fillHeight);
$imageResized = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight); $imageResized = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight);
@@ -1405,9 +1545,9 @@ class CImage
$this->image = $imageResized; $this->image = $imageResized;
$this->width = $this->newWidth; $this->width = $this->newWidth;
$this->height = $this->newHeight; $this->height = $this->newHeight;
} else if (!($this->newWidth == $this->width && $this->newHeight == $this->height)) { } else if (!($this->newWidth == $this->width && $this->newHeight == $this->height)) {
// Resize it // Resize it
$this->log("Resizing, new height and/or width"); $this->log("Resizing, new height and/or width");
@@ -1473,24 +1613,24 @@ class CImage
// Apply filters // Apply filters
if (isset($this->filters) && is_array($this->filters)) { if (isset($this->filters) && is_array($this->filters)) {
foreach ($this->filters as $filter) { foreach ($this->filters as $filter) {
$this->log("Applying filter {$filter['type']}."); $this->log("Applying filter {$filter['type']}.");
switch ($filter['argc']) { switch ($filter['argc']) {
case 0: case 0:
imagefilter($this->image, $filter['type']); imagefilter($this->image, $filter['type']);
break; break;
case 1: case 1:
imagefilter($this->image, $filter['type'], $filter['arg1']); imagefilter($this->image, $filter['type'], $filter['arg1']);
break; break;
case 2: case 2:
imagefilter($this->image, $filter['type'], $filter['arg1'], $filter['arg2']); imagefilter($this->image, $filter['type'], $filter['arg1'], $filter['arg2']);
break; break;
case 3: case 3:
imagefilter($this->image, $filter['type'], $filter['arg1'], $filter['arg2'], $filter['arg3']); imagefilter($this->image, $filter['type'], $filter['arg1'], $filter['arg2'], $filter['arg3']);
break; break;
@@ -1535,11 +1675,11 @@ class CImage
return $this; return $this;
} }
/** /**
* Rotate image using angle. * Rotate image using angle.
* *
* @param float $angle to rotate image. * @param float $angle to rotate image.
* @param int $anglebgColor to fill image with if needed. * @param int $anglebgColor to fill image with if needed.
* *
@@ -1551,7 +1691,7 @@ class CImage
$color = $this->getBackgroundColor(); $color = $this->getBackgroundColor();
$this->image = imagerotate($this->image, $angle, $color); $this->image = imagerotate($this->image, $angle, $color);
$this->width = imagesx($this->image); $this->width = imagesx($this->image);
$this->height = imagesy($this->image); $this->height = imagesy($this->image);
@@ -1564,7 +1704,7 @@ class CImage
/** /**
* Rotate image using information in EXIF. * Rotate image using information in EXIF.
* *
* @return $this * @return $this
*/ */
public function rotateExif() public function rotateExif()
@@ -1599,7 +1739,7 @@ class CImage
} else { } else {
$this->log("Autorotate ignored, no orientation in EXIF."); $this->log("Autorotate ignored, no orientation in EXIF.");
} }
return $this; return $this;
} }
@@ -1633,7 +1773,7 @@ class CImage
/** /**
* Sharpen image using image convolution. * Sharpen image using image convolution.
* *
* @return $this * @return $this
*/ */
public function sharpenImage() public function sharpenImage()
@@ -1646,7 +1786,7 @@ class CImage
/** /**
* Emboss image using image convolution. * Emboss image using image convolution.
* *
* @return $this * @return $this
*/ */
public function embossImage() public function embossImage()
@@ -1659,7 +1799,7 @@ class CImage
/** /**
* Blur image using image convolution. * Blur image using image convolution.
* *
* @return $this * @return $this
*/ */
public function blurImage() public function blurImage()
@@ -1672,7 +1812,7 @@ class CImage
/** /**
* Create convolve expression and return arguments for image convolution. * Create convolve expression and return arguments for image convolution.
* *
* @param string $expression constant string which evaluates to a list of * @param string $expression constant string which evaluates to a list of
* 11 numbers separated by komma or such a list. * 11 numbers separated by komma or such a list.
* *
@@ -1691,17 +1831,17 @@ class CImage
// Expect list of 11 numbers, split by , and build up arguments // Expect list of 11 numbers, split by , and build up arguments
if (count($part) != 11) { if (count($part) != 11) {
throw new Exception( throw new Exception(
"Missmatch in argument convolve. Expected comma-separated string with "Missmatch in argument convolve. Expected comma-separated string with
11 float values. Got $expression." 11 float values. Got $expression."
); );
} }
array_walk($part, function ($item, $key) { array_walk($part, function ($item, $key) {
if (!is_numeric($item)) { if (!is_numeric($item)) {
throw new Exception("Argument to convolve expression should be float but is not."); throw new Exception("Argument to convolve expression should be float but is not.");
} }
}); });
return array( return array(
array( array(
array($part[0], $part[1], $part[2]), array($part[0], $part[1], $part[2]),
@@ -1717,7 +1857,7 @@ class CImage
/** /**
* Add custom expressions (or overwrite existing) for image convolution. * Add custom expressions (or overwrite existing) for image convolution.
* *
* @param array $options Key value array with strings to be converted * @param array $options Key value array with strings to be converted
* to convolution expressions. * to convolution expressions.
* *
@@ -1733,7 +1873,7 @@ class CImage
/** /**
* Image convolution. * Image convolution.
* *
* @param string $options A string with 11 float separated by comma. * @param string $options A string with 11 float separated by comma.
* *
* @return $this * @return $this
@@ -1752,7 +1892,7 @@ class CImage
list($matrix, $divisor, $offset) = $this->createConvolveArguments($option); list($matrix, $divisor, $offset) = $this->createConvolveArguments($option);
imageconvolution($this->image, $matrix, $divisor, $offset); imageconvolution($this->image, $matrix, $divisor, $offset);
} }
return $this; return $this;
} }
@@ -1842,7 +1982,7 @@ class CImage
} }
} }
/** /**
* Create a image and keep transparency for png and gifs. * Create a image and keep transparency for png and gifs.
@@ -1859,7 +1999,17 @@ class CImage
imagealphablending($img, false); imagealphablending($img, false);
imagesavealpha($img, true); imagesavealpha($img, true);
if ($this->bgColorDefault) { $index = imagecolortransparent($this->image);
if ($index != -1) {
imagealphablending($img, true);
$transparent = imagecolorsforindex($this->image, $index);
$color = imagecolorallocatealpha($img, $transparent['red'], $transparent['green'], $transparent['blue'], $transparent['alpha']);
imagefill($img, 0, 0, $color);
$index = imagecolortransparent($img, $color);
$this->Log("Detected transparent color = " . implode(", ", $transparent) . " at index = $index");
} elseif ($this->bgColorDefault) {
$color = $this->getBackgroundColor($img); $color = $this->getBackgroundColor($img);
imagefill($img, 0, 0, $color); imagefill($img, 0, 0, $color);
@@ -1869,10 +2019,10 @@ class CImage
return $img; return $img;
} }
/** /**
* Set optimizing and post-processing options. * Set optimizing and post-processing options.
* *
* @param array $options with config for postprocessing with external tools. * @param array $options with config for postprocessing with external tools.
* *
@@ -1897,7 +2047,7 @@ class CImage
} else { } else {
$this->pngDeflateCmd = null; $this->pngDeflateCmd = null;
} }
return $this; return $this;
} }
@@ -1921,12 +2071,12 @@ class CImage
or $this->raiseError('Target directory is not writable.'); or $this->raiseError('Target directory is not writable.');
switch(strtolower($this->extension)) { switch(strtolower($this->extension)) {
case 'jpeg': case 'jpeg':
case 'jpg': case 'jpg':
$this->Log("Saving image as JPEG to cache using quality = {$this->quality}."); $this->Log("Saving image as JPEG to cache using quality = {$this->quality}.");
imagejpeg($this->image, $this->cacheFileName, $this->quality); imagejpeg($this->image, $this->cacheFileName, $this->quality);
// Use JPEG optimize if defined // Use JPEG optimize if defined
if ($this->jpegOptimizeCmd) { if ($this->jpegOptimizeCmd) {
if ($this->verbose) { if ($this->verbose) {
@@ -1942,10 +2092,8 @@ class CImage
break; break;
case 'gif': case 'gif':
if ($this->saveFolder) { $this->Log("Saving image as GIF to cache.");
$this->Log("Saving image as GIF to cache."); imagegif($this->image, $this->cacheFileName);
imagegif($this->image, $this->cacheFileName);
}
break; break;
case 'png': case 'png':
@@ -1955,7 +2103,7 @@ class CImage
imagealphablending($this->image, false); imagealphablending($this->image, false);
imagesavealpha($this->image, true); imagesavealpha($this->image, true);
imagepng($this->image, $this->cacheFileName, $this->compress); imagepng($this->image, $this->cacheFileName, $this->compress);
// Use external program to filter PNG, if defined // Use external program to filter PNG, if defined
if ($this->pngFilterCmd) { if ($this->pngFilterCmd) {
if ($this->verbose) { if ($this->verbose) {
@@ -1994,6 +2142,42 @@ class CImage
$this->log("imageistruecolor() : " . (imageistruecolor($this->image) ? 'true' : 'false')); $this->log("imageistruecolor() : " . (imageistruecolor($this->image) ? 'true' : 'false'));
$this->log("imagecolorstotal() : " . imagecolorstotal($this->image)); $this->log("imagecolorstotal() : " . imagecolorstotal($this->image));
$this->log("Number of colors in image = " . $this->ColorsTotal($this->image)); $this->log("Number of colors in image = " . $this->ColorsTotal($this->image));
$index = imagecolortransparent($this->image);
$this->log("Detected transparent color = " . ($index > 0 ? implode(", ", imagecolorsforindex($this->image, $index)) : "NONE") . " at index = $index");
}
return $this;
}
/**
* Create a hard link, as an alias, to the cached file.
*
* @param string $alias where to store the link,
* filename without extension.
*
* @return $this
*/
public function linkToCacheFile($alias)
{
if ($alias === null) {
$this->log("Ignore creating alias.");
return $this;
}
$alias = $alias . "." . $this->extension;
if (is_readable($alias)) {
unlink($alias);
}
$res = link($this->cacheFileName, $alias);
if ($res) {
$this->log("Created an alias as: $alias");
} else {
$this->log("Failed to create the alias: $alias");
} }
return $this; return $this;
@@ -2039,17 +2223,17 @@ class CImage
} }
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $lastModified) { if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $lastModified) {
if ($this->verbose) { if ($this->verbose) {
$this->log("304 not modified"); $this->log("304 not modified");
$this->verboseOutput(); $this->verboseOutput();
exit; exit;
} }
header("HTTP/1.0 304 Not Modified"); header("HTTP/1.0 304 Not Modified");
} else { } else {
if ($this->verbose) { if ($this->verbose) {
$this->log("Last modified: " . $gmdate . " GMT"); $this->log("Last modified: " . $gmdate . " GMT");
$this->verboseOutput(); $this->verboseOutput();
@@ -2064,7 +2248,7 @@ class CImage
header('Content-type: ' . $mime); header('Content-type: ' . $mime);
readfile($file); readfile($file);
} }
exit; exit;
} }
@@ -2108,7 +2292,7 @@ class CImage
if (defined("JSON_PRETTY_PRINT") && defined("JSON_UNESCAPED_SLASHES")) { if (defined("JSON_PRETTY_PRINT") && defined("JSON_UNESCAPED_SLASHES")) {
$options = JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES; $options = JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES;
} }
return json_encode($details, $options); return json_encode($details, $options);
} }
@@ -2129,9 +2313,9 @@ class CImage
return $this; return $this;
} }
/** /**
* Do verbose output and print out the log and the actual images. * Do verbose output and print out the log and the actual images.
* *
@@ -2146,7 +2330,7 @@ class CImage
$included = get_included_files(); $included = get_included_files();
$this->log("Included files: " . count($included)); $this->log("Included files: " . count($included));
foreach ($this->log as $val) { foreach ($this->log as $val) {
if (is_array($val)) { if (is_array($val)) {
foreach ($val as $val1) { foreach ($val as $val1) {
@@ -2175,7 +2359,7 @@ EOD;
* *
* @param string $message the error message to display. * @param string $message the error message to display.
* *
* @return void * @return void
* @throws Exception * @throws Exception
*/ */
private function raiseError($message) private function raiseError($message)

351
CRemoteImage.php Normal file
View File

@@ -0,0 +1,351 @@
<?php
/**
* Get a image from a remote server using HTTP GET and If-Modified-Since.
*
*/
class CRemoteImage
{
/**
* Path to cache files.
*/
private $saveFolder = null;
/**
* Use cache or not.
*/
private $useCache = true;
/**
* HTTP object to aid in download file.
*/
private $http;
/**
* Status of the HTTP request.
*/
private $status;
/**
* Defalt age for cached items 60*60*24*7.
*/
private $defaultMaxAge = 604800;
/**
* Url of downloaded item.
*/
private $url;
/**
* Base name of cache file for downloaded item.
*/
private $fileName;
/**
* Filename for json-file with details of cached item.
*/
private $fileJson;
/**
* Filename for image-file.
*/
private $fileImage;
/**
* Cache details loaded from file.
*/
private $cache;
/**
* Constructor
*
*/
public function __construct()
{
;
}
/**
* Get status of last HTTP request.
*
* @return int as status
*/
public function getStatus()
{
return $this->status;
}
/**
* Get JSON details for cache item.
*
* @return array with json details on cache.
*/
public function getDetails()
{
return $this->cache;
}
/**
* Set the path to the cache directory.
*
* @param boolean $use true to use the cache and false to ignore cache.
*
* @return $this
*/
public function setCache($path)
{
$this->saveFolder = $path;
return $this;
}
/**
* Check if cache is writable or throw exception.
*
* @return $this
*
* @throws Exception if cahce folder is not writable.
*/
public function isCacheWritable()
{
if (!is_writable($this->saveFolder)) {
throw new Exception("Cache folder is not writable for downloaded files.");
}
return $this;
}
/**
* Decide if the cache should be used or not before trying to download
* a remote file.
*
* @param boolean $use true to use the cache and false to ignore cache.
*
* @return $this
*/
public function useCache($use = true)
{
$this->useCache = $use;
return $this;
}
/**
* Translate a content type to a file extension.
*
* @param string $type a valid content type.
*
* @return string as file extension or false if no match.
*/
function contentTypeToFileExtension($type) {
$extension = array(
'image/jpeg' => 'jpg',
'image/png' => 'png',
'image/gif' => 'gif',
);
return isset($extension[$type])
? $extension[$type]
: false;
}
/**
* Set header fields.
*
* @return $this
*/
function setHeaderFields() {
$this->http->setHeader("User-Agent", "CImage/0.6 (PHP/". phpversion() . " cURL)");
$this->http->setHeader("Accept", "image/jpeg,image/png,image/gif");
if ($this->useCache) {
$this->http->setHeader("Cache-Control", "max-age=0");
} else {
$this->http->setHeader("Cache-Control", "no-cache");
$this->http->setHeader("Pragma", "no-cache");
}
}
/**
* Save downloaded resource to cache.
*
* @return string as path to saved file or false if not saved.
*/
function save() {
$this->cache = array();
$date = $this->http->getDate(time());
$maxAge = $this->http->getMaxAge($this->defaultMaxAge);
$lastModified = $this->http->getLastModified();
$type = $this->http->getContentType();
$extension = $this->contentTypeToFileExtension($type);
$this->cache['Date'] = gmdate("D, d M Y H:i:s T", $date);
$this->cache['Max-Age'] = $maxAge;
$this->cache['Content-Type'] = $type;
$this->cache['File-Extension'] = $extension;
if ($lastModified) {
$this->cache['Last-Modified'] = gmdate("D, d M Y H:i:s T", $lastModified);
}
if ($extension) {
$this->fileImage = $this->fileName . "." . $extension;
// Save only if body is a valid image
$body = $this->http->getBody();
$img = imagecreatefromstring($body);
if ($img !== false) {
file_put_contents($this->fileImage, $body);
file_put_contents($this->fileJson, json_encode($this->cache));
return $this->fileImage;
}
}
return false;
}
/**
* Got a 304 and updates cache with new age.
*
* @return string as path to cached file.
*/
function updateCacheDetails() {
$date = $this->http->getDate(time());
$maxAge = $this->http->getMaxAge($this->defaultMaxAge);
$lastModified = $this->http->getLastModified();
$this->cache['Date'] = gmdate("D, d M Y H:i:s T", $date);
$this->cache['Max-Age'] = $maxAge;
if ($lastModified) {
$this->cache['Last-Modified'] = gmdate("D, d M Y H:i:s T", $lastModified);
}
file_put_contents($this->fileJson, json_encode($this->cache));
return $this->fileImage;
}
/**
* Download a remote file and keep a cache of downloaded files.
*
* @param string $url a remote url.
*
* @return string as path to downloaded file or false if failed.
*/
function download($url) {
$this->http = new CHttpGet();
$this->url = $url;
// First check if the cache is valid and can be used
$this->loadCacheDetails();
if ($this->useCache) {
$src = $this->getCachedSource();
if ($src) {
$this->status = 1;
return $src;
}
}
// Do a HTTP request to download item
$this->setHeaderFields();
$this->http->setUrl($this->url);
$this->http->doGet();
$this->status = $this->http->getStatus();
if ($this->status === 200) {
$this->isCacheWritable();
return $this->save();
} else if ($this->status === 304) {
$this->isCacheWritable();
return $this->updateCacheDetails();
}
return false;
}
/**
* Get the path to the cached image file if the cache is valid.
*
* @return $this
*/
public function loadCacheDetails()
{
$cacheFile = str_replace(array("/", ":", "#", ".", "?"), "-", $this->url);
$this->fileName = $this->saveFolder . $cacheFile;
$this->fileJson = $this->fileName . ".json";
if (is_readable($this->fileJson)) {
$this->cache = json_decode(file_get_contents($this->fileJson), true);
}
}
/**
* Get the path to the cached image file if the cache is valid.
*
* @return string as the path ot the image file or false if no cache.
*/
public function getCachedSource()
{
$this->fileImage = $this->fileName . "." . $this->cache['File-Extension'];
$imageExists = is_readable($this->fileImage);
// Is cache valid?
$date = strtotime($this->cache['Date']);
$maxAge = $this->cache['Max-Age'];
$now = time();
if ($imageExists && $date + $maxAge > $now) {
return $this->fileImage;
}
// Prepare for a 304 if available
if ($imageExists && isset($this->cache['Last-Modified'])) {
$this->http->setHeader("If-Modified-Since", $this->cache['Last-Modified']);
}
return false;
}
}

218
README.md
View File

@@ -12,20 +12,20 @@ This software is free and open source, licensed according MIT.
Use case Use case
-------------------------------------- --------------------------------------
You got an image from your friend who took it with the iPhone and you want to put it up on your website. You got an image from your friend who took it with the iPhone and you want to put it up on your website.
<img src="http://dbwebb.se/kod-exempel/cimage/webroot/img.php?src=issue36/me-270.jpg&w=300" alt=""> <img src="http://dbwebb.se/kod-exempel/cimage/webroot/img.php?src=issue36/me-270.jpg&w=300" alt="">
The original image is looking like this one, scaled down to a width of 300 pixels. The original image is looking like this one, scaled down to a width of 300 pixels.
So, you need to rotate it and crop off some parts to make it intresting. So, you need to rotate it and crop off some parts to make it intresting.
To show it off, I'll autorotate the image based on its EXIF-information, I will crop it to a thumbnail of 100x100 pixels and add a filter to make it greyscale finishing up with a sharpen effect. Just for the show I'll rotate the image 25 degrees - do not ask me why. To show it off, I'll autorotate the image based on its EXIF-information, I will crop it to a thumbnail of 100x100 pixels and add a filter to make it greyscale finishing up with a sharpen effect. Just for the show I'll rotate the image 25 degrees - do not ask me why.
Lets call this *the URL-Photoshopper*. This is how the magic looks like. Lets call this *the URL-Photoshopper*. This is how the magic looks like.
`img.php?src=issue36/me-270.jpg&w=100&h=100&cf&aro&rb=-25&a=8,30,30,38&f=grayscale`<br>`&convolve=sharpen-alt` `img.php?src=issue36/me-270.jpg&w=100&h=100&cf&aro&rb=-25&a=8,30,30,38&f=grayscale`<br>`&convolve=sharpen-alt`
@@ -38,14 +38,14 @@ For myself, I use `img.php` to put up all images on my website, it gives me the
Requirements Requirements
-------------------------------------- --------------------------------------
`CImage` and `img.php` supports GIF (with transparency), JPEG and PNG (8bit transparent, 24bit semi transparent) images. It requires PHP 5.3 and PHP GD. You optionally need the EXIF extension to support auto-rotation of JPEG-images. `CImage` and `img.php` supports GIF (with transparency), JPEG and PNG (8bit transparent, 24bit semi transparent) images. It requires PHP 5.3 and PHP GD. You optionally need the EXIF extension to support auto-rotation of JPEG-images.
Installation Installation
-------------------------------------- --------------------------------------
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). 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).
I prefer cloning like this. Do switch to the latest stable version. I prefer cloning like this. Do switch to the latest stable version.
@@ -65,7 +65,7 @@ chmod 777 cache
Get going quickly Get going quickly
-------------------------------------- --------------------------------------
@@ -76,7 +76,7 @@ Try it out by pointing your browser to the test file `webroot/test/test.php`. It
###Process your first image ###Process your first image
<img src="http://dbwebb.se/kod-exempel/cimage/webroot/img.php?src=kodim04.png&amp;w=w2&amp;a=40,0,50,0" alt=''> <img src="http://dbwebb.se/kod-exempel/cimage/webroot/img.php?src=kodim04.png&amp;w=w2&amp;a=40,0,50,0" alt=''>
@@ -84,15 +84,15 @@ Try it yourself by opening up an image in your browser. Start with `webroot/img.
###What does "processing the image" involves? ###What does "processing the image" involves?
Add `&verbose` to the link to get a verbose output of what is happens during image processing. This is useful for developers or those who seek a deeper understanding on how it all works. Add `&verbose` to the link to get a verbose output of what is happens during image processing. This is useful for developers or those who seek a deeper understanding on how it all works.
###Check your system ###Check your system
Open up `webroot/check_system.php` if you need to troubleshoot or if you are uncertain if your system has the right extensions loaded. Open up `webroot/check_system.php` if you need to troubleshoot or if you are uncertain if your system has the right extensions loaded.
@@ -106,13 +106,13 @@ The programatic flow, just to get you oriented in the environment, is.
2. `img.php` reads configuration details from `img_config.php`. 2. `img.php` reads configuration details from `img_config.php`.
3. `img.php` reads and processes incoming `$_GET` arguments to prepare using `CImage`. 3. `img.php` reads and processes incoming `$_GET` arguments to prepare using `CImage`.
4. `img.php` uses `CImage`. 4. `img.php` uses `CImage`.
5. `CImage` processes and outputs the image according to how its used. 5. `CImage` processes and outputs the image according to how its used.
Read on to learn more on how to use `img.php`. Read on to learn more on how to use `img.php`.
Basic usage Basic usage
-------------------------------------- --------------------------------------
@@ -127,11 +127,11 @@ It looks like this.
<img src=http://dbwebb.se/kod-exempel/cimage/webroot/img.php?src=kodim13.png&w=w1&save-as=jpg alt=""> <img src=http://dbwebb.se/kod-exempel/cimage/webroot/img.php?src=kodim13.png&w=w1&save-as=jpg alt="">
All images are stored in a directory structure and you access them as `?src=dir1/dir2/image.png`. All images are stored in a directory structure and you access them as `?src=dir1/dir2/image.png`.
###Resize using constraints on width and height ###Resize using constraints on width and height
Create a thumbnail of the image by applying constraints on width and height, or one of them. Create a thumbnail of the image by applying constraints on width and height, or one of them.
@@ -145,7 +145,7 @@ Think of the constraints as a imaginary box where the image should fit. With `wi
###Resize to fit a certain dimension ###Resize to fit a certain dimension
Creating a thumbnail with a certain dimension of width and height, usually involves stretching or cropping the image to fit in the selected dimensions. Here is how you create a image that has the exact dimensions of 300x150 pixels, by either *stretching*, *cropping* or *fill to fit*. Creating a thumbnail with a certain dimension of width and height, usually involves stretching or cropping the image to fit in the selected dimensions. Here is how you create a image that has the exact dimensions of 300x150 pixels, by either *stretching*, *cropping* or *fill to fit*.
@@ -165,7 +165,7 @@ Fill to fit is useful when you have some image that must fit in a certain dimens
###List of parameters ###List of parameters
`img.php` supports a lot of parameters. Combine the parameters to get the desired behavior and resulting image. For example, take the original image, resize it using width, aspect-ratio and crop-to-fit, apply a sharpen effect, save the image as JPEG using quality 30. `img.php` supports a lot of parameters. Combine the parameters to get the desired behavior and resulting image. For example, take the original image, resize it using width, aspect-ratio and crop-to-fit, apply a sharpen effect, save the image as JPEG using quality 30.
@@ -173,14 +173,14 @@ Fill to fit is useful when you have some image that must fit in a certain dimens
|-----------------------------------------------------------| |-----------------------------------------------------------|
| <img src=http://dbwebb.se/kod-exempel/cimage/webroot/img.php?src=kodim13.png&w=600&aspect-ratio=4&crop-to-fit&sharpen&save-as=jpg&q=30 alt=''> | | <img src=http://dbwebb.se/kod-exempel/cimage/webroot/img.php?src=kodim13.png&w=600&aspect-ratio=4&crop-to-fit&sharpen&save-as=jpg&q=30 alt=''> |
Here is a list of all parameters that you can use together with `img.php`, grouped by its basic intent of usage. Here is a list of all parameters that you can use together with `img.php`, grouped by its basic intent of usage.
####Mandatory options and debugging ####Mandatory options and debugging
Option `src` is the only mandatory option. The other in this section is useful for debugging or deciding what version of the target image is used. Option `src` is the only mandatory option. The other in this section is useful for debugging or deciding what version of the target image is used.
| Parameter | Explained | | Parameter | Explained |
|----------------|----------------------------------------------| |----------------|----------------------------------------------|
| `src` | Source image to use, mandatory. `src=img.png` or with subdirectory `src=dir/img.png`. | | `src` | Source image to use, mandatory. `src=img.png` or with subdirectory `src=dir/img.png`. |
| `nc, no-cache` | Do not use the cached version, do all image processing and save a new image to cache. | | `nc, no-cache` | Do not use the cached version, do all image processing and save a new image to cache. |
@@ -190,11 +190,11 @@ Option `src` is the only mandatory option. The other in this section is useful f
####Options for deciding width and height of target image ####Options for deciding width and height of target image
These options are all affecting the final dimensions, width and height, of the resulting image. These options are all affecting the final dimensions, width and height, of the resulting image.
| Parameter | Explained | | Parameter | Explained |
|----------------|----------------------------------------------| |----------------|----------------------------------------------|
| `h, height` | `h=200` sets the width to be to max 200px. `h=25%` sets the height to max 25% of its original height. | | `h, height` | `h=200` sets the width to be to max 200px. `h=25%` sets the height to max 25% of its original height. |
| `w, width` | `w=200` sets the height to be max 200px. `w=100%` sets the width to max 100% of its original width. | | `w, width` | `w=200` sets the height to be max 200px. `w=100%` sets the width to max 100% of its original width. |
@@ -203,11 +203,11 @@ These options are all affecting the final dimensions, width and height, of the r
####Options for resize strategy ####Options for resize strategy
These options affect strategy to use when resizing an image into a target image that has both width and height set. These options affect strategy to use when resizing an image into a target image that has both width and height set.
| Parameter | Explained | | Parameter | Explained |
|----------------|----------------------------------------------| |----------------|----------------------------------------------|
| `nr, no-ratio, stretch` | Do *not* keep aspect ratio when resizing and using both width & height constraints. Results in stretching the image, if needed, to fit in the resulting box. | | `nr, no-ratio, stretch` | Do *not* keep aspect ratio when resizing and using both width & height constraints. Results in stretching the image, if needed, to fit in the resulting box. |
| `cf, crop-to-fit` | Set together with both `h` and `w` to make the image fit into dimensions, and crop out the rest of the image. | | `cf, crop-to-fit` | Set together with both `h` and `w` to make the image fit into dimensions, and crop out the rest of the image. |
@@ -216,32 +216,32 @@ These options affect strategy to use when resizing an image into a target image
####Options for cropping part of image ####Options for cropping part of image
These options enable to decide what part of image to crop out. These options enable to decide what part of image to crop out.
| Parameter | Explained | | Parameter | Explained |
|----------------|----------------------------------------------| |----------------|----------------------------------------------|
| `a, area` | Define the area of the image to work with. Set `area=10,10,10,10` (top,right,bottom,left) to crop out the 10% of the outermost area. It works like an offset to define the part of the image you want to process. Its an alternative of using `crop`. | | `a, area` | Define the area of the image to work with. Set `area=10,10,10,10` (top,right,bottom,left) to crop out the 10% of the outermost area. It works like an offset to define the part of the image you want to process. Its an alternative of using `crop`. |
| `c, crop` | Crops an area from the original image, set width, height, start_x and start_y to define the area to crop, for example `crop=100,100,10,10` (`crop=width,height,start_x,start_y`). Left top corner is 0, 0. You can use `left`, `right` or `center` when setting start_x. You may use `top`, `bottom` or `center` when setting start_y. | | `c, crop` | Crops an area from the original image, set width, height, start_x and start_y to define the area to crop, for example `crop=100,100,10,10` (`crop=width,height,start_x,start_y`). Left top corner is 0, 0. You can use `left`, `right` or `center` when setting start_x. You may use `top`, `bottom` or `center` when setting start_y. |
####General processing options ####General processing options
These options are general options affecting processing. These options are general options affecting processing.
| Parameter | Explained | | Parameter | Explained |
|----------------|----------------------------------------------| |----------------|----------------------------------------------|
| `bgc, bg-color` | Set the backgroundcolor to use (if its needed). Use six hex digits as `bgc=00ff00` and 8 digits when using the alpha channel, as this `bgc=00ff007f`. The alpha value can be between 00 and 7f. | | `bgc, bg-color` | Set the backgroundcolor to use (if its needed). Use six hex digits as `bgc=00ff00` and 8 digits when using the alpha channel, as this `bgc=00ff007f`. The alpha value can be between 00 and 7f. |
####Processing of image before resizing ####Processing of image before resizing
This option are executed *before* the image is resized. This option are executed *before* the image is resized.
| Parameter | Explained | | Parameter | Explained |
|----------------|----------------------------------------------| |----------------|----------------------------------------------|
| `s, scale` | Scale the image to a size proportional to a percentage of its original size, `scale=25` makes an image 25% of its original size and `size=200` doubles up the image size. Scale is applied before resizing and has no impact of the target width and height. | | `s, scale` | Scale the image to a size proportional to a percentage of its original size, `scale=25` makes an image 25% of its original size and `size=200` doubles up the image size. Scale is applied before resizing and has no impact of the target width and height. |
| `rb, rotate-before` | Rotate the image before its processed, send the angle as parameter `rb=45`. | | `rb, rotate-before` | Rotate the image before its processed, send the angle as parameter `rb=45`. |
@@ -249,7 +249,7 @@ This option are executed *before* the image is resized.
####Processing of image after resizing ####Processing of image after resizing
These options are executed *after* the image is resized. These options are executed *after* the image is resized.
@@ -267,7 +267,7 @@ These options are executed *after* the image is resized.
Documentation Documentation
-------------------------------------- --------------------------------------
Read full documentation at: Read full documentation at:
@@ -275,155 +275,7 @@ http://dbwebb.se/opensource/cimage
Revision history ```
------------------------------------- .
..: Copyright 2012-2015 by Mikael Roos (me@mikaelroos.se)
```
v0.6.1 (2015-01-08)
* Adding compare-page for comparing images. Issue #20.
* Added option `no-upscale, nu` as resizing strategy to decline upscaling of smaller images. Fix #61.
* Minor change in `CImage::resize()`, crop now does imagecopy without resamling.
* Correcting internal details for save-as and response json which indicated wrong colors. Fix #62.
* Fixed fill-to-fit that failed when using aspect-ratio. Fix #52.
* JSON returns correct values for resulting image. Fix #58.
* Corrected behaviour for skip-original. Fix #60.
v0.6 (2014-12-06)
* Rewrote and added documentation.
* Moved conolution expressesion from `img_config.php` to `CImage`.
* Minor cleaning of properties in `CImage`. Fix #23.
* Adding `webroot/htaccess` to show off how friendly urls can be created for `img.php`. Fix #45.
* Added option `fill-to-fit, ff`. Fix #38.
* Added option `shortcut, sc` to enable configuration of complex expressions. Fix #2.
* Added support for custom convolutions. Fix #49.
* Restructured testprograms. Fix #41.
* Corrected json on PHP 5.3. Fix #42.
* Improving template for tests in `webroot/tests` when testing out #40.
* Adding testcase for #40.
* Adding option `convolve` taking comma-separated list of 11 float-values, wraps and exposes `imageconvoluttion()`. #4
* Adding option `dpr, device-pixel-ratio` which defaults to 1. Set to 2 to get a twice as large image. Useful for Retina displays. Basically a shortcut to enlarge the image.
* Adding utility `cache.bash` to ease gathering stats on cache usage. #21
* Cache-directory can now be readonly and serve all cached files, still failing when need to save files. #5
* Cache now uses same file extension as original image #37.
* Can output image as json format using `json` #11.
v0.5.3 (2014-11-21)
* Support filenames of uppercase JPEG, JPG, PNG and GIF, as proposed in #37.
* Changing `CImage::output()` as proposed in #37.
* Adding security check that image filename is always below the path `image_path` as specified in `img_config.php` #37.
* Adding configuration item in `img_config.php` for setting valid characters in image filename.
* Moving `webroot/test*` into directory `webroot/test`.
* `webroot/check_system.php` now outputs if extension for exif is loaded.
* Broke API when `initDimensions()` split into two methods, new `initDimensions()` and `loadImageDetails()`.
* Added `autoRotate, aro` to auto rotate image based on EXIF information.
* Added `bgColor, bgc` to use as backgroundcolor when needing a filler color, for example rotate 45.
* Added `rotateBefore, rb` to rotate image a certain angle before processing.
* Added `rotateAfter, ra` to rotate image a certain angle after processing.
* Cleaned up code formatting, removed trailing spaces.
* Removed @ from opening images, better to display correct warning when failing #34, but put it back again.
* Setting gd.jpeg_ignore_warning to true as default #34.
* `webroot/check_system.php` now outputs version of PHP and GD.
* #32 correctly send 404 header when serving an error message.
* Trying to verify issue #29, but can not.
* Adding structure for testprograms together with, use `webroot/test_issue29.php` as sample.
* Improving code formatting.
* Moving parts of verbose output from img.php to CImage.php.
v0.5.2 (2014-04-01)
* Correcting issue #26 providing error message when not using postprocessing.
* Correcting issue #27 warning of default timezone.
* Removed default $config options in `img.php`, was not used, all configuration should be in `img_config.php`.
* Verified known bug - sharpen acts as blur in PHP 5.5.9 and 5.5.10 #28
v0.5.1 (2014-02-12)
* Display image in README-file.
* Create an empty `cache` directory as part of repo.
v0.5 (2014-02-12)
* Change constant name `CImage::PNG_QUALITY_DEFAULT` to `CImage::PNG_COMPRESSION_DEFAULT`.
* Split JPEG quality and PNG compression, `CImage->quality` and `CImage->compression`
* Changed `img.php` parameter name `d, deflate` to `co, compress`.
* Separating configuration issues from `img.php` to `img_config.php`.
* Format code according to PSR-2.
* Disabled post-processing JPEG and PNG as default.
* This version is supporting PHP 5.3, later versions will require 5.5 or later.
* Using GitHub issue tracking for feature requests and planning.
* Rewrote [the manual](http://dbwebb.se/opensource/cimage).
* Created directory `webroot` and moved some files there.
v0.4.1 (2014-01-27)
* Changed => to == on Modified-Since.
* Always send Last-Modified-Header.
* Added `htmlentities()` to verbose output.
* Fixed support for jpeg, not only jpg.
* Fixed crop whole image by setting crop=0,0,0,0
* Use negative values for crop width & height to base calulation on original width/height and withdraw selected amount.
* Correcting jpeg when setting quality.
* Removed obsolete reference to `$newName` in `CImage::__construct()` (issue 1).
v0.4 (2013-10-08)
* Improved support for pre-defined sizes.
* Adding grid column size as predefined size, c1-c24 for a 24 column grid. Configure in `img.php`.
* Corrected error on naming cache-files using subdir.
* Corrected calculation error on width & height for crop-to-fit.
* Adding effects for sharpen, emboss and blur through imageconvolution using matrixes.
* crop-to-fit, add parameter for offset x and y to enable to define which area is the, implemented as area.
* Support for resizing opaque images.
* Center of the image from which the crop is done. Improved usage of area to crop.
* Added support for % in width & height.
* Added aspect-ratio.
* Added scale.
* Quality for PNG images is now knows as deflate.
* Added palette to create images with max 256 colors.
* Added usage of all parameters to README.md
* Added documentation here http://dbwebb.se/opensource/cimage
* Adding `.gitignore`
* Re-adding `cache` directory
v0.3 (2012-10-02)
* Added crop. Can crop a area (`width`, `height`, `start_x`, `start_y`) from the original
image.
* Corrected to make the 304 Not Modified header work.
* Predefined sizes can be configured for width in `img.php`.
* Corrected to make crop work with width or height in combination with crop-to-fit.
v0.2 (2012-05-09)
* Implemented filters as in http://php.net/manual/en/function.imagefilter.php
* Changed `crop` to `crop_to_fit`, works the same way.
* Changed arguments and sends them in array.
* Added quality-setting.
* Added testcases for above.
v0.1.1 (2012-04-27)
* Corrected calculation where both width and height were set.
v0.1 (2012-04-25)
* Initial release after rewriting some older code doing the same, but not that good and flexible.
<pre>
.
..: Copyright 2012-2014 by Mikael Roos (me@mikaelroos.se)
</pre>

185
REVISION.md Normal file
View File

@@ -0,0 +1,185 @@
Revision history
=====================================
v0.7.0-rc.1 (2015-02-10)
-------------------------------------
* Always use password, setting in img_config.php, fix #78.
* Resize gif keeping transparency #81.
* Now returns statuscode 500 when something fails #55.
* Three different modes: strict, production, development #44.
* Three files for all-in-one `imgs.php`, `imgp.php`, `imgd.php` #73.
* Change name of script all-in-one to `webroot/imgs.php` #73.
* Combine all code into one singel script, `webroot/img_single.php` #73.
* Disallow hotlinking/leeching by configuration #46.
* Alias-name is without extension #47.
* Option `alias` now requires `password` to work #47.
* Support for option `password, pwd` to protect usage of `alias` and remote download.
* Added support for option `alias` that creates a link to a cached version of the image #47.
* Create cache directory for remote download if it does not exists.
* Cleaned up `img_config.php` and introduced default values for almost all options #72.
v0.6.2 (2015-01-14)
-------------------------------------
* Added support for download of remote images #43.
* Added autoloader.
v0.6.1 (2015-01-08)
-------------------------------------
* Adding compare-page for comparing images. Issue #20.
* Added option `no-upscale, nu` as resizing strategy to decline upscaling of smaller images. Fix #61.
* Minor change in `CImage::resize()`, crop now does imagecopy without resamling.
* Correcting internal details for save-as and response json which indicated wrong colors. Fix #62.
* Fixed fill-to-fit that failed when using aspect-ratio. Fix #52.
* JSON returns correct values for resulting image. Fix #58.
* Corrected behaviour for skip-original. Fix #60.
v0.6 (2014-12-06)
-------------------------------------
* Rewrote and added documentation.
* Moved conolution expressesion from `img_config.php` to `CImage`.
* Minor cleaning of properties in `CImage`. Fix #23.
* Adding `webroot/htaccess` to show off how friendly urls can be created for `img.php`. Fix #45.
* Added option `fill-to-fit, ff`. Fix #38.
* Added option `shortcut, sc` to enable configuration of complex expressions. Fix #2.
* Added support for custom convolutions. Fix #49.
* Restructured testprograms. Fix #41.
* Corrected json on PHP 5.3. Fix #42.
* Improving template for tests in `webroot/tests` when testing out #40.
* Adding testcase for #40.
* Adding option `convolve` taking comma-separated list of 11 float-values, wraps and exposes `imageconvoluttion()`. #4
* Adding option `dpr, device-pixel-ratio` which defaults to 1. Set to 2 to get a twice as large image. Useful for Retina displays. Basically a shortcut to enlarge the image.
* Adding utility `cache.bash` to ease gathering stats on cache usage. #21
* Cache-directory can now be readonly and serve all cached files, still failing when need to save files. #5
* Cache now uses same file extension as original image #37.
* Can output image as json format using `json` #11.
v0.5.3 (2014-11-21)
-------------------------------------
* Support filenames of uppercase JPEG, JPG, PNG and GIF, as proposed in #37.
* Changing `CImage::output()` as proposed in #37.
* Adding security check that image filename is always below the path `image_path` as specified in `img_config.php` #37.
* Adding configuration item in `img_config.php` for setting valid characters in image filename.
* Moving `webroot/test*` into directory `webroot/test`.
* `webroot/check_system.php` now outputs if extension for exif is loaded.
* Broke API when `initDimensions()` split into two methods, new `initDimensions()` and `loadImageDetails()`.
* Added `autoRotate, aro` to auto rotate image based on EXIF information.
* Added `bgColor, bgc` to use as backgroundcolor when needing a filler color, for example rotate 45.
* Added `rotateBefore, rb` to rotate image a certain angle before processing.
* Added `rotateAfter, ra` to rotate image a certain angle after processing.
* Cleaned up code formatting, removed trailing spaces.
* Removed @ from opening images, better to display correct warning when failing #34, but put it back again.
* Setting gd.jpeg_ignore_warning to true as default #34.
* `webroot/check_system.php` now outputs version of PHP and GD.
* #32 correctly send 404 header when serving an error message.
* Trying to verify issue #29, but can not.
* Adding structure for testprograms together with, use `webroot/test_issue29.php` as sample.
* Improving code formatting.
* Moving parts of verbose output from img.php to CImage.php.
v0.5.2 (2014-04-01)
-------------------------------------
* Correcting issue #26 providing error message when not using postprocessing.
* Correcting issue #27 warning of default timezone.
* Removed default $config options in `img.php`, was not used, all configuration should be in `img_config.php`.
* Verified known bug - sharpen acts as blur in PHP 5.5.9 and 5.5.10 #28
v0.5.1 (2014-02-12)
-------------------------------------
* Display image in README-file.
* Create an empty `cache` directory as part of repo.
v0.5 (2014-02-12)
-------------------------------------
* Change constant name `CImage::PNG_QUALITY_DEFAULT` to `CImage::PNG_COMPRESSION_DEFAULT`.
* Split JPEG quality and PNG compression, `CImage->quality` and `CImage->compression`
* Changed `img.php` parameter name `d, deflate` to `co, compress`.
* Separating configuration issues from `img.php` to `img_config.php`.
* Format code according to PSR-2.
* Disabled post-processing JPEG and PNG as default.
* This version is supporting PHP 5.3, later versions will require 5.5 or later.
* Using GitHub issue tracking for feature requests and planning.
* Rewrote [the manual](http://dbwebb.se/opensource/cimage).
* Created directory `webroot` and moved some files there.
v0.4.1 (2014-01-27)
-------------------------------------
* Changed => to == on Modified-Since.
* Always send Last-Modified-Header.
* Added `htmlentities()` to verbose output.
* Fixed support for jpeg, not only jpg.
* Fixed crop whole image by setting crop=0,0,0,0
* Use negative values for crop width & height to base calulation on original width/height and withdraw selected amount.
* Correcting jpeg when setting quality.
* Removed obsolete reference to `$newName` in `CImage::__construct()` (issue 1).
v0.4 (2013-10-08)
-------------------------------------
* Improved support for pre-defined sizes.
* Adding grid column size as predefined size, c1-c24 for a 24 column grid. Configure in `img.php`.
* Corrected error on naming cache-files using subdir.
* Corrected calculation error on width & height for crop-to-fit.
* Adding effects for sharpen, emboss and blur through imageconvolution using matrixes.
* crop-to-fit, add parameter for offset x and y to enable to define which area is the, implemented as area.
* Support for resizing opaque images.
* Center of the image from which the crop is done. Improved usage of area to crop.
* Added support for % in width & height.
* Added aspect-ratio.
* Added scale.
* Quality for PNG images is now knows as deflate.
* Added palette to create images with max 256 colors.
* Added usage of all parameters to README.md
* Added documentation here http://dbwebb.se/opensource/cimage
* Adding `.gitignore`
* Re-adding `cache` directory
v0.3 (2012-10-02)
-------------------------------------
* Added crop. Can crop a area (`width`, `height`, `start_x`, `start_y`) from the original
image.
* Corrected to make the 304 Not Modified header work.
* Predefined sizes can be configured for width in `img.php`.
* Corrected to make crop work with width or height in combination with crop-to-fit.
v0.2 (2012-05-09)
-------------------------------------
* Implemented filters as in http://php.net/manual/en/function.imagefilter.php
* Changed `crop` to `crop_to_fit`, works the same way.
* Changed arguments and sends them in array.
* Added quality-setting.
* Added testcases for above.
v0.1.1 (2012-04-27)
-------------------------------------
* Corrected calculation where both width and height were set.
v0.1 (2012-04-25)
-------------------------------------
* Initial release after rewriting some older code doing the same, but not that good and flexible.

23
autoload.php Normal file
View File

@@ -0,0 +1,23 @@
<?php
/**
* Autoloader for CImage and related class files.
*
*/
//include __DIR__ . "/../CHttpGet.php";
//include __DIR__ . "/../CRemoteImage.php";
//include __DIR__ . "/../CImage.php";
/**
* Autoloader for classes.
*
* @param string $class the fully-qualified class name.
*
* @return void
*/
spl_autoload_register(function ($class) {
//$path = CIMAGE_SOURCE_PATH . "/{$class}.php";
$path = __DIR__ . "/{$class}.php";
if(is_file($path)) {
require($path);
}
});

74
create-img-single.bash Executable file
View File

@@ -0,0 +1,74 @@
#!/bin/bash
#
# Paths and settings
#
TARGET_D="webroot/imgd.php"
TARGET_P="webroot/imgp.php"
TARGET_S="webroot/imgs.php"
NEWLINES="\n\n\n"
#
# Specify the utilities used
#
ECHO="printf"
#
# Main, start by checking basic usage
#
if [ $# -gt 0 ]
then
$ECHO "Usage: $0\n"
exit 1
fi
#
# Print out details on cache-directory
#
$ECHO "Creating '$TARGET_D', '$TARGET_P' and '$TARGET_S' by combining the following files:"
$ECHO "\n"
$ECHO "\n webroot/img_header.php"
$ECHO "\n CHttpGet.php"
$ECHO "\n CRemoteImage.php"
$ECHO "\n CImage.php"
$ECHO "\n webroot/img.php"
$ECHO "\n"
$ECHO "\n'$TARGET_D' is for development mode."
$ECHO "\n'$TARGET_P' is for production mode (default mode)."
$ECHO "\n'$TARGET_S' is for strict mode."
$ECHO "\n"
$ECHO "\nPress enter to continue. "
read answer
#
# Create the $TARGET_? files
#
cat webroot/img_header.php > $TARGET_P
cat webroot/img_header.php | sed "s|//'mode' => 'production',|'mode' => 'development',|" > $TARGET_D
cat webroot/img_header.php | sed "s|//'mode' => 'production',|'mode' => 'development',|" > $TARGET_S
$ECHO "$NEWLINES" | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
tail -n +2 CHttpGet.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 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
$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
$ECHO "$NEWLINES" | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
$ECHO "\nDone."
$ECHO "\n"
$ECHO "\n"

View File

@@ -1,9 +1,15 @@
<?php <?php
/** /**
* Resize images on the fly using CImage, configuration is made in file named. * Resize and crop images on the fly, store generated images in a cache.
*
* @author Mikael Roos mos@dbwebb.se
* @example http://dbwebb.se/opensource/cimage
* @link https://github.com/mosbth/cimage
* *
*/ */
$version = "v0.7.0-rc.1 (2015-02-10)";
/** /**
@@ -15,8 +21,16 @@
*/ */
function errorPage($msg) function errorPage($msg)
{ {
header("HTTP/1.0 404 Not Found"); global $mode;
die('img.php say 404: ' . $msg);
header("HTTP/1.0 500 Internal Server Error");
if ($mode == 'development') {
die("[img.php] $msg");
} else {
error_log("[img.php] $msg");
die("HTTP/1.0 500 Internal Server Error");
}
} }
@@ -70,6 +84,24 @@ function getDefined($key, $defined, $undefined)
/**
* Get value from config array or default if key is not set in config array.
*
* @param string $key the key in the config array.
* @param mixed $default value to be default if $key is not set in config.
*
* @return mixed value as $config[$key] or $default.
*/
function getConfig($key, $default)
{
global $config;
return isset($config[$key])
? $config[$key]
: $default;
}
/** /**
* Log when verbose mode, when used without argument it returns the result. * Log when verbose mode, when used without argument it returns the result.
* *
@@ -96,20 +128,78 @@ function verbose($msg = null)
/** /**
* Get configuration options from file. * Get configuration options from file, if the file exists, else use $config
* if its defined or create an empty $config.
*/ */
$configFile = __DIR__.'/'.basename(__FILE__, '.php').'_config.php'; $configFile = __DIR__.'/'.basename(__FILE__, '.php').'_config.php';
$config = require $configFile;
call_user_func($config['error_reporting']); if (is_file($configFile)) {
$config = require $configFile;
} else if (!isset($config)) {
$config = array();
}
/**
* verbose, v - do a verbose dump of what happens
*/
$verbose = getDefined(array('verbose', 'v'), true, false);
verbose("img.php version = $version");
/**
* Set mode as strict, production or development.
* Default is production environment.
*/
$mode = getConfig('mode', 'production');
// Settings for any mode
set_time_limit(20);
ini_set('gd.jpeg_ignore_warning', 1);
if (!extension_loaded('gd')) {
errorPage("Extension gd is nod loaded.");
}
// Specific settings for each mode
if ($mode == 'strict') {
error_reporting(0);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
$verbose = false;
} else if ($mode == 'production') {
error_reporting(-1);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
$verbose = false;
} else if ($mode == 'development') {
error_reporting(-1);
ini_set('display_errors', 1);
ini_set('log_errors', 0);
} else {
errorPage("Unknown mode: $mode");
}
verbose("mode = $mode");
verbose("error log = " . ini_get('error_log'));
/** /**
* Set default timezone if not set or if its set in the config-file. * Set default timezone if not set or if its set in the config-file.
*/ */
if (isset($config['default_timezone'])) { $defaultTimezone = getConfig('default_timezone', null);
date_default_timezone_set($config['default_timezone']);
if ($defaultTimezone) {
date_default_timezone_set($defaultTimezone);
} else if (!ini_get('default_timezone')) { } else if (!ini_get('default_timezone')) {
date_default_timezone_set('UTC'); date_default_timezone_set('UTC');
} }
@@ -117,36 +207,128 @@ if (isset($config['default_timezone'])) {
/** /**
* verbose, v - do a verbose dump of what happens * Check if passwords are configured, used and match.
* Options decide themself if they require passwords to be used.
*/ */
$verbose = getDefined(array('verbose', 'v'), true, false); $pwdConfig = getConfig('password', false);
$pwdAlways = getConfig('password_always', false);
$pwd = get(array('password', 'pwd'), null);
// Check if passwords match, if configured to use passwords
$passwordMatch = null;
if ($pwdAlways) {
$passwordMatch = ($pwdConfig === $pwd);
if (!$passwordMatch) {
errorPage("Password required and does not match or exists.");
}
} elseif ($pwdConfig && $pwd) {
$passwordMatch = ($pwdConfig === $pwd);
}
verbose("password match = $passwordMatch");
/**
* Prevent hotlinking, leeching, of images by controlling who access them
* from where.
*
*/
$allowHotlinking = getConfig('allow_hotlinking', true);
$hotlinkingWhitelist = getConfig('hotlinking_whitelist', array());
$serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null;
$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
$refererHost = parse_url($referer, PHP_URL_HOST);
if (!$allowHotlinking) {
if ($passwordMatch) {
; // Always allow when password match
} else if ($passwordMatch === false) {
errorPage("Hotlinking/leeching not allowed when password missmatch.");
} else if (!$referer) {
errorPage("Hotlinking/leeching not allowed and referer is missing.");
} else if (strcmp($serverName, $refererHost) == 0) {
; // Allow when serverName matches refererHost
} else if (!empty($hotlinkingWhitelist)) {
$allowedByWhitelist = false;
foreach ($hotlinkingWhitelist as $val) {
if (preg_match($val, $refererHost)) {
$allowedByWhitelist = true;
}
}
if (!$allowedByWhitelist) {
errorPage("Hotlinking/leeching not allowed by whitelist.");
}
} else {
errorPage("Hotlinking/leeching not allowed.");
}
}
verbose("allow_hotlinking = $allowHotlinking");
verbose("referer = $referer");
verbose("referer host = $refererHost");
/**
* Get the source files.
*/
$autoloader = getConfig('autoloader', false);
$cimageClass = getConfig('cimage_class', false);
if ($autoloader) {
require $autoloader;
} else if ($cimageClass) {
require $cimageClass;
}
/** /**
* Create the class for the image. * Create the class for the image.
*/ */
require $config['cimage_class'];
$img = new CImage(); $img = new CImage();
$img->setVerbose($verbose); $img->setVerbose($verbose);
/**
* Allow or disallow remote download of images from other servers.
* Passwords apply if used.
*
*/
$allowRemote = getConfig('remote_allow', false);
if ($allowRemote && $passwordMatch !== false) {
$pattern = getConfig('remote_pattern', null);
$img->setRemoteDownload($allowRemote, $pattern);
}
/** /**
* shortcut, sc - extend arguments with a constant value, defined * shortcut, sc - extend arguments with a constant value, defined
* in config-file. * in config-file.
*/ */
$shortcut = get(array('shortcut', 'sc'), null); $shortcut = get(array('shortcut', 'sc'), null);
$shortcutConfig = getConfig('shortcut', array(
'sepia' => "&f=grayscale&f0=brightness,-10&f1=contrast,-20&f2=colorize,120,60,0,0&sharpen",
));
verbose("shortcut = $shortcut"); verbose("shortcut = $shortcut");
if (isset($shortcut) if (isset($shortcut)
&& isset($config['shortcut']) && isset($shortcutConfig[$shortcut])) {
&& isset($config['shortcut'][$shortcut])) {
parse_str($shortcutConfig[$shortcut], $get);
parse_str($config['shortcut'][$shortcut], $get); verbose("shortcut-constant = {$shortcutConfig[$shortcut]}");
verbose("shortcut-constant = {$config['shortcut'][$shortcut]}");
$_GET = array_merge($_GET, $get); $_GET = array_merge($_GET, $get);
} }
@@ -158,43 +340,76 @@ if (isset($shortcut)
$srcImage = get('src') $srcImage = get('src')
or errorPage('Must set src-attribute.'); or errorPage('Must set src-attribute.');
// Check for valid/invalid characters // Check for valid/invalid characters
preg_match($config['valid_filename'], $srcImage) $imagePath = getConfig('image_path', __DIR__ . '/img/');
$imagePathConstraint = getConfig('image_path_constraint', true);
$validFilename = getConfig('valid_filename', '#^[a-z0-9A-Z-/_\.:]+$#');
preg_match($validFilename, $srcImage)
or errorPage('Filename contains invalid characters.'); or errorPage('Filename contains invalid characters.');
if ($allowRemote && $img->isRemoteSource($srcImage)) {
// Check that the image is a file below the directory 'image_path'. // If source is a remote file, ignore local file checks.
if ($config['image_path_constraint']) {
} else if ($imagePathConstraint) {
$pathToImage = realpath($config['image_path'] . $srcImage);
$imageDir = realpath($config['image_path']); // Check that the image is a file below the directory 'image_path'.
$pathToImage = realpath($imagePath . $srcImage);
$imageDir = realpath($imagePath);
is_file($pathToImage) is_file($pathToImage)
or errorPage( or errorPage(
'Source image is not a valid file, check the filename and that a 'Source image is not a valid file, check the filename and that a
matching file exists on the filesystem.' matching file exists on the filesystem.'
); );
substr_compare($imageDir, $pathToImage, 0, strlen($imageDir)) == 0 substr_compare($imageDir, $pathToImage, 0, strlen($imageDir)) == 0
or errorPage( or errorPage(
'Security constraint: Source image is not below the directory "image_path" 'Security constraint: Source image is not below the directory "image_path"
as specified in the config file img_config.php.' as specified in the config file img_config.php.'
); );
} }
verbose("src = $srcImage"); verbose("src = $srcImage");
/**
* Manage size constants from config file, use constants to replace values
* for width and height.
*/
$sizeConstant = getConfig('size_constant', function () {
// Set sizes to map constant to value, easier to use with width or height
$sizes = array(
'w1' => 613,
'w2' => 630,
);
// Add grid column width, useful for use as predefined size for width (or height).
$gridColumnWidth = 30;
$gridGutterWidth = 10;
$gridColumns = 24;
for ($i = 1; $i <= $gridColumns; $i++) {
$sizes['c' . $i] = ($gridColumnWidth + $gridGutterWidth) * $i - $gridGutterWidth;
}
return $sizes;
});
$sizes = call_user_func($sizeConstant);
/** /**
* width, w - set target width, affecting the resulting image width, height and resize options * width, w - set target width, affecting the resulting image width, height and resize options
*/ */
$newWidth = get(array('width', 'w')); $newWidth = get(array('width', 'w'));
$maxWidth = getConfig('max_width', 2000);
// Check to replace predefined size // Check to replace predefined size
$sizes = call_user_func($config['size_constant']);
if (isset($sizes[$newWidth])) { if (isset($sizes[$newWidth])) {
$newWidth = $sizes[$newWidth]; $newWidth = $sizes[$newWidth];
} }
@@ -205,7 +420,7 @@ if ($newWidth[strlen($newWidth)-1] == '%') {
or errorPage('Width % not numeric.'); or errorPage('Width % not numeric.');
} else { } else {
is_null($newWidth) is_null($newWidth)
or ($newWidth > 10 && $newWidth <= $config['max_width']) or ($newWidth > 10 && $newWidth <= $maxWidth)
or errorPage('Width out of range.'); or errorPage('Width out of range.');
} }
@@ -217,6 +432,7 @@ verbose("new width = $newWidth");
* height, h - set target height, affecting the resulting image width, height and resize options * height, h - set target height, affecting the resulting image width, height and resize options
*/ */
$newHeight = get(array('height', 'h')); $newHeight = get(array('height', 'h'));
$maxHeight = getConfig('max_height', 2000);
// Check to replace predefined size // Check to replace predefined size
if (isset($sizes[$newHeight])) { if (isset($sizes[$newHeight])) {
@@ -229,7 +445,7 @@ if ($newHeight[strlen($newHeight)-1] == '%') {
or errorPage('Height % out of range.'); or errorPage('Height % out of range.');
} else { } else {
is_null($newHeight) is_null($newHeight)
or ($newHeight > 10 && $newHeight <= $config['max_height']) or ($newHeight > 10 && $newHeight <= $maxHeight)
or errorPage('Hight out of range.'); or errorPage('Hight out of range.');
} }
@@ -240,10 +456,21 @@ verbose("new height = $newHeight");
/** /**
* aspect-ratio, ar - affecting the resulting image width, height and resize options * aspect-ratio, ar - affecting the resulting image width, height and resize options
*/ */
$aspectRatio = get(array('aspect-ratio', 'ar')); $aspectRatio = get(array('aspect-ratio', 'ar'));
$aspectRatioConstant = getConfig('aspect_ratio_constant', function () {
return array(
'3:1' => 3/1,
'3:2' => 3/2,
'4:3' => 4/3,
'8:5' => 8/5,
'16:10' => 16/10,
'16:9' => 16/9,
'golden' => 1.618,
);
});
// Check to replace predefined aspect ratio // Check to replace predefined aspect ratio
$aspectRatios = call_user_func($config['aspect_ratio_constant']); $aspectRatios = call_user_func($aspectRatioConstant);
$negateAspectRatio = ($aspectRatio[0] == '!') ? true : false; $negateAspectRatio = ($aspectRatio[0] == '!') ? true : false;
$aspectRatio = $negateAspectRatio ? substr($aspectRatio, 1) : $aspectRatio; $aspectRatio = $negateAspectRatio ? substr($aspectRatio, 1) : $aspectRatio;
@@ -275,9 +502,11 @@ verbose("crop to fit = $cropToFit");
/** /**
* Set default background color from config file. * Set default background color from config file.
*/ */
if (isset($config['background_color'])) { $backgroundColor = getConfig('background_color', null);
$img->setDefaultBackgroundColor($config['background_color']);
verbose("Using default background_color = {$config['background_color']}"); if ($backgroundColor) {
$img->setDefaultBackgroundColor($backgroundColor);
verbose("Using default background_color = $backgroundColor");
} }
@@ -374,7 +603,7 @@ verbose("quality = $quality");
*/ */
$compress = get(array('compress', 'co')); $compress = get(array('compress', 'co'));
is_null($compress) is_null($compress)
or ($compress > 0 and $compress <= 9) or ($compress > 0 and $compress <= 9)
or errorPage('Compress out of range'); or errorPage('Compress out of range');
@@ -518,11 +747,12 @@ verbose("dpr = $dpr");
* convolve - image convolution as in http://php.net/manual/en/function.imageconvolution.php * convolve - image convolution as in http://php.net/manual/en/function.imageconvolution.php
*/ */
$convolve = get('convolve', null); $convolve = get('convolve', null);
$convolutionConstant = getConfig('convolution_constant', array());
// Check if the convolve is matching an existing constant // Check if the convolve is matching an existing constant
if ($convolve && isset($config['convolution_constant'])) { if ($convolve && isset($convolutionConstant)) {
$img->addConvolveExpressions($config['convolution_constant']); $img->addConvolveExpressions($convolutionConstant);
verbose("convolve constant = " . print_r($config['convolution_constant'], 1)); verbose("convolve constant = " . print_r($convolutionConstant, 1));
} }
verbose("convolve = " . print_r($convolve, 1)); verbose("convolve = " . print_r($convolve, 1));
@@ -538,6 +768,50 @@ verbose("upscale = $upscale");
/**
* Get details for post processing
*/
$postProcessing = getConfig('postprocessing', array(
'png_filter' => false,
'png_filter_cmd' => '/usr/local/bin/optipng -q',
'png_deflate' => false,
'png_deflate_cmd' => '/usr/local/bin/pngout -q',
'jpeg_optimize' => false,
'jpeg_optimize_cmd' => '/usr/local/bin/jpegtran -copy none -optimize',
));
/**
* alias - Save resulting image to another alias name.
* Password always apply, must be defined.
*/
$alias = get('alias', null);
$aliasPath = getConfig('alias_path', null);
$validAliasname = getConfig('valid_aliasname', '#^[a-z0-9A-Z-_]+$#');
$aliasTarget = null;
if ($alias && $aliasPath && $passwordMatch) {
$aliasTarget = $aliasPath . $alias;
$useCache = false;
is_writable($aliasPath)
or errorPage("Directory for alias is not writable.");
preg_match($validAliasname, $alias)
or errorPage('Filename for alias contains invalid characters. Do not add extension.');
} else if ($alias) {
errorPage('Alias is not enabled in the config file or password not matching.');
}
verbose("alias = $alias");
/** /**
* Display image if verbose mode * Display image if verbose mode
*/ */
@@ -570,11 +844,20 @@ EOD;
/**
* Get the cachepath from config.
*/
$cachePath = getConfig('cache_path', __DIR__ . '/../cache/');
/** /**
* Load, process and output the image * Load, process and output the image
*/ */
$img->log("Incoming arguments: " . print_r(verbose(), 1)) $img->log("Incoming arguments: " . print_r(verbose(), 1))
->setSource($srcImage, $config['image_path']) ->setSaveFolder($cachePath)
->useCache($useCache)
->setSource($srcImage, $imagePath)
->setOptions( ->setOptions(
array( array(
// Options for calculate dimensions // Options for calculate dimensions
@@ -591,7 +874,7 @@ $img->log("Incoming arguments: " . print_r(verbose(), 1))
// Pre-processing, before resizing is done // Pre-processing, before resizing is done
'scale' => $scale, 'scale' => $scale,
'rotateBefore' => $rotateBefore, 'rotateBefore' => $rotateBefore,
'autoRotate' => $autoRotate, 'autoRotate' => $autoRotate,
// General processing options // General processing options
'bgColor' => $bgColor, 'bgColor' => $bgColor,
@@ -617,12 +900,13 @@ $img->log("Incoming arguments: " . print_r(verbose(), 1))
->setJpegQuality($quality) ->setJpegQuality($quality)
->setPngCompression($compress) ->setPngCompression($compress)
->useOriginalIfPossible($useOriginal) ->useOriginalIfPossible($useOriginal)
->generateFilename($config['cache_path']) ->generateFilename($cachePath)
->useCacheIfPossible($useCache) ->useCacheIfPossible($useCache)
->load() ->load()
->preResize() ->preResize()
->resize() ->resize()
->postResize() ->postResize()
->setPostProcessingOptions($config['postprocessing']) ->setPostProcessingOptions($postProcessing)
->save() ->save()
->linkToCacheFile($aliasTarget)
->output(); ->output();

BIN
webroot/img/apple_trans.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
webroot/img/glider_anim.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -1,54 +1,123 @@
<?php <?php
/** /**
* Configuration for img.php, name the config file the same as your img.php and * Configuration for img.php, name the config file the same as your img.php and
* append _config. If you are testing out some in imgtest.php then label that * append _config. If you are testing out some in imgtest.php then label that
* config-file imgtest_config.php. * config-file imgtest_config.php.
* *
*/ */
return array( return array(
/** /**
* Paths, where are all the stuff I should use? * Set mode as 'strict', 'production' or 'development'.
* Append ending slash on directories. *
* Default values:
* mode: 'production'
*/
'mode' => 'development',
//'mode' => 'production', // 'development', 'strict'
/**
* Where are the sources for the classfiles.
*
* Default values:
* autoloader: null // used from v0.6.2
* cimage_class: null // used until v0.6.1
*/
'autoloader' => __DIR__ . '/../autoload.php',
//'cimage_class' => __DIR__ . '/../CImage.php',
/**
* Paths, where are the images stored and where is the cache.
* End all paths with a slash.
*
* Default values:
* image_path: __DIR__ . '/img/'
* cache_path: __DIR__ . '/../cache/'
* alias_path: null
*/ */
'cimage_class' => __DIR__ . '/../CImage.php',
'image_path' => __DIR__ . '/img/', 'image_path' => __DIR__ . '/img/',
'cache_path' => __DIR__ . '/../cache/', 'cache_path' => __DIR__ . '/../cache/',
//'alias_path' => __DIR__ . '/img/alias/',
/** /**
* Use password to protect from missusage, send &pwd=... or &password=..
* with the request to match the password or set to false to disable.
* Passwords are only used together with the options for remote download
* and aliasing.
*
* Default values.
* password: false // as in do not use password
* password_always: false // do not always require password,
*/
//'password' => false, // "secret-password",
//'password_always' => false, // always require password,
/**
* Allow or disallow downloading of remote files, images available on
* some remote server. Default is to disallow.
*
* Default values.
* remote_allow: false
* remote_pattern: null // use default values from CImage
*/
//'remote_allow' => true,
//'remote_pattern' => '#^https?://#',
/**
* A regexp for validating characters in the image or alias filename.
*
* Default value:
* valid_filename: '#^[a-z0-9A-Z-/_\.:]+$#'
* valid_aliasname: '#^[a-z0-9A-Z-_]+$#'
*/
//'valid_filename' => '#^[a-z0-9A-Z-/_\.:]+$#',
//'valid_aliasname' => '#^[a-z0-9A-Z-_]+$#',
/**
* Check that the imagefile is a file below 'image_path' using realpath(). * Check that the imagefile is a file below 'image_path' using realpath().
* Security constraint to avoid reaching images outside image_path. * Security constraint to avoid reaching images outside image_path.
* This means that symbolic links to images outside the image_path will fail. * This means that symbolic links to images outside the image_path will fail.
*
* Default value:
* image_path_constraint: true
*/ */
'image_path_constraint' => true, //'image_path_constraint' => false,
/** /**
* A regexp for validating characters in the image filename. * Set default timezone.
*
* Default values.
* default_timezone: ini_get('default_timezone') or 'UTC'
*/ */
'valid_filename' => '#^[a-z0-9A-Z-/_\.]+$#', //'default_timezone' => 'UTC',
/**
* Set default timezone, it defaults to UTC if not specified.
*
*/
//'default_timezone' => 'UTC',
/** /**
* Max image dimensions, larger dimensions results in 404. * Max image dimensions, larger dimensions results in 404.
* This is basically a security constraint to avoid using resources on creating * This is basically a security constraint to avoid using resources on creating
* large (unwanted) images. * large (unwanted) images.
* *
* Default values.
* max_width: 2000
* max_height: 2000
*/ */
'max_width' => 2000, //'max_width' => 2000,
'max_height' => 2000, //'max_height' => 2000,
@@ -56,10 +125,12 @@ return array(
* Set default background color for all images. Override it using * Set default background color for all images. Override it using
* option bgColor. * option bgColor.
* Colorvalue is 6 digit hex string between 000000-FFFFFF * Colorvalue is 6 digit hex string between 000000-FFFFFF
* or 8 digit hex string if using the alpha channel where * or 8 digit hex string if using the alpha channel where
* the alpha value is between 00 (opaqe) and 7F (transparent), * the alpha value is between 00 (opaqe) and 7F (transparent),
* that is between 00000000-FFFFFF7F. * that is between 00000000-FFFFFF7F.
* *
* Default values.
* background_color: As specified by CImage
*/ */
//'background_color' => "FFFFFF", //'background_color' => "FFFFFF",
//'background_color' => "FFFFFF7F", //'background_color' => "FFFFFF7F",
@@ -67,9 +138,21 @@ return array(
/** /**
* Post processing of images using external tools, set to true or false * Post processing of images using external tools, set to true or false
* and set command to be executed. * and set command to be executed.
*
* Default values.
*
* png_filter: false
* png_filter_cmd: '/usr/local/bin/optipng -q'
*
* png_deflate: false
* png_deflate_cmd: '/usr/local/bin/pngout -q'
*
* jpeg_optimize: false
* jpeg_optimize_cmd: '/usr/local/bin/jpegtran -copy none -optimize'
*/ */
/*
'postprocessing' => array( 'postprocessing' => array(
'png_filter' => false, 'png_filter' => false,
'png_filter_cmd' => '/usr/local/bin/optipng -q', 'png_filter_cmd' => '/usr/local/bin/optipng -q',
@@ -80,41 +163,78 @@ return array(
'jpeg_optimize' => false, 'jpeg_optimize' => false,
'jpeg_optimize_cmd' => '/usr/local/bin/jpegtran -copy none -optimize', 'jpeg_optimize_cmd' => '/usr/local/bin/jpegtran -copy none -optimize',
), ),
*/
/** /**
* Create custom convolution expressions, matrix 3x3, divisor and * Create custom convolution expressions, matrix 3x3, divisor and
* offset. * offset.
*
* Default values.
* convolution_constant: array()
*/ */
/*
'convolution_constant' => array( 'convolution_constant' => array(
//'sharpen' => '-1,-1,-1, -1,16,-1, -1,-1,-1, 8, 0', //'sharpen' => '-1,-1,-1, -1,16,-1, -1,-1,-1, 8, 0',
//'sharpen-alt' => '0,-1,0, -1,5,-1, 0,-1,0, 1, 0', //'sharpen-alt' => '0,-1,0, -1,5,-1, 0,-1,0, 1, 0',
), ),
*/
/**
* Prevent leeching of images by controlling who can access them from where.
* Default it to allow hotlinking.
* Password apply when hotlinking is disallowed, use password to allow.
* The whitelist is an array of regexpes for allowed hostnames that can
* hotlink images.
*
* Default values.
* allow_hotlinking: true
* hotlinking_whitelist: array()
*/
/*
'allow_hotlinking' => false,
'hotlinking_whitelist' => array(
'#^localhost$#',
'#^dbwebb\.se$#',
),
*/
/** /**
* Create custom shortcuts for more advanced expressions. * Create custom shortcuts for more advanced expressions.
*
* Default values.
* shortcut: array(
* 'sepia' => "&f=grayscale&f0=brightness,-10&f1=contrast,-20&f2=colorize,120,60,0,0&sharpen",
* )
*/ */
/*
'shortcut' => array( 'shortcut' => array(
'sepia' => "&f=grayscale&f0=brightness,-10&f1=contrast,-20&f2=colorize,120,60,0,0&sharpen", 'sepia' => "&f=grayscale&f0=brightness,-10&f1=contrast,-20&f2=colorize,120,60,0,0&sharpen",
), ),*/
/** /**
* Predefined size constants. * Predefined size constants.
* *
* These can be used together with &width or &height to create a constant value * These can be used together with &width or &height to create a constant value
* for a width or height where can be changed in one place. * for a width or height where can be changed in one place.
* Useful when your site changes its layout or if you have a grid to fit images into. * Useful when your site changes its layout or if you have a grid to fit images into.
* *
* Example: * Example:
* &width=w1 // results in width=613 * &width=w1 // results in width=613
* &width=c2 // results in spanning two columns with a gutter, 30*2+10=70 * &width=c2 // results in spanning two columns with a gutter, 30*2+10=70
* &width=c24 // results in spanning whole grid 24*30+((24-1)*10)=950 * &width=c24 // results in spanning whole grid 24*30+((24-1)*10)=950
*
* Default values.
* size_constant: As specified by the function below.
*/ */
/*
'size_constant' => function () { 'size_constant' => function () {
// Set sizes to map constant to value, easier to use with width or height // Set sizes to map constant to value, easier to use with width or height
@@ -133,15 +253,17 @@ return array(
} }
return $sizes; return $sizes;
}, },*/
/** /**
* Predefined aspect ratios. * Predefined aspect ratios.
* *
* Default values.
* aspect_ratio_constant: As the function below.
*/ */
'aspect_ratio_constant' => function () { /*'aspect_ratio_constant' => function () {
return array( return array(
'3:1' => 3/1, '3:1' => 3/1,
'3:2' => 3/2, '3:2' => 3/2,
@@ -151,20 +273,5 @@ return array(
'16:9' => 16/9, '16:9' => 16/9,
'golden' => 1.618, 'golden' => 1.618,
); );
}, },*/
/**
* Set error reporting to match development or production environment
*/
'error_reporting' => function () {
error_reporting(-1); // Report all type of errors
ini_set('display_errors', 1); // Display all errors
set_time_limit(20);
ini_set('gd.jpeg_ignore_warning', 1); // Ignore warning of corrupt jpegs
if (!extension_loaded('gd')) {
throw new Exception("Extension gd is nod loaded.");
}
},
); );

35
webroot/img_header.php Normal file
View File

@@ -0,0 +1,35 @@
<?php
/**
* Resize and crop images on the fly, store generated images in a cache.
*
* This version is a all-in-one version of img.php, it is not dependant an any other file
* so you can simply copy it to any place you want it.
*
* @author Mikael Roos mos@dbwebb.se
* @example http://dbwebb.se/opensource/cimage
* @link https://github.com/mosbth/cimage
*
*/
/**
* Change configuration details in the array below or create a separate file
* where you store the configuration details.
*
* The configuration file should be named the same name as this file and then
* add '_config.php'. If this file is named 'img.php' then name the
* config file should be named 'img_config.php'.
*
* The settings below are only a few of the available ones. Check the file in
* webroot/img_config.php for a complete list of configuration options.
*/
$config = array(
//'mode' => 'production', // 'production', 'development', 'strict'
//'image_path' => __DIR__ . '/img/',
//'cache_path' => __DIR__ . '/../cache/',
//'alias_path' => __DIR__ . '/img/alias/',
//'remote_allow' => true,
//'password' => false, // "secret-password",
);

3906
webroot/imgd.php Normal file

File diff suppressed because it is too large Load Diff

3906
webroot/imgp.php Normal file

File diff suppressed because it is too large Load Diff

3906
webroot/imgs.php Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -17,11 +17,13 @@ $description = "The issue was to implement fill-to-fit, but it needs some flexib
// Use these images in the test // Use these images in the test
$images = array( $images = array(
'kodim04.png', 'kodim04.png',
'apple_trans.gif',
'circle_trans.png',
); );
// For each image, apply these testcases // For each image, apply these testcases
$cache = "&nc"; // ""; // "&nc" $cache = "&nc"; // ""; // "&nc"
$testcase = array( $testcase = array(
"$cache&w=300&h=300&fill-to-fit", "$cache&w=300&h=300&fill-to-fit",