1
0
mirror of https://github.com/mosbth/cimage.git synced 2025-08-26 17:14:27 +02:00

Compare commits

..

6 Commits

Author SHA1 Message Date
Mikael Roos
e59ef91991 prepare to tag v0.7.17 2016-08-09 13:23:04 +02:00
Mikael Roos
2337dbe94c Made &lossless part of the generated cache filename. 2016-08-09 13:22:33 +02:00
Mikael Roos
c5de59a754 prepare to tag v0.7.16 2016-08-09 13:02:25 +02:00
Mikael Roos
7ab19d39d6 adding support for pngquant 2016-08-09 13:01:38 +02:00
Mikael Roos
9f6cba9292 changed date of release 2016-08-09 10:21:41 +02:00
Mikael Roos
21e53887b8 prepare to tag v0.7.15 2016-08-09 10:19:49 +02:00
12 changed files with 453 additions and 60 deletions

View File

@@ -155,6 +155,13 @@ class CImage
/**
* Do lossy output using external postprocessing tools.
*/
private $lossy = null;
/**
* Verbose mode to print out a trace and display the created image
*/
@@ -190,7 +197,15 @@ class CImage
/**
* Path to command for filter optimize, for example optipng or null.
* Path to command for lossy optimize, for example pngquant.
*/
private $pngLossy;
private $pngLossyCmd;
/**
* Path to command for filter optimize, for example optipng.
*/
private $pngFilter;
private $pngFilterCmd;
@@ -198,7 +213,7 @@ class CImage
/**
* Path to command for deflate optimize, for example pngout or null.
* Path to command for deflate optimize, for example pngout.
*/
private $pngDeflate;
private $pngDeflateCmd;
@@ -827,6 +842,9 @@ class CImage
// Output format
'outputFormat' => null,
'dpr' => 1,
// Postprocessing using external tools
'lossy' => null,
);
// Convert crop settings from string to array
@@ -1380,6 +1398,7 @@ class CImage
$compress = $this->compress ? "_co{$this->compress}" : null;
$rotateBefore = $this->rotateBefore ? "_rb{$this->rotateBefore}" : null;
$rotateAfter = $this->rotateAfter ? "_ra{$this->rotateAfter}" : null;
$lossy = $this->lossy ? "_l" : null;
$saveAs = $this->normalizeFileExtension();
$saveAs = $saveAs ? "_$saveAs" : null;
@@ -1446,7 +1465,7 @@ class CImage
. $quality . $filters . $sharpen . $emboss . $blur . $palette
. $optimize . $compress
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor
. $convolve . $copyStrat . $saveAs;
. $convolve . $copyStrat . $lossy . $saveAs;
return $this->setTarget($file, $base);
}
@@ -2345,6 +2364,14 @@ class CImage
$this->jpegOptimizeCmd = null;
}
if (array_key_exists("png_lossy", $options)
&& $options['png_lossy'] !== false) {
$this->pngLossy = $options['png_lossy'];
$this->pngLossyCmd = $options['png_lossy_cmd'];
} else {
$this->pngLossyCmd = null;
}
if (isset($options['png_filter']) && $options['png_filter']) {
$this->pngFilterCmd = $options['png_filter_cmd'];
} else {
@@ -2446,6 +2473,24 @@ class CImage
imagesavealpha($this->image, true);
imagepng($this->image, $this->cacheFileName, $this->compress);
// Use external program to process lossy PNG, if defined
$lossyEnabled = $this->pngLossy === true;
$lossySoftEnabled = $this->pngLossy === null;
$lossyActiveEnabled = $this->lossy === true;
if ($lossyEnabled || ($lossySoftEnabled && $lossyActiveEnabled)) {
if ($this->verbose) {
clearstatcache();
$this->log("Lossy enabled: $lossyEnabled");
$this->log("Lossy soft enabled: $lossySoftEnabled");
$this->Log("Filesize before lossy optimize: " . filesize($this->cacheFileName) . " bytes.");
}
$res = array();
$cmd = $this->pngLossyCmd . " $this->cacheFileName $this->cacheFileName";
exec($cmd, $res);
$this->Log($cmd);
$this->Log($res);
}
// Use external program to filter PNG, if defined
if ($this->pngFilterCmd) {
if ($this->verbose) {

View File

@@ -49,14 +49,14 @@ There are several ways of installing. You either install the whole project which
The [sourcode is available on GitHub](https://github.com/mosbth/cimage). Clone, fork or [download as zip](https://github.com/mosbth/cimage/archive/master.zip).
**Latest stable version is v0.7.14 released 2016-08-08.**
**Latest stable version is v0.7.17 released 2016-08-09.**
I prefer cloning like this. Do switch to the latest stable version.
```bash
git clone git://github.com/mosbth/cimage.git
cd cimage
git checkout v0.7.14
git checkout v0.7.17
```
Make the cache-directory writable by the webserver.
@@ -79,7 +79,7 @@ There are some all-included bundles of `img.php` that can be downloaded and used
Dowload the version of your choice like this.
```bash
wget https://raw.githubusercontent.com/mosbth/cimage/v0.7.14/webroot/imgp.php
wget https://raw.githubusercontent.com/mosbth/cimage/v0.7.17/webroot/imgp.php
```
Open up the file in your editor and edit the array `$config`. Ensure that the paths to the image directory and the cache directory matches your environment, or create an own config-file for the script.

View File

@@ -5,11 +5,25 @@ Revision history
[![Build Status](https://scrutinizer-ci.com/g/mosbth/cimage/badges/build.png?b=master)](https://scrutinizer-ci.com/g/mosbth/cimage/build-status/master)
v0.7.15 (2016-08-08)
v0.7.17 (2016-08-09)
-------------------------------------
* Added the [Lenna/Lena sample image](http://www.cs.cmu.edu/~chuck/lennapg/) as tif and created a png, jpeg and webp version using Imagick convert `convert lena.tif lena.{png,jpg,webp}`.
* Support saving to imgp format through `sa=webp`, #132.
* Made `&lossless` part of the generated cache filename.
v0.7.16 (2016-08-09)
-------------------------------------
* Fix default mode to be production.
* Added pngquant as extra postprocessing utility for PNG-images, #154.
* Bug `&status` wrong variable name for fast track cache.
v0.7.15 (2016-08-09)
-------------------------------------
* Added the [Lenna/Lena sample image](http://www.cs.cmu.edu/~chuck/lennapg/) as tif and created a png, jpeg and webp version using Imagick convert `convert lena.tif lena.{png,jpg,webp}`, #152.
* Limited and basic support for WEBP format, se #132.
v0.7.14 (2016-08-08)

View File

@@ -1,6 +1,6 @@
<?php
// Version of cimage and img.php
define("CIMAGE_VERSION", "v0.7.15 (2016-08-09)");
define("CIMAGE_VERSION", "v0.7.17 (2016-08-09)");
// For CRemoteImage
define("CIMAGE_USER_AGENT", "CImage/" . CIMAGE_VERSION);

View File

@@ -163,3 +163,24 @@ function verbose($msg = null)
$log[] = $msg;
}
/**
* Log when verbose mode, when used without argument it returns the result.
*
* @param string $msg to log.
*
* @return void or array.
*/
function checkExternalCommand($what, $enabled, $commandString)
{
$no = $enabled ? null : 'NOT';
$text = "Post processing $what is $no enabled.<br>";
list($command) = explode(" ", $commandString);
$no = is_executable($command) ? null : 'NOT';
$text .= "The command for $what is $no an executable.<br>";
return $text;
}

View File

@@ -21,6 +21,9 @@ if (!$no) {
echo "<strong>Checking path for postprocessing tools</strong>";
echo "<br>pngquant: ";
system("which pngquant");
echo "<br>optipng: ";
system("which optipng");

View File

@@ -840,6 +840,9 @@ verbose("upscale = $upscale");
* Get details for post processing
*/
$postProcessing = getConfig('postprocessing', array(
'png_lossy' => false,
'png_lossy_cmd' => '/usr/local/bin/pngquant --force --output',
'png_filter' => false,
'png_filter_cmd' => '/usr/local/bin/optipng -q',
@@ -852,6 +855,15 @@ $postProcessing = getConfig('postprocessing', array(
/**
* lossy - Do lossy postprocessing, if available.
*/
$lossy = getDefined(array('lossy'), true, null);
verbose("lossy = $lossy");
/**
* alias - Save resulting image to another alias name.
* Password always apply, must be defined.
@@ -970,7 +982,7 @@ if ($status) {
$res = $cache->getStatusOfSubdir("srgb");
$text .= "Cache srgb $res\n";
$res = $cache->getStatusOfSubdir($fasttrackCache);
$res = $cache->getStatusOfSubdir($fastTrackCache);
$text .= "Cache fasttrack $res\n";
$text .= "Alias path writable = " . is_writable($aliasPath) . "\n";
@@ -987,6 +999,11 @@ if ($status) {
$no = extension_loaded('gd') ? null : 'NOT';
$text .= "Extension gd is $no loaded.<br>";
$text .= checkExternalCommand("PNG LOSSY", $postProcessing["png_lossy"], $postProcessing["png_lossy_cmd"]);
$text .= checkExternalCommand("PNG FILTER", $postProcessing["png_filter"], $postProcessing["png_filter_cmd"]);
$text .= checkExternalCommand("PNG DEFLATE", $postProcessing["png_deflate"], $postProcessing["png_deflate_cmd"]);
$text .= checkExternalCommand("JPEG OPTIMIZE", $postProcessing["jpeg_optimize"], $postProcessing["jpeg_optimize_cmd"]);
if (!$no) {
$text .= print_r(gd_info(), 1);
}
@@ -1055,6 +1072,7 @@ if (is_callable($hookBeforeCImage)) {
// Other
'postProcessing' => $postProcessing,
'lossy' => $lossy,
));
verbose(print_r($allConfig, 1));
extract($allConfig);
@@ -1139,6 +1157,9 @@ $img->log("Incoming arguments: " . print_r(verbose(), 1))
// Output format
'outputFormat' => $outputFormat,
'dpr' => $dpr,
// Postprocessing using external tools
'lossy' => $lossy,
)
)
->loadImageDetails()

BIN
webroot/img/duke.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

View File

@@ -41,7 +41,7 @@ return array(
* mode: 'production'
*/
//'mode' => 'production',
'mode' => 'development',
//'mode' => 'development',
//'mode' => 'strict',
@@ -321,8 +321,16 @@ return array(
* Post processing of images using external tools, set to true or false
* and set command to be executed.
*
* The png_lossy can alos have a value of null which means that its
* enabled but not used as default. Each image having the option
* &lossy will be processed. This means one can individually choose
* when to use the lossy processing.
*
* Default values.
*
* png_lossy: false
* png_lossy_cmd: '/usr/local/bin/pngquant --force --output'
*
* png_filter: false
* png_filter_cmd: '/usr/local/bin/optipng -q'
*
@@ -334,6 +342,9 @@ return array(
*/
/*
'postprocessing' => array(
'png_lossy' => null,
'png_lossy_cmd' => '/usr/local/bin/pngquant --force --output',
'png_filter' => false,
'png_filter_cmd' => '/usr/local/bin/optipng -q',

View File

@@ -38,11 +38,16 @@ $config = array(
// Version of cimage and img.php
define("CIMAGE_VERSION", "v0.7.13 (2016-08-08)");
define("CIMAGE_VERSION", "v0.7.17 (2016-08-09)");
// For CRemoteImage
define("CIMAGE_USER_AGENT", "CImage/" . CIMAGE_VERSION);
// Image type IMG_WEBP is only defined from 5.6.25
if (!defined("IMG_WEBP")) {
define("IMG_WEBP", -1);
}
/**
@@ -212,6 +217,27 @@ function verbose($msg = null)
/**
* Log when verbose mode, when used without argument it returns the result.
*
* @param string $msg to log.
*
* @return void or array.
*/
function checkExternalCommand($what, $enabled, $commandString)
{
$no = $enabled ? null : 'NOT';
$text = "Post processing $what is $no enabled.<br>";
list($command) = explode(" ", $commandString);
$no = is_executable($command) ? null : 'NOT';
$text .= "The command for $what is $no an executable.<br>";
return $text;
}
/**
* Get a image from a remote server using HTTP GET and If-Modified-Since.
*
@@ -1255,6 +1281,13 @@ class CImage
/**
* Do lossy output using external postprocessing tools.
*/
private $lossy = null;
/**
* Verbose mode to print out a trace and display the created image
*/
@@ -1290,7 +1323,15 @@ class CImage
/**
* Path to command for filter optimize, for example optipng or null.
* Path to command for lossy optimize, for example pngquant.
*/
private $pngLossy;
private $pngLossyCmd;
/**
* Path to command for filter optimize, for example optipng.
*/
private $pngFilter;
private $pngFilterCmd;
@@ -1298,7 +1339,7 @@ class CImage
/**
* Path to command for deflate optimize, for example pngout or null.
* Path to command for deflate optimize, for example pngout.
*/
private $pngDeflate;
private $pngDeflateCmd;
@@ -1740,7 +1781,7 @@ class CImage
*/
private function checkFileExtension($extension)
{
$valid = array('jpg', 'jpeg', 'png', 'gif');
$valid = array('jpg', 'jpeg', 'png', 'gif', 'webp');
in_array(strtolower($extension), $valid)
or $this->raiseError('Not a valid file extension.');
@@ -1763,7 +1804,7 @@ class CImage
if ($extension == 'jpeg') {
$extension = 'jpg';
}
}
return $extension;
}
@@ -1927,6 +1968,9 @@ class CImage
// Output format
'outputFormat' => null,
'dpr' => 1,
// Postprocessing using external tools
'lossy' => null,
);
// Convert crop settings from string to array
@@ -2041,17 +2085,34 @@ class CImage
is_readable($file)
or $this->raiseError('Image file does not exist.');
// Get details on image
$info = list($this->width, $this->height, $this->fileType, $this->attr) = getimagesize($file);
$info = list($this->width, $this->height, $this->fileType) = getimagesize($file);
if (empty($info)) {
throw new Exception("The file doesn't seem to be a valid image.");
// To support webp
$this->fileType = false;
if (function_exists("exif_imagetype")) {
$this->fileType = exif_imagetype($file);
if ($this->fileType === false) {
if (function_exists("imagecreatefromwebp")) {
$webp = imagecreatefromwebp($file);
if ($webp !== false) {
$this->width = imagesx($webp);
$this->height = imagesy($webp);
$this->fileType = IMG_WEBP;
}
}
}
}
}
if (!$this->fileType) {
throw new Exception("Loading image details, the file doesn't seem to be a valid image.");
}
if ($this->verbose) {
$this->log("Loading image details for: {$file}");
$this->log(" Image width x height (type): {$this->width} x {$this->height} ({$this->fileType}).");
$this->log(" Image filesize: " . filesize($file) . " bytes.");
$this->log(" Image mimetype: " . image_type_to_mime_type($this->fileType));
$this->log(" Image mimetype: " . $this->getMimeType());
}
return $this;
@@ -2059,6 +2120,23 @@ class CImage
/**
* Get mime type for image type.
*
* @return $this
* @throws Exception
*/
protected function getMimeType()
{
if ($this->fileType === IMG_WEBP) {
return "image/webp";
}
return image_type_to_mime_type($this->fileType);
}
/**
* Init new width and height and do some sanity checks on constraints, before any
* processing can be done.
@@ -2446,6 +2524,7 @@ class CImage
$compress = $this->compress ? "_co{$this->compress}" : null;
$rotateBefore = $this->rotateBefore ? "_rb{$this->rotateBefore}" : null;
$rotateAfter = $this->rotateAfter ? "_ra{$this->rotateAfter}" : null;
$lossy = $this->lossy ? "_l" : null;
$saveAs = $this->normalizeFileExtension();
$saveAs = $saveAs ? "_$saveAs" : null;
@@ -2512,7 +2591,7 @@ class CImage
. $quality . $filters . $sharpen . $emboss . $blur . $palette
. $optimize . $compress
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor
. $convolve . $copyStrat . $saveAs;
. $convolve . $copyStrat . $lossy . $saveAs;
return $this->setTarget($file, $base);
}
@@ -2570,9 +2649,14 @@ class CImage
$this->setSource($src, $dir);
}
$this->loadImageDetails($this->pathToImage);
$this->loadImageDetails();
$this->image = imagecreatefromstring(file_get_contents($this->pathToImage));
if ($this->fileType === IMG_WEBP) {
$this->image = imagecreatefromwebp($this->pathToImage);
} else {
$imageAsString = file_get_contents($this->pathToImage);
$this->image = imagecreatefromstring($imageAsString);
}
if ($this->image === false) {
throw new Exception("Could not load image.");
}
@@ -3406,6 +3490,14 @@ class CImage
$this->jpegOptimizeCmd = null;
}
if (array_key_exists("png_lossy", $options)
&& $options['png_lossy'] !== false) {
$this->pngLossy = $options['png_lossy'];
$this->pngLossyCmd = $options['png_lossy_cmd'];
} else {
$this->pngLossyCmd = null;
}
if (isset($options['png_filter']) && $options['png_filter']) {
$this->pngFilterCmd = $options['png_filter_cmd'];
} else {
@@ -3433,9 +3525,11 @@ class CImage
// switch on mimetype
if (isset($this->extension)) {
return strtolower($this->extension);
} else {
return substr(image_type_to_extension($this->fileType), 1);
} elseif ($this->fileType === IMG_WEBP) {
return "webp";
}
return substr(image_type_to_extension($this->fileType), 1);
}
@@ -3491,6 +3585,11 @@ class CImage
imagegif($this->image, $this->cacheFileName);
break;
case 'webp':
$this->Log("Saving image as WEBP to cache using quality = {$this->quality}.");
imagewebp($this->image, $this->cacheFileName, $this->quality);
break;
case 'png':
default:
$this->Log("Saving image as PNG to cache using compression = {$this->compress}.");
@@ -3500,6 +3599,24 @@ class CImage
imagesavealpha($this->image, true);
imagepng($this->image, $this->cacheFileName, $this->compress);
// Use external program to process lossy PNG, if defined
$lossyEnabled = $this->pngLossy === true;
$lossySoftEnabled = $this->pngLossy === null;
$lossyActiveEnabled = $this->lossy === true;
if ($lossyEnabled || ($lossySoftEnabled && $lossyActiveEnabled)) {
if ($this->verbose) {
clearstatcache();
$this->log("Lossy enabled: $lossyEnabled");
$this->log("Lossy soft enabled: $lossySoftEnabled");
$this->Log("Filesize before lossy optimize: " . filesize($this->cacheFileName) . " bytes.");
}
$res = array();
$cmd = $this->pngLossyCmd . " $this->cacheFileName $this->cacheFileName";
exec($cmd, $res);
$this->Log($cmd);
$this->Log($res);
}
// Use external program to filter PNG, if defined
if ($this->pngFilterCmd) {
if ($this->verbose) {
@@ -3679,6 +3796,7 @@ class CImage
$format = $this->outputFormat;
}
$this->log("### Output");
$this->log("Output format is: $format");
if (!$this->verbose && $format == 'json') {
@@ -3712,7 +3830,8 @@ class CImage
$this->fastTrackCache->addHeader($header);
}
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) {
$this->log("304 not modified");
@@ -3727,10 +3846,8 @@ class CImage
} else {
// Get details on image
$info = getimagesize($file);
!empty($info) or $this->raiseError("The file doesn't seem to be an image.");
$mime = $info['mime'];
$this->loadImageDetails($file);
$mime = $this->getMimeType();
$size = filesize($file);
if ($this->verbose) {
@@ -3791,7 +3908,7 @@ class CImage
$this->load($file);
$details['filename'] = basename($file);
$details['mimeType'] = image_type_to_mime_type($this->fileType);
$details['mimeType'] = $this->getMimeType($this->fileType);
$details['width'] = $this->width;
$details['height'] = $this->height;
$details['aspectRatio'] = round($this->width / $this->height, 3);
@@ -3893,6 +4010,7 @@ class CImage
private function verboseOutput()
{
$log = null;
$this->log("### Summary of verbose log");
$this->log("As JSON: \n" . $this->json());
$this->log("Memory peak: " . round(memory_get_peak_usage() /1024/1024) . "M");
$this->log("Memory limit: " . ini_get('memory_limit'));
@@ -5131,6 +5249,9 @@ verbose("upscale = $upscale");
* Get details for post processing
*/
$postProcessing = getConfig('postprocessing', array(
'png_lossy' => false,
'png_lossy_cmd' => '/usr/local/bin/pngquant --force --output',
'png_filter' => false,
'png_filter_cmd' => '/usr/local/bin/optipng -q',
@@ -5143,6 +5264,15 @@ $postProcessing = getConfig('postprocessing', array(
/**
* lossy - Do lossy postprocessing, if available.
*/
$lossy = getDefined(array('lossy'), true, null);
verbose("lossy = $lossy");
/**
* alias - Save resulting image to another alias name.
* Password always apply, must be defined.
@@ -5261,7 +5391,7 @@ if ($status) {
$res = $cache->getStatusOfSubdir("srgb");
$text .= "Cache srgb $res\n";
$res = $cache->getStatusOfSubdir($fasttrackCache);
$res = $cache->getStatusOfSubdir($fastTrackCache);
$text .= "Cache fasttrack $res\n";
$text .= "Alias path writable = " . is_writable($aliasPath) . "\n";
@@ -5278,6 +5408,11 @@ if ($status) {
$no = extension_loaded('gd') ? null : 'NOT';
$text .= "Extension gd is $no loaded.<br>";
$text .= checkExternalCommand("PNG LOSSY", $postProcessing["png_lossy"], $postProcessing["png_lossy_cmd"]);
$text .= checkExternalCommand("PNG FILTER", $postProcessing["png_filter"], $postProcessing["png_filter_cmd"]);
$text .= checkExternalCommand("PNG DEFLATE", $postProcessing["png_deflate"], $postProcessing["png_deflate_cmd"]);
$text .= checkExternalCommand("JPEG OPTIMIZE", $postProcessing["jpeg_optimize"], $postProcessing["jpeg_optimize_cmd"]);
if (!$no) {
$text .= print_r(gd_info(), 1);
}
@@ -5346,6 +5481,7 @@ if (is_callable($hookBeforeCImage)) {
// Other
'postProcessing' => $postProcessing,
'lossy' => $lossy,
));
verbose(print_r($allConfig, 1));
extract($allConfig);
@@ -5430,6 +5566,9 @@ $img->log("Incoming arguments: " . print_r(verbose(), 1))
// Output format
'outputFormat' => $outputFormat,
'dpr' => $dpr,
// Postprocessing using external tools
'lossy' => $lossy,
)
)
->loadImageDetails()

View File

@@ -38,11 +38,16 @@ $config = array(
// Version of cimage and img.php
define("CIMAGE_VERSION", "v0.7.13 (2016-08-08)");
define("CIMAGE_VERSION", "v0.7.17 (2016-08-09)");
// For CRemoteImage
define("CIMAGE_USER_AGENT", "CImage/" . CIMAGE_VERSION);
// Image type IMG_WEBP is only defined from 5.6.25
if (!defined("IMG_WEBP")) {
define("IMG_WEBP", -1);
}
/**
@@ -212,6 +217,27 @@ function verbose($msg = null)
/**
* Log when verbose mode, when used without argument it returns the result.
*
* @param string $msg to log.
*
* @return void or array.
*/
function checkExternalCommand($what, $enabled, $commandString)
{
$no = $enabled ? null : 'NOT';
$text = "Post processing $what is $no enabled.<br>";
list($command) = explode(" ", $commandString);
$no = is_executable($command) ? null : 'NOT';
$text .= "The command for $what is $no an executable.<br>";
return $text;
}
/**
* Get a image from a remote server using HTTP GET and If-Modified-Since.
*
@@ -1255,6 +1281,13 @@ class CImage
/**
* Do lossy output using external postprocessing tools.
*/
private $lossy = null;
/**
* Verbose mode to print out a trace and display the created image
*/
@@ -1290,7 +1323,15 @@ class CImage
/**
* Path to command for filter optimize, for example optipng or null.
* Path to command for lossy optimize, for example pngquant.
*/
private $pngLossy;
private $pngLossyCmd;
/**
* Path to command for filter optimize, for example optipng.
*/
private $pngFilter;
private $pngFilterCmd;
@@ -1298,7 +1339,7 @@ class CImage
/**
* Path to command for deflate optimize, for example pngout or null.
* Path to command for deflate optimize, for example pngout.
*/
private $pngDeflate;
private $pngDeflateCmd;
@@ -1740,7 +1781,7 @@ class CImage
*/
private function checkFileExtension($extension)
{
$valid = array('jpg', 'jpeg', 'png', 'gif');
$valid = array('jpg', 'jpeg', 'png', 'gif', 'webp');
in_array(strtolower($extension), $valid)
or $this->raiseError('Not a valid file extension.');
@@ -1763,7 +1804,7 @@ class CImage
if ($extension == 'jpeg') {
$extension = 'jpg';
}
}
return $extension;
}
@@ -1927,6 +1968,9 @@ class CImage
// Output format
'outputFormat' => null,
'dpr' => 1,
// Postprocessing using external tools
'lossy' => null,
);
// Convert crop settings from string to array
@@ -2041,17 +2085,34 @@ class CImage
is_readable($file)
or $this->raiseError('Image file does not exist.');
// Get details on image
$info = list($this->width, $this->height, $this->fileType, $this->attr) = getimagesize($file);
$info = list($this->width, $this->height, $this->fileType) = getimagesize($file);
if (empty($info)) {
throw new Exception("The file doesn't seem to be a valid image.");
// To support webp
$this->fileType = false;
if (function_exists("exif_imagetype")) {
$this->fileType = exif_imagetype($file);
if ($this->fileType === false) {
if (function_exists("imagecreatefromwebp")) {
$webp = imagecreatefromwebp($file);
if ($webp !== false) {
$this->width = imagesx($webp);
$this->height = imagesy($webp);
$this->fileType = IMG_WEBP;
}
}
}
}
}
if (!$this->fileType) {
throw new Exception("Loading image details, the file doesn't seem to be a valid image.");
}
if ($this->verbose) {
$this->log("Loading image details for: {$file}");
$this->log(" Image width x height (type): {$this->width} x {$this->height} ({$this->fileType}).");
$this->log(" Image filesize: " . filesize($file) . " bytes.");
$this->log(" Image mimetype: " . image_type_to_mime_type($this->fileType));
$this->log(" Image mimetype: " . $this->getMimeType());
}
return $this;
@@ -2059,6 +2120,23 @@ class CImage
/**
* Get mime type for image type.
*
* @return $this
* @throws Exception
*/
protected function getMimeType()
{
if ($this->fileType === IMG_WEBP) {
return "image/webp";
}
return image_type_to_mime_type($this->fileType);
}
/**
* Init new width and height and do some sanity checks on constraints, before any
* processing can be done.
@@ -2446,6 +2524,7 @@ class CImage
$compress = $this->compress ? "_co{$this->compress}" : null;
$rotateBefore = $this->rotateBefore ? "_rb{$this->rotateBefore}" : null;
$rotateAfter = $this->rotateAfter ? "_ra{$this->rotateAfter}" : null;
$lossy = $this->lossy ? "_l" : null;
$saveAs = $this->normalizeFileExtension();
$saveAs = $saveAs ? "_$saveAs" : null;
@@ -2512,7 +2591,7 @@ class CImage
. $quality . $filters . $sharpen . $emboss . $blur . $palette
. $optimize . $compress
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor
. $convolve . $copyStrat . $saveAs;
. $convolve . $copyStrat . $lossy . $saveAs;
return $this->setTarget($file, $base);
}
@@ -2570,9 +2649,14 @@ class CImage
$this->setSource($src, $dir);
}
$this->loadImageDetails($this->pathToImage);
$this->loadImageDetails();
$this->image = imagecreatefromstring(file_get_contents($this->pathToImage));
if ($this->fileType === IMG_WEBP) {
$this->image = imagecreatefromwebp($this->pathToImage);
} else {
$imageAsString = file_get_contents($this->pathToImage);
$this->image = imagecreatefromstring($imageAsString);
}
if ($this->image === false) {
throw new Exception("Could not load image.");
}
@@ -3406,6 +3490,14 @@ class CImage
$this->jpegOptimizeCmd = null;
}
if (array_key_exists("png_lossy", $options)
&& $options['png_lossy'] !== false) {
$this->pngLossy = $options['png_lossy'];
$this->pngLossyCmd = $options['png_lossy_cmd'];
} else {
$this->pngLossyCmd = null;
}
if (isset($options['png_filter']) && $options['png_filter']) {
$this->pngFilterCmd = $options['png_filter_cmd'];
} else {
@@ -3433,9 +3525,11 @@ class CImage
// switch on mimetype
if (isset($this->extension)) {
return strtolower($this->extension);
} else {
return substr(image_type_to_extension($this->fileType), 1);
} elseif ($this->fileType === IMG_WEBP) {
return "webp";
}
return substr(image_type_to_extension($this->fileType), 1);
}
@@ -3491,6 +3585,11 @@ class CImage
imagegif($this->image, $this->cacheFileName);
break;
case 'webp':
$this->Log("Saving image as WEBP to cache using quality = {$this->quality}.");
imagewebp($this->image, $this->cacheFileName, $this->quality);
break;
case 'png':
default:
$this->Log("Saving image as PNG to cache using compression = {$this->compress}.");
@@ -3500,6 +3599,24 @@ class CImage
imagesavealpha($this->image, true);
imagepng($this->image, $this->cacheFileName, $this->compress);
// Use external program to process lossy PNG, if defined
$lossyEnabled = $this->pngLossy === true;
$lossySoftEnabled = $this->pngLossy === null;
$lossyActiveEnabled = $this->lossy === true;
if ($lossyEnabled || ($lossySoftEnabled && $lossyActiveEnabled)) {
if ($this->verbose) {
clearstatcache();
$this->log("Lossy enabled: $lossyEnabled");
$this->log("Lossy soft enabled: $lossySoftEnabled");
$this->Log("Filesize before lossy optimize: " . filesize($this->cacheFileName) . " bytes.");
}
$res = array();
$cmd = $this->pngLossyCmd . " $this->cacheFileName $this->cacheFileName";
exec($cmd, $res);
$this->Log($cmd);
$this->Log($res);
}
// Use external program to filter PNG, if defined
if ($this->pngFilterCmd) {
if ($this->verbose) {
@@ -3679,6 +3796,7 @@ class CImage
$format = $this->outputFormat;
}
$this->log("### Output");
$this->log("Output format is: $format");
if (!$this->verbose && $format == 'json') {
@@ -3712,7 +3830,8 @@ class CImage
$this->fastTrackCache->addHeader($header);
}
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) {
$this->log("304 not modified");
@@ -3727,10 +3846,8 @@ class CImage
} else {
// Get details on image
$info = getimagesize($file);
!empty($info) or $this->raiseError("The file doesn't seem to be an image.");
$mime = $info['mime'];
$this->loadImageDetails($file);
$mime = $this->getMimeType();
$size = filesize($file);
if ($this->verbose) {
@@ -3791,7 +3908,7 @@ class CImage
$this->load($file);
$details['filename'] = basename($file);
$details['mimeType'] = image_type_to_mime_type($this->fileType);
$details['mimeType'] = $this->getMimeType($this->fileType);
$details['width'] = $this->width;
$details['height'] = $this->height;
$details['aspectRatio'] = round($this->width / $this->height, 3);
@@ -3893,6 +4010,7 @@ class CImage
private function verboseOutput()
{
$log = null;
$this->log("### Summary of verbose log");
$this->log("As JSON: \n" . $this->json());
$this->log("Memory peak: " . round(memory_get_peak_usage() /1024/1024) . "M");
$this->log("Memory limit: " . ini_get('memory_limit'));
@@ -5131,6 +5249,9 @@ verbose("upscale = $upscale");
* Get details for post processing
*/
$postProcessing = getConfig('postprocessing', array(
'png_lossy' => false,
'png_lossy_cmd' => '/usr/local/bin/pngquant --force --output',
'png_filter' => false,
'png_filter_cmd' => '/usr/local/bin/optipng -q',
@@ -5143,6 +5264,15 @@ $postProcessing = getConfig('postprocessing', array(
/**
* lossy - Do lossy postprocessing, if available.
*/
$lossy = getDefined(array('lossy'), true, null);
verbose("lossy = $lossy");
/**
* alias - Save resulting image to another alias name.
* Password always apply, must be defined.
@@ -5261,7 +5391,7 @@ if ($status) {
$res = $cache->getStatusOfSubdir("srgb");
$text .= "Cache srgb $res\n";
$res = $cache->getStatusOfSubdir($fasttrackCache);
$res = $cache->getStatusOfSubdir($fastTrackCache);
$text .= "Cache fasttrack $res\n";
$text .= "Alias path writable = " . is_writable($aliasPath) . "\n";
@@ -5278,6 +5408,11 @@ if ($status) {
$no = extension_loaded('gd') ? null : 'NOT';
$text .= "Extension gd is $no loaded.<br>";
$text .= checkExternalCommand("PNG LOSSY", $postProcessing["png_lossy"], $postProcessing["png_lossy_cmd"]);
$text .= checkExternalCommand("PNG FILTER", $postProcessing["png_filter"], $postProcessing["png_filter_cmd"]);
$text .= checkExternalCommand("PNG DEFLATE", $postProcessing["png_deflate"], $postProcessing["png_deflate_cmd"]);
$text .= checkExternalCommand("JPEG OPTIMIZE", $postProcessing["jpeg_optimize"], $postProcessing["jpeg_optimize_cmd"]);
if (!$no) {
$text .= print_r(gd_info(), 1);
}
@@ -5346,6 +5481,7 @@ if (is_callable($hookBeforeCImage)) {
// Other
'postProcessing' => $postProcessing,
'lossy' => $lossy,
));
verbose(print_r($allConfig, 1));
extract($allConfig);
@@ -5430,6 +5566,9 @@ $img->log("Incoming arguments: " . print_r(verbose(), 1))
// Output format
'outputFormat' => $outputFormat,
'dpr' => $dpr,
// Postprocessing using external tools
'lossy' => $lossy,
)
)
->loadImageDetails()

File diff suppressed because one or more lines are too long