Compare commits
56 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
b44be78f06 | ||
|
1056f0a5ee | ||
|
1666ea1412 | ||
|
bb57af697b | ||
|
55ce23ae5e | ||
|
4589b3b3cd | ||
|
d5ca10cebc | ||
|
9d7343a2df | ||
|
3d7adcdbde | ||
|
80cd4e092f | ||
|
4c0ac8ed23 | ||
|
39b86628db | ||
|
5f4280d387 | ||
|
dd315dbd21 | ||
|
493118e1c5 | ||
|
e41b3d9877 | ||
|
bb60001c36 | ||
|
adeca3f9f9 | ||
|
a5662690fe | ||
|
3cfa9a6a98 | ||
|
4ecebcd5b4 | ||
|
9196d1ee41 | ||
|
0249056761 | ||
|
4ea72be49a | ||
|
2ce1f18fe5 | ||
|
0f1f537b62 | ||
|
1411adc828 | ||
|
86737af69e | ||
|
c563275ed5 | ||
|
8fec09b195 | ||
|
ac16343cd7 | ||
|
cd142c5880 | ||
|
91dd92d483 | ||
|
4b64d921d1 | ||
|
4211d7e0e6 | ||
|
dd8878c8bd | ||
|
f9604518e4 | ||
|
61aa52854e | ||
|
401478c839 | ||
|
f0ab9479d6 | ||
|
9ff7a61ca9 | ||
|
3170beb832 | ||
|
8001f72a1a | ||
|
0f9e0220f1 | ||
|
e59ef91991 | ||
|
2337dbe94c | ||
|
c5de59a754 | ||
|
7ab19d39d6 | ||
|
9f6cba9292 | ||
|
21e53887b8 | ||
|
66c5a07767 | ||
|
bbfd895c4c | ||
|
b5de49d601 | ||
|
7677fc772f | ||
|
3d0b25abe0 | ||
|
1e5de9d225 |
@@ -51,6 +51,15 @@ class CCache
|
|||||||
return $path;
|
return $path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($create && defined('WINDOWS2WSL')) {
|
||||||
|
// Special case to solve Windows 2 WSL integration
|
||||||
|
$path = $this->path . "/" . $subdir;
|
||||||
|
|
||||||
|
if (mkdir($path)) {
|
||||||
|
return realpath($path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($create && is_writable($this->path)) {
|
if ($create && is_writable($this->path)) {
|
||||||
$path = $this->path . "/" . $subdir;
|
$path = $this->path . "/" . $subdir;
|
||||||
|
|
||||||
|
@@ -215,7 +215,7 @@ class CHttpGet
|
|||||||
{
|
{
|
||||||
$type = isset($this->response['header']['Content-Type'])
|
$type = isset($this->response['header']['Content-Type'])
|
||||||
? $this->response['header']['Content-Type']
|
? $this->response['header']['Content-Type']
|
||||||
: null;
|
: '';
|
||||||
|
|
||||||
return preg_match('#[a-z]+/[a-z]+#', $type)
|
return preg_match('#[a-z]+/[a-z]+#', $type)
|
||||||
? $type
|
? $type
|
||||||
|
168
CImage.php
@@ -6,6 +6,7 @@
|
|||||||
* @example http://dbwebb.se/opensource/cimage
|
* @example http://dbwebb.se/opensource/cimage
|
||||||
* @link https://github.com/mosbth/cimage
|
* @link https://github.com/mosbth/cimage
|
||||||
*/
|
*/
|
||||||
|
#[AllowDynamicProperties]
|
||||||
class CImage
|
class CImage
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -155,6 +156,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
|
* Verbose mode to print out a trace and display the created image
|
||||||
*/
|
*/
|
||||||
@@ -190,7 +198,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 $pngFilter;
|
||||||
private $pngFilterCmd;
|
private $pngFilterCmd;
|
||||||
@@ -198,7 +214,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 $pngDeflate;
|
||||||
private $pngDeflateCmd;
|
private $pngDeflateCmd;
|
||||||
@@ -408,6 +424,13 @@ class CImage
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use interlaced progressive mode for JPEG images.
|
||||||
|
*/
|
||||||
|
private $interlace = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Image copy strategy, defaults to RESAMPLE.
|
* Image copy strategy, defaults to RESAMPLE.
|
||||||
*/
|
*/
|
||||||
@@ -640,7 +663,7 @@ class CImage
|
|||||||
*/
|
*/
|
||||||
private function checkFileExtension($extension)
|
private function checkFileExtension($extension)
|
||||||
{
|
{
|
||||||
$valid = array('jpg', 'jpeg', 'png', 'gif');
|
$valid = array('jpg', 'jpeg', 'png', 'gif', 'webp');
|
||||||
|
|
||||||
in_array(strtolower($extension), $valid)
|
in_array(strtolower($extension), $valid)
|
||||||
or $this->raiseError('Not a valid file extension.');
|
or $this->raiseError('Not a valid file extension.');
|
||||||
@@ -657,9 +680,9 @@ class CImage
|
|||||||
*
|
*
|
||||||
* @return string $extension as a normalized file extension.
|
* @return string $extension as a normalized file extension.
|
||||||
*/
|
*/
|
||||||
private function normalizeFileExtension($extension = null)
|
private function normalizeFileExtension($extension = "")
|
||||||
{
|
{
|
||||||
$extension = strtolower($extension ? $extension : $this->extension);
|
$extension = strtolower($extension ? $extension : $this->extension ?? "");
|
||||||
|
|
||||||
if ($extension == 'jpeg') {
|
if ($extension == 'jpeg') {
|
||||||
$extension = 'jpg';
|
$extension = 'jpg';
|
||||||
@@ -823,10 +846,14 @@ class CImage
|
|||||||
'blur' => null,
|
'blur' => null,
|
||||||
'convolve' => null,
|
'convolve' => null,
|
||||||
'rotateAfter' => null,
|
'rotateAfter' => null,
|
||||||
|
'interlace' => null,
|
||||||
|
|
||||||
// Output format
|
// Output format
|
||||||
'outputFormat' => null,
|
'outputFormat' => null,
|
||||||
'dpr' => 1,
|
'dpr' => 1,
|
||||||
|
|
||||||
|
// Postprocessing using external tools
|
||||||
|
'lossy' => null,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Convert crop settings from string to array
|
// Convert crop settings from string to array
|
||||||
@@ -938,20 +965,40 @@ class CImage
|
|||||||
{
|
{
|
||||||
$file = $file ? $file : $this->pathToImage;
|
$file = $file ? $file : $this->pathToImage;
|
||||||
|
|
||||||
|
// Special case to solve Windows 2 WSL integration
|
||||||
|
if (!defined('WINDOWS2WSL')) {
|
||||||
is_readable($file)
|
is_readable($file)
|
||||||
or $this->raiseError('Image file does not exist.');
|
or $this->raiseError('Image file does not exist.');
|
||||||
|
}
|
||||||
|
|
||||||
// Get details on image
|
$info = list($this->width, $this->height, $this->fileType) = getimagesize($file);
|
||||||
$info = list($this->width, $this->height, $this->fileType, $this->attr) = getimagesize($file);
|
|
||||||
if (empty($info)) {
|
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) {
|
if ($this->verbose) {
|
||||||
$this->log("Loading image details for: {$file}");
|
$this->log("Loading image details for: {$file}");
|
||||||
$this->log(" Image width x height (type): {$this->width} x {$this->height} ({$this->fileType}).");
|
$this->log(" Image width x height (type): {$this->width} x {$this->height} ({$this->fileType}).");
|
||||||
$this->log(" Image filesize: " . filesize($file) . " bytes.");
|
$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;
|
return $this;
|
||||||
@@ -959,6 +1006,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
|
* Init new width and height and do some sanity checks on constraints, before any
|
||||||
* processing can be done.
|
* processing can be done.
|
||||||
@@ -971,13 +1035,15 @@ class CImage
|
|||||||
$this->log("Init dimension (before) newWidth x newHeight is {$this->newWidth} x {$this->newHeight}.");
|
$this->log("Init dimension (before) newWidth x newHeight is {$this->newWidth} x {$this->newHeight}.");
|
||||||
|
|
||||||
// width as %
|
// width as %
|
||||||
if ($this->newWidth[strlen($this->newWidth)-1] == '%') {
|
if ($this->newWidth
|
||||||
|
&& $this->newWidth[strlen($this->newWidth)-1] == '%') {
|
||||||
$this->newWidth = $this->width * substr($this->newWidth, 0, -1) / 100;
|
$this->newWidth = $this->width * substr($this->newWidth, 0, -1) / 100;
|
||||||
$this->log("Setting new width based on % to {$this->newWidth}");
|
$this->log("Setting new width based on % to {$this->newWidth}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// height as %
|
// height as %
|
||||||
if ($this->newHeight[strlen($this->newHeight)-1] == '%') {
|
if ($this->newHeight
|
||||||
|
&& $this->newHeight[strlen($this->newHeight)-1] == '%') {
|
||||||
$this->newHeight = $this->height * substr($this->newHeight, 0, -1) / 100;
|
$this->newHeight = $this->height * substr($this->newHeight, 0, -1) / 100;
|
||||||
$this->log("Setting new height based on % to {$this->newHeight}");
|
$this->log("Setting new height based on % to {$this->newHeight}");
|
||||||
}
|
}
|
||||||
@@ -1313,6 +1379,7 @@ class CImage
|
|||||||
&& !$this->autoRotate
|
&& !$this->autoRotate
|
||||||
&& !$this->bgColor
|
&& !$this->bgColor
|
||||||
&& ($this->upscale === self::UPSCALE_DEFAULT)
|
&& ($this->upscale === self::UPSCALE_DEFAULT)
|
||||||
|
&& !$this->lossy
|
||||||
) {
|
) {
|
||||||
$this->log("Using original image.");
|
$this->log("Using original image.");
|
||||||
$this->output($this->pathToImage);
|
$this->output($this->pathToImage);
|
||||||
@@ -1346,6 +1413,8 @@ class CImage
|
|||||||
$compress = $this->compress ? "_co{$this->compress}" : null;
|
$compress = $this->compress ? "_co{$this->compress}" : null;
|
||||||
$rotateBefore = $this->rotateBefore ? "_rb{$this->rotateBefore}" : null;
|
$rotateBefore = $this->rotateBefore ? "_rb{$this->rotateBefore}" : null;
|
||||||
$rotateAfter = $this->rotateAfter ? "_ra{$this->rotateAfter}" : null;
|
$rotateAfter = $this->rotateAfter ? "_ra{$this->rotateAfter}" : null;
|
||||||
|
$lossy = $this->lossy ? "_l" : null;
|
||||||
|
$interlace = $this->interlace ? "_i" : null;
|
||||||
|
|
||||||
$saveAs = $this->normalizeFileExtension();
|
$saveAs = $this->normalizeFileExtension();
|
||||||
$saveAs = $saveAs ? "_$saveAs" : null;
|
$saveAs = $saveAs ? "_$saveAs" : null;
|
||||||
@@ -1412,7 +1481,7 @@ class CImage
|
|||||||
. $quality . $filters . $sharpen . $emboss . $blur . $palette
|
. $quality . $filters . $sharpen . $emboss . $blur . $palette
|
||||||
. $optimize . $compress
|
. $optimize . $compress
|
||||||
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor
|
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor
|
||||||
. $convolve . $copyStrat . $saveAs;
|
. $convolve . $copyStrat . $lossy . $interlace . $saveAs;
|
||||||
|
|
||||||
return $this->setTarget($file, $base);
|
return $this->setTarget($file, $base);
|
||||||
}
|
}
|
||||||
@@ -1470,9 +1539,14 @@ class CImage
|
|||||||
$this->setSource($src, $dir);
|
$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) {
|
if ($this->image === false) {
|
||||||
throw new Exception("Could not load image.");
|
throw new Exception("Could not load image.");
|
||||||
}
|
}
|
||||||
@@ -2306,6 +2380,14 @@ class CImage
|
|||||||
$this->jpegOptimizeCmd = null;
|
$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']) {
|
if (isset($options['png_filter']) && $options['png_filter']) {
|
||||||
$this->pngFilterCmd = $options['png_filter_cmd'];
|
$this->pngFilterCmd = $options['png_filter_cmd'];
|
||||||
} else {
|
} else {
|
||||||
@@ -2333,9 +2415,11 @@ class CImage
|
|||||||
// switch on mimetype
|
// switch on mimetype
|
||||||
if (isset($this->extension)) {
|
if (isset($this->extension)) {
|
||||||
return strtolower($this->extension);
|
return strtolower($this->extension);
|
||||||
} else {
|
} elseif ($this->fileType === IMG_WEBP) {
|
||||||
return substr(image_type_to_extension($this->fileType), 1);
|
return "webp";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return substr(image_type_to_extension($this->fileType), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2360,8 +2444,10 @@ class CImage
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!defined("WINDOWS2WSL")) {
|
||||||
is_writable($this->saveFolder)
|
is_writable($this->saveFolder)
|
||||||
or $this->raiseError('Target directory is not writable.');
|
or $this->raiseError('Target directory is not writable.');
|
||||||
|
}
|
||||||
|
|
||||||
$type = $this->getTargetImageExtension();
|
$type = $this->getTargetImageExtension();
|
||||||
$this->Log("Saving image as " . $type);
|
$this->Log("Saving image as " . $type);
|
||||||
@@ -2369,6 +2455,12 @@ class CImage
|
|||||||
|
|
||||||
case 'jpeg':
|
case 'jpeg':
|
||||||
case 'jpg':
|
case 'jpg':
|
||||||
|
// Set as interlaced progressive JPEG
|
||||||
|
if ($this->interlace) {
|
||||||
|
$this->Log("Set JPEG image to be interlaced.");
|
||||||
|
$res = imageinterlace($this->image, true);
|
||||||
|
}
|
||||||
|
|
||||||
$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);
|
||||||
|
|
||||||
@@ -2391,6 +2483,11 @@ class CImage
|
|||||||
imagegif($this->image, $this->cacheFileName);
|
imagegif($this->image, $this->cacheFileName);
|
||||||
break;
|
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':
|
case 'png':
|
||||||
default:
|
default:
|
||||||
$this->Log("Saving image as PNG to cache using compression = {$this->compress}.");
|
$this->Log("Saving image as PNG to cache using compression = {$this->compress}.");
|
||||||
@@ -2400,6 +2497,24 @@ class CImage
|
|||||||
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 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
|
// Use external program to filter PNG, if defined
|
||||||
if ($this->pngFilterCmd) {
|
if ($this->pngFilterCmd) {
|
||||||
if ($this->verbose) {
|
if ($this->verbose) {
|
||||||
@@ -2579,6 +2694,7 @@ class CImage
|
|||||||
$format = $this->outputFormat;
|
$format = $this->outputFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->log("### Output");
|
||||||
$this->log("Output format is: $format");
|
$this->log("Output format is: $format");
|
||||||
|
|
||||||
if (!$this->verbose && $format == 'json') {
|
if (!$this->verbose && $format == 'json') {
|
||||||
@@ -2612,7 +2728,8 @@ class CImage
|
|||||||
$this->fastTrackCache->addHeader($header);
|
$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) {
|
if ($this->verbose) {
|
||||||
$this->log("304 not modified");
|
$this->log("304 not modified");
|
||||||
@@ -2627,10 +2744,8 @@ class CImage
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Get details on image
|
$this->loadImageDetails($file);
|
||||||
$info = getimagesize($file);
|
$mime = $this->getMimeType();
|
||||||
!empty($info) or $this->raiseError("The file doesn't seem to be an image.");
|
|
||||||
$mime = $info['mime'];
|
|
||||||
$size = filesize($file);
|
$size = filesize($file);
|
||||||
|
|
||||||
if ($this->verbose) {
|
if ($this->verbose) {
|
||||||
@@ -2684,18 +2799,18 @@ class CImage
|
|||||||
$lastModified = filemtime($this->pathToImage);
|
$lastModified = filemtime($this->pathToImage);
|
||||||
$details['srcGmdate'] = gmdate("D, d M Y H:i:s", $lastModified);
|
$details['srcGmdate'] = gmdate("D, d M Y H:i:s", $lastModified);
|
||||||
|
|
||||||
$details['cache'] = basename($this->cacheFileName);
|
$details['cache'] = basename($this->cacheFileName ?? "");
|
||||||
$lastModified = filemtime($this->cacheFileName);
|
$lastModified = filemtime($this->cacheFileName ?? "");
|
||||||
$details['cacheGmdate'] = gmdate("D, d M Y H:i:s", $lastModified);
|
$details['cacheGmdate'] = gmdate("D, d M Y H:i:s", $lastModified);
|
||||||
|
|
||||||
$this->load($file);
|
$this->load($file);
|
||||||
|
|
||||||
$details['filename'] = basename($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['width'] = $this->width;
|
||||||
$details['height'] = $this->height;
|
$details['height'] = $this->height;
|
||||||
$details['aspectRatio'] = round($this->width / $this->height, 3);
|
$details['aspectRatio'] = round($this->width / $this->height, 3);
|
||||||
$details['size'] = filesize($file);
|
$details['size'] = filesize($file ?? "");
|
||||||
$details['colors'] = $this->colorsTotal($this->image);
|
$details['colors'] = $this->colorsTotal($this->image);
|
||||||
$details['includedFiles'] = count(get_included_files());
|
$details['includedFiles'] = count(get_included_files());
|
||||||
$details['memoryPeek'] = round(memory_get_peak_usage()/1024/1024, 3) . " MB" ;
|
$details['memoryPeek'] = round(memory_get_peak_usage()/1024/1024, 3) . " MB" ;
|
||||||
@@ -2793,6 +2908,7 @@ class CImage
|
|||||||
private function verboseOutput()
|
private function verboseOutput()
|
||||||
{
|
{
|
||||||
$log = null;
|
$log = null;
|
||||||
|
$this->log("### Summary of verbose log");
|
||||||
$this->log("As JSON: \n" . $this->json());
|
$this->log("As JSON: \n" . $this->json());
|
||||||
$this->log("Memory peak: " . round(memory_get_peak_usage() /1024/1024) . "M");
|
$this->log("Memory peak: " . round(memory_get_peak_usage() /1024/1024) . "M");
|
||||||
$this->log("Memory limit: " . ini_get('memory_limit'));
|
$this->log("Memory limit: " . ini_get('memory_limit'));
|
||||||
|
@@ -2,8 +2,10 @@ Image conversion on the fly using PHP
|
|||||||
=====================================
|
=====================================
|
||||||
|
|
||||||
[](https://gitter.im/mosbth/cimage?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[](https://gitter.im/mosbth/cimage?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
|
<!--
|
||||||
[](https://travis-ci.org/mosbth/cimage)
|
[](https://travis-ci.org/mosbth/cimage)
|
||||||
[](https://scrutinizer-ci.com/g/mosbth/cimage/build-status/master)
|
[](https://scrutinizer-ci.com/g/mosbth/cimage/build-status/master)
|
||||||
|
-->
|
||||||
|
|
||||||
About
|
About
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
@@ -49,14 +51,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).
|
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.18 released 2016-08-09.**
|
||||||
|
|
||||||
I prefer cloning like this. Do switch to the latest stable version.
|
I prefer cloning like this. Do switch to the latest stable version.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone git://github.com/mosbth/cimage.git
|
git clone git://github.com/mosbth/cimage.git
|
||||||
cd cimage
|
cd cimage
|
||||||
git checkout v0.7.14
|
git checkout v0.7.18
|
||||||
```
|
```
|
||||||
|
|
||||||
Make the cache-directory writable by the webserver.
|
Make the cache-directory writable by the webserver.
|
||||||
@@ -79,7 +81,7 @@ There are some all-included bundles of `img.php` that can be downloaded and used
|
|||||||
Dowload the version of your choice like this.
|
Dowload the version of your choice like this.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
wget https://raw.githubusercontent.com/mosbth/cimage/v0.7.14/webroot/imgp.php
|
wget https://raw.githubusercontent.com/mosbth/cimage/v0.7.18/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.
|
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.
|
||||||
|
122
REVISION.md
@@ -1,14 +1,136 @@
|
|||||||
Revision history
|
Revision history
|
||||||
=====================================
|
=====================================
|
||||||
|
|
||||||
|
<!--
|
||||||
[](https://travis-ci.org/mosbth/cimage)
|
[](https://travis-ci.org/mosbth/cimage)
|
||||||
[](https://scrutinizer-ci.com/g/mosbth/cimage/build-status/master)
|
[](https://scrutinizer-ci.com/g/mosbth/cimage/build-status/master)
|
||||||
|
--->
|
||||||
|
|
||||||
|
v0.8.6 (2023-10-27)
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
* Fix deprecation notice on "Creation of dynamic property" for PHP 8.2.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
v0.8.5 (2022-11-17)
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
* Enable configuration fix for solving Windows 2 WSL2 issue with is_readable/is_writable #189.
|
||||||
|
* Update CHttpGet.php for php 8.1 deprecated notice #188.
|
||||||
|
* Remove build status from README (since it is not up to date).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
v0.8.4 (2022-05-30)
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
* Support PHP 8.1 and remove (more) deprecated messages when run in in development mode.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
v0.8.3 (2022-05-24)
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
* Support PHP 8.1 and remove deprecated messages when run in in development mode.
|
||||||
|
* Generate prebuilt all include files for various settings
|
||||||
|
* Fix deprecated for PHP 8.1
|
||||||
|
* Fix deprecated for PHP 8.1
|
||||||
|
* Add php version as output in verbose mode
|
||||||
|
* Add PHP 81 as test environment
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
v0.8.2 (2021-10-27)
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
* Remove bad configuration.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
v0.8.1 (2020-06-08)
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
* Updated version number in define.php.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
v0.8.0 (2020-06-08)
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
* Enable to set JPEG image as interlaced, implement feature #177.
|
||||||
|
* Add function getValue() to read from querystring.
|
||||||
|
* Set PHP 7.0 as precondition (to prepare to update the codebase).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
v0.7.23 (2020-05-06)
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
* Fix error in composer.json
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
v0.7.22 (2020-05-06)
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
* Update composer.json and move ext-gd from required to suggested to ease installation where cli does not have all extensions installed.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
v0.7.21 (2020-01-15)
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
* Support PHP 7.4, some minor fixes with notices.
|
||||||
|
|
||||||
|
|
||||||
|
v0.7.20 (2017-11-06)
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
* Remove webroot/img/{round8.PNG,wider.JPEG,wider.JPG} to avoid unzip warning message when installing with composer.
|
||||||
|
* Adding docker-compose.yml #169.
|
||||||
|
|
||||||
|
|
||||||
|
v0.7.19 (2017-03-31)
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
* Move exception handler from functions.php to img.php #166.
|
||||||
|
* Correct XSS injection in `check_system.php`.
|
||||||
|
* Composer suggests ext-imagick and ext-curl.
|
||||||
|
|
||||||
|
|
||||||
|
v0.7.18 (2016-08-09)
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
* Made `&lossless` a requirement to not use the original image.
|
||||||
|
|
||||||
|
|
||||||
|
v0.7.17 (2016-08-09)
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
* 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)
|
v0.7.14 (2016-08-08)
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
|
|
||||||
* Re-add removed cache directory.
|
* Re-add removed cache directory.
|
||||||
|
* Make fast track cache disabled by default in the config file.
|
||||||
|
|
||||||
|
|
||||||
v0.7.13 (2016-08-08)
|
v0.7.13 (2016-08-08)
|
||||||
|
6
SECURITY.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
Security policy
|
||||||
|
======================
|
||||||
|
|
||||||
|
To report security vulnerabilities in the project, send en email to mikael.t.h.roos@gmail.com.
|
||||||
|
|
||||||
|
For other security related issues, please open an issue on the project.
|
@@ -18,11 +18,13 @@
|
|||||||
"docs": "http://dbwebb.se/opensource/cimage"
|
"docs": "http://dbwebb.se/opensource/cimage"
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.3",
|
"php": ">=7.0"
|
||||||
"ext-gd": "*"
|
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-exif": "*"
|
"ext-curl": "*",
|
||||||
|
"ext-exif": "*",
|
||||||
|
"ext-gd": "*",
|
||||||
|
"ext-imagick": "*"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"files": [
|
"files": [
|
||||||
|
@@ -1,6 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
// Version of cimage and img.php
|
// Version of cimage and img.php
|
||||||
define("CIMAGE_VERSION", "v0.7.13 (2016-08-08)");
|
define("CIMAGE_VERSION", "v0.8.6 (2023-10-27)");
|
||||||
|
|
||||||
// For CRemoteImage
|
// For CRemoteImage
|
||||||
define("CIMAGE_USER_AGENT", "CImage/" . CIMAGE_VERSION);
|
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);
|
||||||
|
}
|
||||||
|
97
docker-compose.yaml
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
cli:
|
||||||
|
image: anax/dev
|
||||||
|
volumes: [ ".:/home/anax/repo" ]
|
||||||
|
|
||||||
|
apache:
|
||||||
|
image: anax/dev:apache
|
||||||
|
volumes: [ ".:/home/anax/repo" ]
|
||||||
|
ports: [ "11000:80" ]
|
||||||
|
|
||||||
|
remserver:
|
||||||
|
image: anax/dev:apache
|
||||||
|
ports:
|
||||||
|
- "8090:80"
|
||||||
|
volumes: [ ".:/home/anax/repo" ]
|
||||||
|
|
||||||
|
php82:
|
||||||
|
image: anax/dev:php82
|
||||||
|
volumes: [ ".:/home/anax/repo" ]
|
||||||
|
|
||||||
|
php82-apache:
|
||||||
|
image: anax/dev:php82-apache
|
||||||
|
ports: [ "11082:80" ]
|
||||||
|
volumes: [ ".:/home/anax/repo" ]
|
||||||
|
|
||||||
|
php81:
|
||||||
|
image: anax/dev:php81
|
||||||
|
volumes: [ ".:/home/anax/repo" ]
|
||||||
|
|
||||||
|
php81-apache:
|
||||||
|
image: anax/dev:php81-apache
|
||||||
|
ports: [ "11081:80" ]
|
||||||
|
volumes: [ ".:/home/anax/repo" ]
|
||||||
|
|
||||||
|
php80:
|
||||||
|
image: anax/dev:php80
|
||||||
|
volumes: [ ".:/home/anax/repo" ]
|
||||||
|
|
||||||
|
php80-apache:
|
||||||
|
image: anax/dev:php80-apache
|
||||||
|
ports: [ "11080:80" ]
|
||||||
|
volumes: [ ".:/home/anax/repo" ]
|
||||||
|
|
||||||
|
php74:
|
||||||
|
image: anax/dev:php74
|
||||||
|
volumes: [ ".:/home/anax/repo" ]
|
||||||
|
|
||||||
|
php74-apache:
|
||||||
|
image: anax/dev:php74-apache
|
||||||
|
ports: [ "11074:80" ]
|
||||||
|
volumes: [ ".:/home/anax/repo" ]
|
||||||
|
|
||||||
|
php73:
|
||||||
|
image: anax/dev:php73
|
||||||
|
volumes: [ ".:/home/anax/repo" ]
|
||||||
|
|
||||||
|
php73-apache:
|
||||||
|
image: anax/dev:php73-apache
|
||||||
|
ports: [ "11073:80" ]
|
||||||
|
volumes: [ ".:/home/anax/repo" ]
|
||||||
|
|
||||||
|
php72:
|
||||||
|
image: anax/dev:php72
|
||||||
|
volumes: [ ".:/home/anax/repo" ]
|
||||||
|
|
||||||
|
php72-apache:
|
||||||
|
image: anax/dev:php72-apache
|
||||||
|
ports: [ "11072:80" ]
|
||||||
|
volumes: [ ".:/home/anax/repo" ]
|
||||||
|
|
||||||
|
php71:
|
||||||
|
image: anax/dev:php71
|
||||||
|
volumes: [ ".:/home/anax/repo" ]
|
||||||
|
|
||||||
|
php71-apache:
|
||||||
|
image: anax/dev:php71-apache
|
||||||
|
ports: [ "11071:80" ]
|
||||||
|
volumes: [ ".:/home/anax/repo" ]
|
||||||
|
|
||||||
|
php70:
|
||||||
|
image: anax/dev:php70
|
||||||
|
volumes: [ ".:/home/anax/repo" ]
|
||||||
|
|
||||||
|
php70:
|
||||||
|
image: anax/dev:php70-apache
|
||||||
|
ports: [ "11070:80" ]
|
||||||
|
volumes: [ ".:/home/anax/repo" ]
|
||||||
|
|
||||||
|
php56:
|
||||||
|
image: anax/dev:php56
|
||||||
|
volumes: [ ".:/home/anax/repo" ]
|
||||||
|
|
||||||
|
php56:
|
||||||
|
image: anax/dev:php56-apache
|
||||||
|
ports: [ "11056:80" ]
|
||||||
|
volumes: [ ".:/home/anax/repo" ]
|
@@ -67,22 +67,6 @@ function errorPage($msg, $type = 500)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom exception handler.
|
|
||||||
*/
|
|
||||||
set_exception_handler(function ($exception) {
|
|
||||||
errorPage(
|
|
||||||
"<p><b>img.php: Uncaught exception:</b> <p>"
|
|
||||||
. $exception->getMessage()
|
|
||||||
. "</p><pre>"
|
|
||||||
. $exception->getTraceAsString()
|
|
||||||
. "</pre>",
|
|
||||||
500
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get input from query string or return default value if not set.
|
* Get input from query string or return default value if not set.
|
||||||
*
|
*
|
||||||
@@ -123,6 +107,25 @@ function getDefined($key, $defined, $undefined)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get value of input from query string or else $undefined.
|
||||||
|
*
|
||||||
|
* @param mixed $key as string or array of string values to look for in $_GET.
|
||||||
|
* @param mixed $undefined value to return when $key has no, or empty value in $_GET.
|
||||||
|
*
|
||||||
|
* @return mixed value as or $undefined.
|
||||||
|
*/
|
||||||
|
function getValue($key, $undefined)
|
||||||
|
{
|
||||||
|
$val = get($key);
|
||||||
|
if (is_null($val) || $val === "") {
|
||||||
|
return $undefined;
|
||||||
|
}
|
||||||
|
return $val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get value from config array or default if key is not set in config array.
|
* Get value from config array or default if key is not set in config array.
|
||||||
*
|
*
|
||||||
@@ -148,7 +151,7 @@ function getConfig($key, $default)
|
|||||||
*
|
*
|
||||||
* @return void or array.
|
* @return void or array.
|
||||||
*/
|
*/
|
||||||
function verbose($msg = null)
|
function verbose($msg = null, $arg = "")
|
||||||
{
|
{
|
||||||
global $verbose, $verboseFile;
|
global $verbose, $verboseFile;
|
||||||
static $log = array();
|
static $log = array();
|
||||||
@@ -161,5 +164,34 @@ function verbose($msg = null)
|
|||||||
return $log;
|
return $log;
|
||||||
}
|
}
|
||||||
|
|
||||||
$log[] = $msg;
|
if (is_null($arg)) {
|
||||||
|
$arg = "null";
|
||||||
|
} elseif ($arg === false) {
|
||||||
|
$arg = "false";
|
||||||
|
} elseif ($arg === true) {
|
||||||
|
$arg = "true";
|
||||||
|
}
|
||||||
|
|
||||||
|
$log[] = $msg . $arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
echo 'Current PHP version: ' . phpversion() . '<br><br>';
|
echo 'Current PHP version: ' . phpversion() . '<br><br>';
|
||||||
|
|
||||||
echo 'Running on: ' . $_SERVER['SERVER_SOFTWARE'] . '<br><br>';
|
echo 'Running on: ' . htmlentities($_SERVER['SERVER_SOFTWARE']) . '<br><br>';
|
||||||
|
|
||||||
$no = extension_loaded('exif') ? null : 'NOT';
|
$no = extension_loaded('exif') ? null : 'NOT';
|
||||||
echo "Extension exif is $no loaded.<br>";
|
echo "Extension exif is $no loaded.<br>";
|
||||||
@@ -15,13 +15,15 @@ echo "Extension imagick is $no loaded.<br>";
|
|||||||
|
|
||||||
$no = extension_loaded('gd') ? null : 'NOT';
|
$no = extension_loaded('gd') ? null : 'NOT';
|
||||||
echo "Extension gd is $no loaded.<br>";
|
echo "Extension gd is $no loaded.<br>";
|
||||||
|
|
||||||
if (!$no) {
|
if (!$no) {
|
||||||
echo "<pre>", var_dump(gd_info()), "</pre>";
|
echo "<pre>", var_dump(gd_info()), "</pre>";
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "<strong>Checking path for postprocessing tools</strong>";
|
echo "<strong>Checking path for postprocessing tools</strong>";
|
||||||
|
|
||||||
|
echo "<br>pngquant: ";
|
||||||
|
system("which pngquant");
|
||||||
|
|
||||||
echo "<br>optipng: ";
|
echo "<br>optipng: ";
|
||||||
system("which optipng");
|
system("which optipng");
|
||||||
|
|
||||||
|
@@ -3,6 +3,12 @@
|
|||||||
<head>
|
<head>
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
function e($str) {
|
||||||
|
return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
body {
|
body {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,15 +134,15 @@ if (isset($_GET['input1'])) {
|
|||||||
// Use incoming from querystring as defaults
|
// Use incoming from querystring as defaults
|
||||||
?>
|
?>
|
||||||
CImage.compare({
|
CImage.compare({
|
||||||
"input1": "<?=$_GET['input1']?>",
|
"input1": "<?=e($_GET['input1'])?>",
|
||||||
"input2": "<?=$_GET['input2']?>",
|
"input2": "<?=e($_GET['input2'])?>",
|
||||||
"input3": "<?=$_GET['input3']?>",
|
"input3": "<?=e($_GET['input3'])?>",
|
||||||
"input4": "<?=$_GET['input4']?>",
|
"input4": "<?=e($_GET['input4'])?>",
|
||||||
"input5": "<?=$_GET['input5']?>",
|
"input5": "<?=e($_GET['input5'])?>",
|
||||||
"input6": "<?=$_GET['input6']?>",
|
"input6": "<?=e($_GET['input6'])?>",
|
||||||
"json": <?=$_GET['json']?>,
|
"json": <?=e($_GET['json'])?>,
|
||||||
"stack": <?=$_GET['stack']?>,
|
"stack": <?=e($_GET['stack'])?>,
|
||||||
"bg": <?=$_GET['bg']?>
|
"bg": <?=e($_GET['bg'])?>
|
||||||
});
|
});
|
||||||
<?php
|
<?php
|
||||||
} elseif (isset($script)) {
|
} elseif (isset($script)) {
|
||||||
|
@@ -8,6 +8,22 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom exception handler.
|
||||||
|
*/
|
||||||
|
set_exception_handler(function ($exception) {
|
||||||
|
errorPage(
|
||||||
|
"<p><b>img.php: Uncaught exception:</b> <p>"
|
||||||
|
. $exception->getMessage()
|
||||||
|
. "</p><pre>"
|
||||||
|
. $exception->getTraceAsString()
|
||||||
|
. "</pre>",
|
||||||
|
500
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get configuration options from file, if the file exists, else use $config
|
* Get configuration options from file, if the file exists, else use $config
|
||||||
* if its defined or create an empty $config.
|
* if its defined or create an empty $config.
|
||||||
@@ -170,7 +186,7 @@ $hotlinkingWhitelist = getConfig('hotlinking_whitelist', array());
|
|||||||
|
|
||||||
$serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null;
|
$serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null;
|
||||||
$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
|
$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
|
||||||
$refererHost = parse_url($referer, PHP_URL_HOST);
|
$refererHost = parse_url($referer ?? "", PHP_URL_HOST);
|
||||||
|
|
||||||
if (!$allowHotlinking) {
|
if (!$allowHotlinking) {
|
||||||
if ($passwordMatch) {
|
if ($passwordMatch) {
|
||||||
@@ -303,11 +319,11 @@ if (isset($shortcut)
|
|||||||
/**
|
/**
|
||||||
* src - the source image file.
|
* src - the source image file.
|
||||||
*/
|
*/
|
||||||
$srcImage = urldecode(get('src'))
|
$srcImage = urldecode(get('src', ""))
|
||||||
or errorPage('Must set src-attribute.', 404);
|
or errorPage('Must set src-attribute.', 404);
|
||||||
|
|
||||||
// Get settings for src-alt as backup image
|
// Get settings for src-alt as backup image
|
||||||
$srcAltImage = urldecode(get('src-alt', null));
|
$srcAltImage = urldecode(get('src-alt', ""));
|
||||||
$srcAltConfig = getConfig('src_alt', null);
|
$srcAltConfig = getConfig('src_alt', null);
|
||||||
if (empty($srcAltImage)) {
|
if (empty($srcAltImage)) {
|
||||||
$srcAltImage = $srcAltConfig;
|
$srcAltImage = $srcAltConfig;
|
||||||
@@ -424,7 +440,7 @@ if (isset($sizes[$newWidth])) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Support width as % of original width
|
// Support width as % of original width
|
||||||
if ($newWidth[strlen($newWidth)-1] == '%') {
|
if ($newWidth && $newWidth[strlen($newWidth)-1] == '%') {
|
||||||
is_numeric(substr($newWidth, 0, -1))
|
is_numeric(substr($newWidth, 0, -1))
|
||||||
or errorPage('Width % not numeric.', 404);
|
or errorPage('Width % not numeric.', 404);
|
||||||
} else {
|
} else {
|
||||||
@@ -449,7 +465,7 @@ if (isset($sizes[$newHeight])) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// height
|
// height
|
||||||
if ($newHeight[strlen($newHeight)-1] == '%') {
|
if ($newHeight && $newHeight[strlen($newHeight)-1] == '%') {
|
||||||
is_numeric(substr($newHeight, 0, -1))
|
is_numeric(substr($newHeight, 0, -1))
|
||||||
or errorPage('Height % out of range.', 404);
|
or errorPage('Height % out of range.', 404);
|
||||||
} else {
|
} else {
|
||||||
@@ -480,7 +496,7 @@ $aspectRatioConstant = getConfig('aspect_ratio_constant', function () {
|
|||||||
|
|
||||||
// Check to replace predefined aspect ratio
|
// Check to replace predefined aspect ratio
|
||||||
$aspectRatios = call_user_func($aspectRatioConstant);
|
$aspectRatios = call_user_func($aspectRatioConstant);
|
||||||
$negateAspectRatio = ($aspectRatio[0] == '!') ? true : false;
|
$negateAspectRatio = ($aspectRatio && $aspectRatio[0] == '!') ? true : false;
|
||||||
$aspectRatio = $negateAspectRatio ? substr($aspectRatio, 1) : $aspectRatio;
|
$aspectRatio = $negateAspectRatio ? substr($aspectRatio, 1) : $aspectRatio;
|
||||||
|
|
||||||
if (isset($aspectRatios[$aspectRatio])) {
|
if (isset($aspectRatios[$aspectRatio])) {
|
||||||
@@ -840,6 +856,9 @@ verbose("upscale = $upscale");
|
|||||||
* Get details for post processing
|
* Get details for post processing
|
||||||
*/
|
*/
|
||||||
$postProcessing = getConfig('postprocessing', array(
|
$postProcessing = getConfig('postprocessing', array(
|
||||||
|
'png_lossy' => false,
|
||||||
|
'png_lossy_cmd' => '/usr/local/bin/pngquant --force --output',
|
||||||
|
|
||||||
'png_filter' => false,
|
'png_filter' => false,
|
||||||
'png_filter_cmd' => '/usr/local/bin/optipng -q',
|
'png_filter_cmd' => '/usr/local/bin/optipng -q',
|
||||||
|
|
||||||
@@ -852,6 +871,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.
|
* alias - Save resulting image to another alias name.
|
||||||
* Password always apply, must be defined.
|
* Password always apply, must be defined.
|
||||||
@@ -892,6 +920,18 @@ if ($cacheControl) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* interlace - Enable configuration for interlaced progressive JPEG images.
|
||||||
|
*/
|
||||||
|
$interlaceConfig = getConfig('interlace', null);
|
||||||
|
$interlaceValue = getValue('interlace', null);
|
||||||
|
$interlaceDefined = getDefined('interlace', true, null);
|
||||||
|
$interlace = $interlaceValue ?? $interlaceDefined ?? $interlaceConfig;
|
||||||
|
verbose("interlace (configfile) = ", $interlaceConfig);
|
||||||
|
verbose("interlace = ", $interlace);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare a dummy image and use it as source image.
|
* Prepare a dummy image and use it as source image.
|
||||||
*/
|
*/
|
||||||
@@ -970,7 +1010,7 @@ if ($status) {
|
|||||||
$res = $cache->getStatusOfSubdir("srgb");
|
$res = $cache->getStatusOfSubdir("srgb");
|
||||||
$text .= "Cache srgb $res\n";
|
$text .= "Cache srgb $res\n";
|
||||||
|
|
||||||
$res = $cache->getStatusOfSubdir($fasttrackCache);
|
$res = $cache->getStatusOfSubdir($fastTrackCache);
|
||||||
$text .= "Cache fasttrack $res\n";
|
$text .= "Cache fasttrack $res\n";
|
||||||
|
|
||||||
$text .= "Alias path writable = " . is_writable($aliasPath) . "\n";
|
$text .= "Alias path writable = " . is_writable($aliasPath) . "\n";
|
||||||
@@ -987,6 +1027,11 @@ if ($status) {
|
|||||||
$no = extension_loaded('gd') ? null : 'NOT';
|
$no = extension_loaded('gd') ? null : 'NOT';
|
||||||
$text .= "Extension gd is $no loaded.<br>";
|
$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) {
|
if (!$no) {
|
||||||
$text .= print_r(gd_info(), 1);
|
$text .= print_r(gd_info(), 1);
|
||||||
}
|
}
|
||||||
@@ -1048,6 +1093,7 @@ if (is_callable($hookBeforeCImage)) {
|
|||||||
'blur' => $blur,
|
'blur' => $blur,
|
||||||
'convolve' => $convolve,
|
'convolve' => $convolve,
|
||||||
'rotateAfter' => $rotateAfter,
|
'rotateAfter' => $rotateAfter,
|
||||||
|
'interlace' => $interlace,
|
||||||
|
|
||||||
// Output format
|
// Output format
|
||||||
'outputFormat' => $outputFormat,
|
'outputFormat' => $outputFormat,
|
||||||
@@ -1055,6 +1101,7 @@ if (is_callable($hookBeforeCImage)) {
|
|||||||
|
|
||||||
// Other
|
// Other
|
||||||
'postProcessing' => $postProcessing,
|
'postProcessing' => $postProcessing,
|
||||||
|
'lossy' => $lossy,
|
||||||
));
|
));
|
||||||
verbose(print_r($allConfig, 1));
|
verbose(print_r($allConfig, 1));
|
||||||
extract($allConfig);
|
extract($allConfig);
|
||||||
@@ -1102,7 +1149,8 @@ EOD;
|
|||||||
/**
|
/**
|
||||||
* Load, process and output the image
|
* Load, process and output the image
|
||||||
*/
|
*/
|
||||||
$img->log("Incoming arguments: " . print_r(verbose(), 1))
|
$img->log("PHP version: " . phpversion())
|
||||||
|
->log("Incoming arguments: " . print_r(verbose(), 1))
|
||||||
->setSaveFolder($cachePath)
|
->setSaveFolder($cachePath)
|
||||||
->useCache($useCache)
|
->useCache($useCache)
|
||||||
->setSource($srcImage, $imagePath)
|
->setSource($srcImage, $imagePath)
|
||||||
@@ -1135,10 +1183,14 @@ $img->log("Incoming arguments: " . print_r(verbose(), 1))
|
|||||||
'blur' => $blur,
|
'blur' => $blur,
|
||||||
'convolve' => $convolve,
|
'convolve' => $convolve,
|
||||||
'rotateAfter' => $rotateAfter,
|
'rotateAfter' => $rotateAfter,
|
||||||
|
'interlace' => $interlace,
|
||||||
|
|
||||||
// Output format
|
// Output format
|
||||||
'outputFormat' => $outputFormat,
|
'outputFormat' => $outputFormat,
|
||||||
'dpr' => $dpr,
|
'dpr' => $dpr,
|
||||||
|
|
||||||
|
// Postprocessing using external tools
|
||||||
|
'lossy' => $lossy,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
->loadImageDetails()
|
->loadImageDetails()
|
||||||
|
BIN
webroot/img/duke.png
Normal file
After Width: | Height: | Size: 228 KiB |
BIN
webroot/img/lena.jpg
Normal file
After Width: | Height: | Size: 395 KiB |
BIN
webroot/img/lena.png
Normal file
After Width: | Height: | Size: 464 KiB |
BIN
webroot/img/lena.tif
Normal file
BIN
webroot/img/lena.webp
Normal file
After Width: | Height: | Size: 131 KiB |
Before Width: | Height: | Size: 6.2 KiB |
BIN
webroot/img/webp/1.webp
Normal file
After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 70 KiB |
Before Width: | Height: | Size: 70 KiB |
@@ -21,6 +21,15 @@ if (!defined("CIMAGE_DEBUG")) {
|
|||||||
define("CIMAGE_DEBUG_FILE", "/tmp/cimage");
|
define("CIMAGE_DEBUG_FILE", "/tmp/cimage");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set this if you work with a webserver in Windows and try to access files
|
||||||
|
* within WSL2.
|
||||||
|
* The issue seems to be with functions like `is_writable()` and
|
||||||
|
* `is_readable()`.
|
||||||
|
* When WINDOWS2WSL is defined (to any value) it ignores these functions.
|
||||||
|
*/
|
||||||
|
#define('WINDOWS2WSL', 1);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
@@ -41,7 +50,7 @@ return array(
|
|||||||
* mode: 'production'
|
* mode: 'production'
|
||||||
*/
|
*/
|
||||||
//'mode' => 'production',
|
//'mode' => 'production',
|
||||||
//'mode' => 'development',
|
'mode' => 'development',
|
||||||
//'mode' => 'strict',
|
//'mode' => 'strict',
|
||||||
|
|
||||||
|
|
||||||
@@ -67,7 +76,7 @@ return array(
|
|||||||
*/
|
*/
|
||||||
'image_path' => __DIR__ . '/img/',
|
'image_path' => __DIR__ . '/img/',
|
||||||
'cache_path' => __DIR__ . '/../cache/',
|
'cache_path' => __DIR__ . '/../cache/',
|
||||||
//'alias_path' => __DIR__ . '/img/alias/',
|
'alias_path' => __DIR__ . '/img/alias/',
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -116,7 +125,7 @@ return array(
|
|||||||
* password_type: 'text' // use plain password, not encoded,
|
* password_type: 'text' // use plain password, not encoded,
|
||||||
*/
|
*/
|
||||||
//'password_always' => false, // always require password,
|
//'password_always' => false, // always require password,
|
||||||
//'password' => false, // "secret-password",
|
//'password' => "moped", // "secret-password",
|
||||||
//'password_type' => 'text', // supports 'text', 'md5', 'hash',
|
//'password_type' => 'text', // supports 'text', 'md5', 'hash',
|
||||||
|
|
||||||
|
|
||||||
@@ -321,8 +330,16 @@ 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.
|
||||||
*
|
*
|
||||||
|
* 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.
|
* Default values.
|
||||||
*
|
*
|
||||||
|
* png_lossy: false
|
||||||
|
* png_lossy_cmd: '/usr/local/bin/pngquant --force --output'
|
||||||
|
*
|
||||||
* png_filter: false
|
* png_filter: false
|
||||||
* png_filter_cmd: '/usr/local/bin/optipng -q'
|
* png_filter_cmd: '/usr/local/bin/optipng -q'
|
||||||
*
|
*
|
||||||
@@ -334,6 +351,9 @@ return array(
|
|||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
'postprocessing' => array(
|
'postprocessing' => array(
|
||||||
|
'png_lossy' => null,
|
||||||
|
'png_lossy_cmd' => '/usr/local/bin/pngquant --force --output',
|
||||||
|
|
||||||
'png_filter' => false,
|
'png_filter' => false,
|
||||||
'png_filter_cmd' => '/usr/local/bin/optipng -q',
|
'png_filter_cmd' => '/usr/local/bin/optipng -q',
|
||||||
|
|
||||||
@@ -474,6 +494,18 @@ return array(
|
|||||||
"scale" => 14,
|
"scale" => 14,
|
||||||
"luminanceStrategy" => 3,
|
"luminanceStrategy" => 3,
|
||||||
"customCharacterSet" => null,
|
"customCharacterSet" => null,
|
||||||
);
|
), */
|
||||||
},*/
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default options for creating interlaced progressive JPEG images. Set
|
||||||
|
* to true to always render jpeg images as interlaced. This setting can
|
||||||
|
* be overridden by using `?interlace`, `?interlace=true` or
|
||||||
|
* `?interlace=false`.
|
||||||
|
*
|
||||||
|
* Default values are:
|
||||||
|
* interlace: false
|
||||||
|
*/
|
||||||
|
/*'interlace' => false,*/
|
||||||
);
|
);
|
||||||
|
322
webroot/imgd.php
@@ -38,11 +38,16 @@ $config = array(
|
|||||||
|
|
||||||
|
|
||||||
// Version of cimage and img.php
|
// Version of cimage and img.php
|
||||||
define("CIMAGE_VERSION", "v0.7.13 (2016-08-08)");
|
define("CIMAGE_VERSION", "v0.8.6 (2023-10-27)");
|
||||||
|
|
||||||
// For CRemoteImage
|
// For CRemoteImage
|
||||||
define("CIMAGE_USER_AGENT", "CImage/" . CIMAGE_VERSION);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -113,22 +118,6 @@ function errorPage($msg, $type = 500)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom exception handler.
|
|
||||||
*/
|
|
||||||
set_exception_handler(function ($exception) {
|
|
||||||
errorPage(
|
|
||||||
"<p><b>img.php: Uncaught exception:</b> <p>"
|
|
||||||
. $exception->getMessage()
|
|
||||||
. "</p><pre>"
|
|
||||||
. $exception->getTraceAsString()
|
|
||||||
. "</pre>",
|
|
||||||
500
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get input from query string or return default value if not set.
|
* Get input from query string or return default value if not set.
|
||||||
*
|
*
|
||||||
@@ -169,6 +158,25 @@ function getDefined($key, $defined, $undefined)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get value of input from query string or else $undefined.
|
||||||
|
*
|
||||||
|
* @param mixed $key as string or array of string values to look for in $_GET.
|
||||||
|
* @param mixed $undefined value to return when $key has no, or empty value in $_GET.
|
||||||
|
*
|
||||||
|
* @return mixed value as or $undefined.
|
||||||
|
*/
|
||||||
|
function getValue($key, $undefined)
|
||||||
|
{
|
||||||
|
$val = get($key);
|
||||||
|
if (is_null($val) || $val === "") {
|
||||||
|
return $undefined;
|
||||||
|
}
|
||||||
|
return $val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get value from config array or default if key is not set in config array.
|
* Get value from config array or default if key is not set in config array.
|
||||||
*
|
*
|
||||||
@@ -194,7 +202,7 @@ function getConfig($key, $default)
|
|||||||
*
|
*
|
||||||
* @return void or array.
|
* @return void or array.
|
||||||
*/
|
*/
|
||||||
function verbose($msg = null)
|
function verbose($msg = null, $arg = "")
|
||||||
{
|
{
|
||||||
global $verbose, $verboseFile;
|
global $verbose, $verboseFile;
|
||||||
static $log = array();
|
static $log = array();
|
||||||
@@ -207,7 +215,36 @@ function verbose($msg = null)
|
|||||||
return $log;
|
return $log;
|
||||||
}
|
}
|
||||||
|
|
||||||
$log[] = $msg;
|
if (is_null($arg)) {
|
||||||
|
$arg = "null";
|
||||||
|
} elseif ($arg === false) {
|
||||||
|
$arg = "false";
|
||||||
|
} elseif ($arg === true) {
|
||||||
|
$arg = "true";
|
||||||
|
}
|
||||||
|
|
||||||
|
$log[] = $msg . $arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -428,7 +465,7 @@ class CHttpGet
|
|||||||
{
|
{
|
||||||
$type = isset($this->response['header']['Content-Type'])
|
$type = isset($this->response['header']['Content-Type'])
|
||||||
? $this->response['header']['Content-Type']
|
? $this->response['header']['Content-Type']
|
||||||
: null;
|
: '';
|
||||||
|
|
||||||
return preg_match('#[a-z]+/[a-z]+#', $type)
|
return preg_match('#[a-z]+/[a-z]+#', $type)
|
||||||
? $type
|
? $type
|
||||||
@@ -1106,6 +1143,7 @@ class CAsciiArt
|
|||||||
* @example http://dbwebb.se/opensource/cimage
|
* @example http://dbwebb.se/opensource/cimage
|
||||||
* @link https://github.com/mosbth/cimage
|
* @link https://github.com/mosbth/cimage
|
||||||
*/
|
*/
|
||||||
|
#[AllowDynamicProperties]
|
||||||
class CImage
|
class CImage
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -1255,6 +1293,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
|
* Verbose mode to print out a trace and display the created image
|
||||||
*/
|
*/
|
||||||
@@ -1290,7 +1335,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 $pngFilter;
|
||||||
private $pngFilterCmd;
|
private $pngFilterCmd;
|
||||||
@@ -1298,7 +1351,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 $pngDeflate;
|
||||||
private $pngDeflateCmd;
|
private $pngDeflateCmd;
|
||||||
@@ -1508,6 +1561,13 @@ class CImage
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use interlaced progressive mode for JPEG images.
|
||||||
|
*/
|
||||||
|
private $interlace = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Image copy strategy, defaults to RESAMPLE.
|
* Image copy strategy, defaults to RESAMPLE.
|
||||||
*/
|
*/
|
||||||
@@ -1740,7 +1800,7 @@ class CImage
|
|||||||
*/
|
*/
|
||||||
private function checkFileExtension($extension)
|
private function checkFileExtension($extension)
|
||||||
{
|
{
|
||||||
$valid = array('jpg', 'jpeg', 'png', 'gif');
|
$valid = array('jpg', 'jpeg', 'png', 'gif', 'webp');
|
||||||
|
|
||||||
in_array(strtolower($extension), $valid)
|
in_array(strtolower($extension), $valid)
|
||||||
or $this->raiseError('Not a valid file extension.');
|
or $this->raiseError('Not a valid file extension.');
|
||||||
@@ -1757,9 +1817,9 @@ class CImage
|
|||||||
*
|
*
|
||||||
* @return string $extension as a normalized file extension.
|
* @return string $extension as a normalized file extension.
|
||||||
*/
|
*/
|
||||||
private function normalizeFileExtension($extension = null)
|
private function normalizeFileExtension($extension = "")
|
||||||
{
|
{
|
||||||
$extension = strtolower($extension ? $extension : $this->extension);
|
$extension = strtolower($extension ? $extension : $this->extension ?? "");
|
||||||
|
|
||||||
if ($extension == 'jpeg') {
|
if ($extension == 'jpeg') {
|
||||||
$extension = 'jpg';
|
$extension = 'jpg';
|
||||||
@@ -1923,10 +1983,14 @@ class CImage
|
|||||||
'blur' => null,
|
'blur' => null,
|
||||||
'convolve' => null,
|
'convolve' => null,
|
||||||
'rotateAfter' => null,
|
'rotateAfter' => null,
|
||||||
|
'interlace' => null,
|
||||||
|
|
||||||
// Output format
|
// Output format
|
||||||
'outputFormat' => null,
|
'outputFormat' => null,
|
||||||
'dpr' => 1,
|
'dpr' => 1,
|
||||||
|
|
||||||
|
// Postprocessing using external tools
|
||||||
|
'lossy' => null,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Convert crop settings from string to array
|
// Convert crop settings from string to array
|
||||||
@@ -2038,20 +2102,40 @@ class CImage
|
|||||||
{
|
{
|
||||||
$file = $file ? $file : $this->pathToImage;
|
$file = $file ? $file : $this->pathToImage;
|
||||||
|
|
||||||
|
// Special case to solve Windows 2 WSL integration
|
||||||
|
if (!defined('WINDOWS2WSL')) {
|
||||||
is_readable($file)
|
is_readable($file)
|
||||||
or $this->raiseError('Image file does not exist.');
|
or $this->raiseError('Image file does not exist.');
|
||||||
|
}
|
||||||
|
|
||||||
// Get details on image
|
$info = list($this->width, $this->height, $this->fileType) = getimagesize($file);
|
||||||
$info = list($this->width, $this->height, $this->fileType, $this->attr) = getimagesize($file);
|
|
||||||
if (empty($info)) {
|
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) {
|
if ($this->verbose) {
|
||||||
$this->log("Loading image details for: {$file}");
|
$this->log("Loading image details for: {$file}");
|
||||||
$this->log(" Image width x height (type): {$this->width} x {$this->height} ({$this->fileType}).");
|
$this->log(" Image width x height (type): {$this->width} x {$this->height} ({$this->fileType}).");
|
||||||
$this->log(" Image filesize: " . filesize($file) . " bytes.");
|
$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;
|
return $this;
|
||||||
@@ -2059,6 +2143,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
|
* Init new width and height and do some sanity checks on constraints, before any
|
||||||
* processing can be done.
|
* processing can be done.
|
||||||
@@ -2071,13 +2172,15 @@ class CImage
|
|||||||
$this->log("Init dimension (before) newWidth x newHeight is {$this->newWidth} x {$this->newHeight}.");
|
$this->log("Init dimension (before) newWidth x newHeight is {$this->newWidth} x {$this->newHeight}.");
|
||||||
|
|
||||||
// width as %
|
// width as %
|
||||||
if ($this->newWidth[strlen($this->newWidth)-1] == '%') {
|
if ($this->newWidth
|
||||||
|
&& $this->newWidth[strlen($this->newWidth)-1] == '%') {
|
||||||
$this->newWidth = $this->width * substr($this->newWidth, 0, -1) / 100;
|
$this->newWidth = $this->width * substr($this->newWidth, 0, -1) / 100;
|
||||||
$this->log("Setting new width based on % to {$this->newWidth}");
|
$this->log("Setting new width based on % to {$this->newWidth}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// height as %
|
// height as %
|
||||||
if ($this->newHeight[strlen($this->newHeight)-1] == '%') {
|
if ($this->newHeight
|
||||||
|
&& $this->newHeight[strlen($this->newHeight)-1] == '%') {
|
||||||
$this->newHeight = $this->height * substr($this->newHeight, 0, -1) / 100;
|
$this->newHeight = $this->height * substr($this->newHeight, 0, -1) / 100;
|
||||||
$this->log("Setting new height based on % to {$this->newHeight}");
|
$this->log("Setting new height based on % to {$this->newHeight}");
|
||||||
}
|
}
|
||||||
@@ -2413,6 +2516,7 @@ class CImage
|
|||||||
&& !$this->autoRotate
|
&& !$this->autoRotate
|
||||||
&& !$this->bgColor
|
&& !$this->bgColor
|
||||||
&& ($this->upscale === self::UPSCALE_DEFAULT)
|
&& ($this->upscale === self::UPSCALE_DEFAULT)
|
||||||
|
&& !$this->lossy
|
||||||
) {
|
) {
|
||||||
$this->log("Using original image.");
|
$this->log("Using original image.");
|
||||||
$this->output($this->pathToImage);
|
$this->output($this->pathToImage);
|
||||||
@@ -2446,6 +2550,8 @@ class CImage
|
|||||||
$compress = $this->compress ? "_co{$this->compress}" : null;
|
$compress = $this->compress ? "_co{$this->compress}" : null;
|
||||||
$rotateBefore = $this->rotateBefore ? "_rb{$this->rotateBefore}" : null;
|
$rotateBefore = $this->rotateBefore ? "_rb{$this->rotateBefore}" : null;
|
||||||
$rotateAfter = $this->rotateAfter ? "_ra{$this->rotateAfter}" : null;
|
$rotateAfter = $this->rotateAfter ? "_ra{$this->rotateAfter}" : null;
|
||||||
|
$lossy = $this->lossy ? "_l" : null;
|
||||||
|
$interlace = $this->interlace ? "_i" : null;
|
||||||
|
|
||||||
$saveAs = $this->normalizeFileExtension();
|
$saveAs = $this->normalizeFileExtension();
|
||||||
$saveAs = $saveAs ? "_$saveAs" : null;
|
$saveAs = $saveAs ? "_$saveAs" : null;
|
||||||
@@ -2512,7 +2618,7 @@ class CImage
|
|||||||
. $quality . $filters . $sharpen . $emboss . $blur . $palette
|
. $quality . $filters . $sharpen . $emboss . $blur . $palette
|
||||||
. $optimize . $compress
|
. $optimize . $compress
|
||||||
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor
|
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor
|
||||||
. $convolve . $copyStrat . $saveAs;
|
. $convolve . $copyStrat . $lossy . $interlace . $saveAs;
|
||||||
|
|
||||||
return $this->setTarget($file, $base);
|
return $this->setTarget($file, $base);
|
||||||
}
|
}
|
||||||
@@ -2570,9 +2676,14 @@ class CImage
|
|||||||
$this->setSource($src, $dir);
|
$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) {
|
if ($this->image === false) {
|
||||||
throw new Exception("Could not load image.");
|
throw new Exception("Could not load image.");
|
||||||
}
|
}
|
||||||
@@ -3406,6 +3517,14 @@ class CImage
|
|||||||
$this->jpegOptimizeCmd = null;
|
$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']) {
|
if (isset($options['png_filter']) && $options['png_filter']) {
|
||||||
$this->pngFilterCmd = $options['png_filter_cmd'];
|
$this->pngFilterCmd = $options['png_filter_cmd'];
|
||||||
} else {
|
} else {
|
||||||
@@ -3433,9 +3552,11 @@ class CImage
|
|||||||
// switch on mimetype
|
// switch on mimetype
|
||||||
if (isset($this->extension)) {
|
if (isset($this->extension)) {
|
||||||
return strtolower($this->extension);
|
return strtolower($this->extension);
|
||||||
} else {
|
} elseif ($this->fileType === IMG_WEBP) {
|
||||||
return substr(image_type_to_extension($this->fileType), 1);
|
return "webp";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return substr(image_type_to_extension($this->fileType), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -3460,8 +3581,10 @@ class CImage
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!defined("WINDOWS2WSL")) {
|
||||||
is_writable($this->saveFolder)
|
is_writable($this->saveFolder)
|
||||||
or $this->raiseError('Target directory is not writable.');
|
or $this->raiseError('Target directory is not writable.');
|
||||||
|
}
|
||||||
|
|
||||||
$type = $this->getTargetImageExtension();
|
$type = $this->getTargetImageExtension();
|
||||||
$this->Log("Saving image as " . $type);
|
$this->Log("Saving image as " . $type);
|
||||||
@@ -3469,6 +3592,12 @@ class CImage
|
|||||||
|
|
||||||
case 'jpeg':
|
case 'jpeg':
|
||||||
case 'jpg':
|
case 'jpg':
|
||||||
|
// Set as interlaced progressive JPEG
|
||||||
|
if ($this->interlace) {
|
||||||
|
$this->Log("Set JPEG image to be interlaced.");
|
||||||
|
$res = imageinterlace($this->image, true);
|
||||||
|
}
|
||||||
|
|
||||||
$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);
|
||||||
|
|
||||||
@@ -3491,6 +3620,11 @@ class CImage
|
|||||||
imagegif($this->image, $this->cacheFileName);
|
imagegif($this->image, $this->cacheFileName);
|
||||||
break;
|
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':
|
case 'png':
|
||||||
default:
|
default:
|
||||||
$this->Log("Saving image as PNG to cache using compression = {$this->compress}.");
|
$this->Log("Saving image as PNG to cache using compression = {$this->compress}.");
|
||||||
@@ -3500,6 +3634,24 @@ class CImage
|
|||||||
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 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
|
// Use external program to filter PNG, if defined
|
||||||
if ($this->pngFilterCmd) {
|
if ($this->pngFilterCmd) {
|
||||||
if ($this->verbose) {
|
if ($this->verbose) {
|
||||||
@@ -3679,6 +3831,7 @@ class CImage
|
|||||||
$format = $this->outputFormat;
|
$format = $this->outputFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->log("### Output");
|
||||||
$this->log("Output format is: $format");
|
$this->log("Output format is: $format");
|
||||||
|
|
||||||
if (!$this->verbose && $format == 'json') {
|
if (!$this->verbose && $format == 'json') {
|
||||||
@@ -3712,7 +3865,8 @@ class CImage
|
|||||||
$this->fastTrackCache->addHeader($header);
|
$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) {
|
if ($this->verbose) {
|
||||||
$this->log("304 not modified");
|
$this->log("304 not modified");
|
||||||
@@ -3727,10 +3881,8 @@ class CImage
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Get details on image
|
$this->loadImageDetails($file);
|
||||||
$info = getimagesize($file);
|
$mime = $this->getMimeType();
|
||||||
!empty($info) or $this->raiseError("The file doesn't seem to be an image.");
|
|
||||||
$mime = $info['mime'];
|
|
||||||
$size = filesize($file);
|
$size = filesize($file);
|
||||||
|
|
||||||
if ($this->verbose) {
|
if ($this->verbose) {
|
||||||
@@ -3784,18 +3936,18 @@ class CImage
|
|||||||
$lastModified = filemtime($this->pathToImage);
|
$lastModified = filemtime($this->pathToImage);
|
||||||
$details['srcGmdate'] = gmdate("D, d M Y H:i:s", $lastModified);
|
$details['srcGmdate'] = gmdate("D, d M Y H:i:s", $lastModified);
|
||||||
|
|
||||||
$details['cache'] = basename($this->cacheFileName);
|
$details['cache'] = basename($this->cacheFileName ?? "");
|
||||||
$lastModified = filemtime($this->cacheFileName);
|
$lastModified = filemtime($this->cacheFileName ?? "");
|
||||||
$details['cacheGmdate'] = gmdate("D, d M Y H:i:s", $lastModified);
|
$details['cacheGmdate'] = gmdate("D, d M Y H:i:s", $lastModified);
|
||||||
|
|
||||||
$this->load($file);
|
$this->load($file);
|
||||||
|
|
||||||
$details['filename'] = basename($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['width'] = $this->width;
|
||||||
$details['height'] = $this->height;
|
$details['height'] = $this->height;
|
||||||
$details['aspectRatio'] = round($this->width / $this->height, 3);
|
$details['aspectRatio'] = round($this->width / $this->height, 3);
|
||||||
$details['size'] = filesize($file);
|
$details['size'] = filesize($file ?? "");
|
||||||
$details['colors'] = $this->colorsTotal($this->image);
|
$details['colors'] = $this->colorsTotal($this->image);
|
||||||
$details['includedFiles'] = count(get_included_files());
|
$details['includedFiles'] = count(get_included_files());
|
||||||
$details['memoryPeek'] = round(memory_get_peak_usage()/1024/1024, 3) . " MB" ;
|
$details['memoryPeek'] = round(memory_get_peak_usage()/1024/1024, 3) . " MB" ;
|
||||||
@@ -3893,6 +4045,7 @@ class CImage
|
|||||||
private function verboseOutput()
|
private function verboseOutput()
|
||||||
{
|
{
|
||||||
$log = null;
|
$log = null;
|
||||||
|
$this->log("### Summary of verbose log");
|
||||||
$this->log("As JSON: \n" . $this->json());
|
$this->log("As JSON: \n" . $this->json());
|
||||||
$this->log("Memory peak: " . round(memory_get_peak_usage() /1024/1024) . "M");
|
$this->log("Memory peak: " . round(memory_get_peak_usage() /1024/1024) . "M");
|
||||||
$this->log("Memory limit: " . ini_get('memory_limit'));
|
$this->log("Memory limit: " . ini_get('memory_limit'));
|
||||||
@@ -3993,6 +4146,15 @@ class CCache
|
|||||||
return $path;
|
return $path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($create && defined('WINDOWS2WSL')) {
|
||||||
|
// Special case to solve Windows 2 WSL integration
|
||||||
|
$path = $this->path . "/" . $subdir;
|
||||||
|
|
||||||
|
if (mkdir($path)) {
|
||||||
|
return realpath($path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($create && is_writable($this->path)) {
|
if ($create && is_writable($this->path)) {
|
||||||
$path = $this->path . "/" . $subdir;
|
$path = $this->path . "/" . $subdir;
|
||||||
|
|
||||||
@@ -4299,6 +4461,22 @@ class CFastTrackCache
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom exception handler.
|
||||||
|
*/
|
||||||
|
set_exception_handler(function ($exception) {
|
||||||
|
errorPage(
|
||||||
|
"<p><b>img.php: Uncaught exception:</b> <p>"
|
||||||
|
. $exception->getMessage()
|
||||||
|
. "</p><pre>"
|
||||||
|
. $exception->getTraceAsString()
|
||||||
|
. "</pre>",
|
||||||
|
500
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get configuration options from file, if the file exists, else use $config
|
* Get configuration options from file, if the file exists, else use $config
|
||||||
* if its defined or create an empty $config.
|
* if its defined or create an empty $config.
|
||||||
@@ -4461,7 +4639,7 @@ $hotlinkingWhitelist = getConfig('hotlinking_whitelist', array());
|
|||||||
|
|
||||||
$serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null;
|
$serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null;
|
||||||
$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
|
$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
|
||||||
$refererHost = parse_url($referer, PHP_URL_HOST);
|
$refererHost = parse_url($referer ?? "", PHP_URL_HOST);
|
||||||
|
|
||||||
if (!$allowHotlinking) {
|
if (!$allowHotlinking) {
|
||||||
if ($passwordMatch) {
|
if ($passwordMatch) {
|
||||||
@@ -4594,11 +4772,11 @@ if (isset($shortcut)
|
|||||||
/**
|
/**
|
||||||
* src - the source image file.
|
* src - the source image file.
|
||||||
*/
|
*/
|
||||||
$srcImage = urldecode(get('src'))
|
$srcImage = urldecode(get('src', ""))
|
||||||
or errorPage('Must set src-attribute.', 404);
|
or errorPage('Must set src-attribute.', 404);
|
||||||
|
|
||||||
// Get settings for src-alt as backup image
|
// Get settings for src-alt as backup image
|
||||||
$srcAltImage = urldecode(get('src-alt', null));
|
$srcAltImage = urldecode(get('src-alt', ""));
|
||||||
$srcAltConfig = getConfig('src_alt', null);
|
$srcAltConfig = getConfig('src_alt', null);
|
||||||
if (empty($srcAltImage)) {
|
if (empty($srcAltImage)) {
|
||||||
$srcAltImage = $srcAltConfig;
|
$srcAltImage = $srcAltConfig;
|
||||||
@@ -4715,7 +4893,7 @@ if (isset($sizes[$newWidth])) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Support width as % of original width
|
// Support width as % of original width
|
||||||
if ($newWidth[strlen($newWidth)-1] == '%') {
|
if ($newWidth && $newWidth[strlen($newWidth)-1] == '%') {
|
||||||
is_numeric(substr($newWidth, 0, -1))
|
is_numeric(substr($newWidth, 0, -1))
|
||||||
or errorPage('Width % not numeric.', 404);
|
or errorPage('Width % not numeric.', 404);
|
||||||
} else {
|
} else {
|
||||||
@@ -4740,7 +4918,7 @@ if (isset($sizes[$newHeight])) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// height
|
// height
|
||||||
if ($newHeight[strlen($newHeight)-1] == '%') {
|
if ($newHeight && $newHeight[strlen($newHeight)-1] == '%') {
|
||||||
is_numeric(substr($newHeight, 0, -1))
|
is_numeric(substr($newHeight, 0, -1))
|
||||||
or errorPage('Height % out of range.', 404);
|
or errorPage('Height % out of range.', 404);
|
||||||
} else {
|
} else {
|
||||||
@@ -4771,7 +4949,7 @@ $aspectRatioConstant = getConfig('aspect_ratio_constant', function () {
|
|||||||
|
|
||||||
// Check to replace predefined aspect ratio
|
// Check to replace predefined aspect ratio
|
||||||
$aspectRatios = call_user_func($aspectRatioConstant);
|
$aspectRatios = call_user_func($aspectRatioConstant);
|
||||||
$negateAspectRatio = ($aspectRatio[0] == '!') ? true : false;
|
$negateAspectRatio = ($aspectRatio && $aspectRatio[0] == '!') ? true : false;
|
||||||
$aspectRatio = $negateAspectRatio ? substr($aspectRatio, 1) : $aspectRatio;
|
$aspectRatio = $negateAspectRatio ? substr($aspectRatio, 1) : $aspectRatio;
|
||||||
|
|
||||||
if (isset($aspectRatios[$aspectRatio])) {
|
if (isset($aspectRatios[$aspectRatio])) {
|
||||||
@@ -5131,6 +5309,9 @@ verbose("upscale = $upscale");
|
|||||||
* Get details for post processing
|
* Get details for post processing
|
||||||
*/
|
*/
|
||||||
$postProcessing = getConfig('postprocessing', array(
|
$postProcessing = getConfig('postprocessing', array(
|
||||||
|
'png_lossy' => false,
|
||||||
|
'png_lossy_cmd' => '/usr/local/bin/pngquant --force --output',
|
||||||
|
|
||||||
'png_filter' => false,
|
'png_filter' => false,
|
||||||
'png_filter_cmd' => '/usr/local/bin/optipng -q',
|
'png_filter_cmd' => '/usr/local/bin/optipng -q',
|
||||||
|
|
||||||
@@ -5143,6 +5324,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.
|
* alias - Save resulting image to another alias name.
|
||||||
* Password always apply, must be defined.
|
* Password always apply, must be defined.
|
||||||
@@ -5183,6 +5373,18 @@ if ($cacheControl) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* interlace - Enable configuration for interlaced progressive JPEG images.
|
||||||
|
*/
|
||||||
|
$interlaceConfig = getConfig('interlace', null);
|
||||||
|
$interlaceValue = getValue('interlace', null);
|
||||||
|
$interlaceDefined = getDefined('interlace', true, null);
|
||||||
|
$interlace = $interlaceValue ?? $interlaceDefined ?? $interlaceConfig;
|
||||||
|
verbose("interlace (configfile) = ", $interlaceConfig);
|
||||||
|
verbose("interlace = ", $interlace);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare a dummy image and use it as source image.
|
* Prepare a dummy image and use it as source image.
|
||||||
*/
|
*/
|
||||||
@@ -5261,7 +5463,7 @@ if ($status) {
|
|||||||
$res = $cache->getStatusOfSubdir("srgb");
|
$res = $cache->getStatusOfSubdir("srgb");
|
||||||
$text .= "Cache srgb $res\n";
|
$text .= "Cache srgb $res\n";
|
||||||
|
|
||||||
$res = $cache->getStatusOfSubdir($fasttrackCache);
|
$res = $cache->getStatusOfSubdir($fastTrackCache);
|
||||||
$text .= "Cache fasttrack $res\n";
|
$text .= "Cache fasttrack $res\n";
|
||||||
|
|
||||||
$text .= "Alias path writable = " . is_writable($aliasPath) . "\n";
|
$text .= "Alias path writable = " . is_writable($aliasPath) . "\n";
|
||||||
@@ -5278,6 +5480,11 @@ if ($status) {
|
|||||||
$no = extension_loaded('gd') ? null : 'NOT';
|
$no = extension_loaded('gd') ? null : 'NOT';
|
||||||
$text .= "Extension gd is $no loaded.<br>";
|
$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) {
|
if (!$no) {
|
||||||
$text .= print_r(gd_info(), 1);
|
$text .= print_r(gd_info(), 1);
|
||||||
}
|
}
|
||||||
@@ -5339,6 +5546,7 @@ if (is_callable($hookBeforeCImage)) {
|
|||||||
'blur' => $blur,
|
'blur' => $blur,
|
||||||
'convolve' => $convolve,
|
'convolve' => $convolve,
|
||||||
'rotateAfter' => $rotateAfter,
|
'rotateAfter' => $rotateAfter,
|
||||||
|
'interlace' => $interlace,
|
||||||
|
|
||||||
// Output format
|
// Output format
|
||||||
'outputFormat' => $outputFormat,
|
'outputFormat' => $outputFormat,
|
||||||
@@ -5346,6 +5554,7 @@ if (is_callable($hookBeforeCImage)) {
|
|||||||
|
|
||||||
// Other
|
// Other
|
||||||
'postProcessing' => $postProcessing,
|
'postProcessing' => $postProcessing,
|
||||||
|
'lossy' => $lossy,
|
||||||
));
|
));
|
||||||
verbose(print_r($allConfig, 1));
|
verbose(print_r($allConfig, 1));
|
||||||
extract($allConfig);
|
extract($allConfig);
|
||||||
@@ -5393,7 +5602,8 @@ EOD;
|
|||||||
/**
|
/**
|
||||||
* Load, process and output the image
|
* Load, process and output the image
|
||||||
*/
|
*/
|
||||||
$img->log("Incoming arguments: " . print_r(verbose(), 1))
|
$img->log("PHP version: " . phpversion())
|
||||||
|
->log("Incoming arguments: " . print_r(verbose(), 1))
|
||||||
->setSaveFolder($cachePath)
|
->setSaveFolder($cachePath)
|
||||||
->useCache($useCache)
|
->useCache($useCache)
|
||||||
->setSource($srcImage, $imagePath)
|
->setSource($srcImage, $imagePath)
|
||||||
@@ -5426,10 +5636,14 @@ $img->log("Incoming arguments: " . print_r(verbose(), 1))
|
|||||||
'blur' => $blur,
|
'blur' => $blur,
|
||||||
'convolve' => $convolve,
|
'convolve' => $convolve,
|
||||||
'rotateAfter' => $rotateAfter,
|
'rotateAfter' => $rotateAfter,
|
||||||
|
'interlace' => $interlace,
|
||||||
|
|
||||||
// Output format
|
// Output format
|
||||||
'outputFormat' => $outputFormat,
|
'outputFormat' => $outputFormat,
|
||||||
'dpr' => $dpr,
|
'dpr' => $dpr,
|
||||||
|
|
||||||
|
// Postprocessing using external tools
|
||||||
|
'lossy' => $lossy,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
->loadImageDetails()
|
->loadImageDetails()
|
||||||
|
322
webroot/imgp.php
@@ -38,11 +38,16 @@ $config = array(
|
|||||||
|
|
||||||
|
|
||||||
// Version of cimage and img.php
|
// Version of cimage and img.php
|
||||||
define("CIMAGE_VERSION", "v0.7.13 (2016-08-08)");
|
define("CIMAGE_VERSION", "v0.8.6 (2023-10-27)");
|
||||||
|
|
||||||
// For CRemoteImage
|
// For CRemoteImage
|
||||||
define("CIMAGE_USER_AGENT", "CImage/" . CIMAGE_VERSION);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -113,22 +118,6 @@ function errorPage($msg, $type = 500)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom exception handler.
|
|
||||||
*/
|
|
||||||
set_exception_handler(function ($exception) {
|
|
||||||
errorPage(
|
|
||||||
"<p><b>img.php: Uncaught exception:</b> <p>"
|
|
||||||
. $exception->getMessage()
|
|
||||||
. "</p><pre>"
|
|
||||||
. $exception->getTraceAsString()
|
|
||||||
. "</pre>",
|
|
||||||
500
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get input from query string or return default value if not set.
|
* Get input from query string or return default value if not set.
|
||||||
*
|
*
|
||||||
@@ -169,6 +158,25 @@ function getDefined($key, $defined, $undefined)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get value of input from query string or else $undefined.
|
||||||
|
*
|
||||||
|
* @param mixed $key as string or array of string values to look for in $_GET.
|
||||||
|
* @param mixed $undefined value to return when $key has no, or empty value in $_GET.
|
||||||
|
*
|
||||||
|
* @return mixed value as or $undefined.
|
||||||
|
*/
|
||||||
|
function getValue($key, $undefined)
|
||||||
|
{
|
||||||
|
$val = get($key);
|
||||||
|
if (is_null($val) || $val === "") {
|
||||||
|
return $undefined;
|
||||||
|
}
|
||||||
|
return $val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get value from config array or default if key is not set in config array.
|
* Get value from config array or default if key is not set in config array.
|
||||||
*
|
*
|
||||||
@@ -194,7 +202,7 @@ function getConfig($key, $default)
|
|||||||
*
|
*
|
||||||
* @return void or array.
|
* @return void or array.
|
||||||
*/
|
*/
|
||||||
function verbose($msg = null)
|
function verbose($msg = null, $arg = "")
|
||||||
{
|
{
|
||||||
global $verbose, $verboseFile;
|
global $verbose, $verboseFile;
|
||||||
static $log = array();
|
static $log = array();
|
||||||
@@ -207,7 +215,36 @@ function verbose($msg = null)
|
|||||||
return $log;
|
return $log;
|
||||||
}
|
}
|
||||||
|
|
||||||
$log[] = $msg;
|
if (is_null($arg)) {
|
||||||
|
$arg = "null";
|
||||||
|
} elseif ($arg === false) {
|
||||||
|
$arg = "false";
|
||||||
|
} elseif ($arg === true) {
|
||||||
|
$arg = "true";
|
||||||
|
}
|
||||||
|
|
||||||
|
$log[] = $msg . $arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -428,7 +465,7 @@ class CHttpGet
|
|||||||
{
|
{
|
||||||
$type = isset($this->response['header']['Content-Type'])
|
$type = isset($this->response['header']['Content-Type'])
|
||||||
? $this->response['header']['Content-Type']
|
? $this->response['header']['Content-Type']
|
||||||
: null;
|
: '';
|
||||||
|
|
||||||
return preg_match('#[a-z]+/[a-z]+#', $type)
|
return preg_match('#[a-z]+/[a-z]+#', $type)
|
||||||
? $type
|
? $type
|
||||||
@@ -1106,6 +1143,7 @@ class CAsciiArt
|
|||||||
* @example http://dbwebb.se/opensource/cimage
|
* @example http://dbwebb.se/opensource/cimage
|
||||||
* @link https://github.com/mosbth/cimage
|
* @link https://github.com/mosbth/cimage
|
||||||
*/
|
*/
|
||||||
|
#[AllowDynamicProperties]
|
||||||
class CImage
|
class CImage
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -1255,6 +1293,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
|
* Verbose mode to print out a trace and display the created image
|
||||||
*/
|
*/
|
||||||
@@ -1290,7 +1335,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 $pngFilter;
|
||||||
private $pngFilterCmd;
|
private $pngFilterCmd;
|
||||||
@@ -1298,7 +1351,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 $pngDeflate;
|
||||||
private $pngDeflateCmd;
|
private $pngDeflateCmd;
|
||||||
@@ -1508,6 +1561,13 @@ class CImage
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use interlaced progressive mode for JPEG images.
|
||||||
|
*/
|
||||||
|
private $interlace = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Image copy strategy, defaults to RESAMPLE.
|
* Image copy strategy, defaults to RESAMPLE.
|
||||||
*/
|
*/
|
||||||
@@ -1740,7 +1800,7 @@ class CImage
|
|||||||
*/
|
*/
|
||||||
private function checkFileExtension($extension)
|
private function checkFileExtension($extension)
|
||||||
{
|
{
|
||||||
$valid = array('jpg', 'jpeg', 'png', 'gif');
|
$valid = array('jpg', 'jpeg', 'png', 'gif', 'webp');
|
||||||
|
|
||||||
in_array(strtolower($extension), $valid)
|
in_array(strtolower($extension), $valid)
|
||||||
or $this->raiseError('Not a valid file extension.');
|
or $this->raiseError('Not a valid file extension.');
|
||||||
@@ -1757,9 +1817,9 @@ class CImage
|
|||||||
*
|
*
|
||||||
* @return string $extension as a normalized file extension.
|
* @return string $extension as a normalized file extension.
|
||||||
*/
|
*/
|
||||||
private function normalizeFileExtension($extension = null)
|
private function normalizeFileExtension($extension = "")
|
||||||
{
|
{
|
||||||
$extension = strtolower($extension ? $extension : $this->extension);
|
$extension = strtolower($extension ? $extension : $this->extension ?? "");
|
||||||
|
|
||||||
if ($extension == 'jpeg') {
|
if ($extension == 'jpeg') {
|
||||||
$extension = 'jpg';
|
$extension = 'jpg';
|
||||||
@@ -1923,10 +1983,14 @@ class CImage
|
|||||||
'blur' => null,
|
'blur' => null,
|
||||||
'convolve' => null,
|
'convolve' => null,
|
||||||
'rotateAfter' => null,
|
'rotateAfter' => null,
|
||||||
|
'interlace' => null,
|
||||||
|
|
||||||
// Output format
|
// Output format
|
||||||
'outputFormat' => null,
|
'outputFormat' => null,
|
||||||
'dpr' => 1,
|
'dpr' => 1,
|
||||||
|
|
||||||
|
// Postprocessing using external tools
|
||||||
|
'lossy' => null,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Convert crop settings from string to array
|
// Convert crop settings from string to array
|
||||||
@@ -2038,20 +2102,40 @@ class CImage
|
|||||||
{
|
{
|
||||||
$file = $file ? $file : $this->pathToImage;
|
$file = $file ? $file : $this->pathToImage;
|
||||||
|
|
||||||
|
// Special case to solve Windows 2 WSL integration
|
||||||
|
if (!defined('WINDOWS2WSL')) {
|
||||||
is_readable($file)
|
is_readable($file)
|
||||||
or $this->raiseError('Image file does not exist.');
|
or $this->raiseError('Image file does not exist.');
|
||||||
|
}
|
||||||
|
|
||||||
// Get details on image
|
$info = list($this->width, $this->height, $this->fileType) = getimagesize($file);
|
||||||
$info = list($this->width, $this->height, $this->fileType, $this->attr) = getimagesize($file);
|
|
||||||
if (empty($info)) {
|
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) {
|
if ($this->verbose) {
|
||||||
$this->log("Loading image details for: {$file}");
|
$this->log("Loading image details for: {$file}");
|
||||||
$this->log(" Image width x height (type): {$this->width} x {$this->height} ({$this->fileType}).");
|
$this->log(" Image width x height (type): {$this->width} x {$this->height} ({$this->fileType}).");
|
||||||
$this->log(" Image filesize: " . filesize($file) . " bytes.");
|
$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;
|
return $this;
|
||||||
@@ -2059,6 +2143,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
|
* Init new width and height and do some sanity checks on constraints, before any
|
||||||
* processing can be done.
|
* processing can be done.
|
||||||
@@ -2071,13 +2172,15 @@ class CImage
|
|||||||
$this->log("Init dimension (before) newWidth x newHeight is {$this->newWidth} x {$this->newHeight}.");
|
$this->log("Init dimension (before) newWidth x newHeight is {$this->newWidth} x {$this->newHeight}.");
|
||||||
|
|
||||||
// width as %
|
// width as %
|
||||||
if ($this->newWidth[strlen($this->newWidth)-1] == '%') {
|
if ($this->newWidth
|
||||||
|
&& $this->newWidth[strlen($this->newWidth)-1] == '%') {
|
||||||
$this->newWidth = $this->width * substr($this->newWidth, 0, -1) / 100;
|
$this->newWidth = $this->width * substr($this->newWidth, 0, -1) / 100;
|
||||||
$this->log("Setting new width based on % to {$this->newWidth}");
|
$this->log("Setting new width based on % to {$this->newWidth}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// height as %
|
// height as %
|
||||||
if ($this->newHeight[strlen($this->newHeight)-1] == '%') {
|
if ($this->newHeight
|
||||||
|
&& $this->newHeight[strlen($this->newHeight)-1] == '%') {
|
||||||
$this->newHeight = $this->height * substr($this->newHeight, 0, -1) / 100;
|
$this->newHeight = $this->height * substr($this->newHeight, 0, -1) / 100;
|
||||||
$this->log("Setting new height based on % to {$this->newHeight}");
|
$this->log("Setting new height based on % to {$this->newHeight}");
|
||||||
}
|
}
|
||||||
@@ -2413,6 +2516,7 @@ class CImage
|
|||||||
&& !$this->autoRotate
|
&& !$this->autoRotate
|
||||||
&& !$this->bgColor
|
&& !$this->bgColor
|
||||||
&& ($this->upscale === self::UPSCALE_DEFAULT)
|
&& ($this->upscale === self::UPSCALE_DEFAULT)
|
||||||
|
&& !$this->lossy
|
||||||
) {
|
) {
|
||||||
$this->log("Using original image.");
|
$this->log("Using original image.");
|
||||||
$this->output($this->pathToImage);
|
$this->output($this->pathToImage);
|
||||||
@@ -2446,6 +2550,8 @@ class CImage
|
|||||||
$compress = $this->compress ? "_co{$this->compress}" : null;
|
$compress = $this->compress ? "_co{$this->compress}" : null;
|
||||||
$rotateBefore = $this->rotateBefore ? "_rb{$this->rotateBefore}" : null;
|
$rotateBefore = $this->rotateBefore ? "_rb{$this->rotateBefore}" : null;
|
||||||
$rotateAfter = $this->rotateAfter ? "_ra{$this->rotateAfter}" : null;
|
$rotateAfter = $this->rotateAfter ? "_ra{$this->rotateAfter}" : null;
|
||||||
|
$lossy = $this->lossy ? "_l" : null;
|
||||||
|
$interlace = $this->interlace ? "_i" : null;
|
||||||
|
|
||||||
$saveAs = $this->normalizeFileExtension();
|
$saveAs = $this->normalizeFileExtension();
|
||||||
$saveAs = $saveAs ? "_$saveAs" : null;
|
$saveAs = $saveAs ? "_$saveAs" : null;
|
||||||
@@ -2512,7 +2618,7 @@ class CImage
|
|||||||
. $quality . $filters . $sharpen . $emboss . $blur . $palette
|
. $quality . $filters . $sharpen . $emboss . $blur . $palette
|
||||||
. $optimize . $compress
|
. $optimize . $compress
|
||||||
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor
|
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor
|
||||||
. $convolve . $copyStrat . $saveAs;
|
. $convolve . $copyStrat . $lossy . $interlace . $saveAs;
|
||||||
|
|
||||||
return $this->setTarget($file, $base);
|
return $this->setTarget($file, $base);
|
||||||
}
|
}
|
||||||
@@ -2570,9 +2676,14 @@ class CImage
|
|||||||
$this->setSource($src, $dir);
|
$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) {
|
if ($this->image === false) {
|
||||||
throw new Exception("Could not load image.");
|
throw new Exception("Could not load image.");
|
||||||
}
|
}
|
||||||
@@ -3406,6 +3517,14 @@ class CImage
|
|||||||
$this->jpegOptimizeCmd = null;
|
$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']) {
|
if (isset($options['png_filter']) && $options['png_filter']) {
|
||||||
$this->pngFilterCmd = $options['png_filter_cmd'];
|
$this->pngFilterCmd = $options['png_filter_cmd'];
|
||||||
} else {
|
} else {
|
||||||
@@ -3433,9 +3552,11 @@ class CImage
|
|||||||
// switch on mimetype
|
// switch on mimetype
|
||||||
if (isset($this->extension)) {
|
if (isset($this->extension)) {
|
||||||
return strtolower($this->extension);
|
return strtolower($this->extension);
|
||||||
} else {
|
} elseif ($this->fileType === IMG_WEBP) {
|
||||||
return substr(image_type_to_extension($this->fileType), 1);
|
return "webp";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return substr(image_type_to_extension($this->fileType), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -3460,8 +3581,10 @@ class CImage
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!defined("WINDOWS2WSL")) {
|
||||||
is_writable($this->saveFolder)
|
is_writable($this->saveFolder)
|
||||||
or $this->raiseError('Target directory is not writable.');
|
or $this->raiseError('Target directory is not writable.');
|
||||||
|
}
|
||||||
|
|
||||||
$type = $this->getTargetImageExtension();
|
$type = $this->getTargetImageExtension();
|
||||||
$this->Log("Saving image as " . $type);
|
$this->Log("Saving image as " . $type);
|
||||||
@@ -3469,6 +3592,12 @@ class CImage
|
|||||||
|
|
||||||
case 'jpeg':
|
case 'jpeg':
|
||||||
case 'jpg':
|
case 'jpg':
|
||||||
|
// Set as interlaced progressive JPEG
|
||||||
|
if ($this->interlace) {
|
||||||
|
$this->Log("Set JPEG image to be interlaced.");
|
||||||
|
$res = imageinterlace($this->image, true);
|
||||||
|
}
|
||||||
|
|
||||||
$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);
|
||||||
|
|
||||||
@@ -3491,6 +3620,11 @@ class CImage
|
|||||||
imagegif($this->image, $this->cacheFileName);
|
imagegif($this->image, $this->cacheFileName);
|
||||||
break;
|
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':
|
case 'png':
|
||||||
default:
|
default:
|
||||||
$this->Log("Saving image as PNG to cache using compression = {$this->compress}.");
|
$this->Log("Saving image as PNG to cache using compression = {$this->compress}.");
|
||||||
@@ -3500,6 +3634,24 @@ class CImage
|
|||||||
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 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
|
// Use external program to filter PNG, if defined
|
||||||
if ($this->pngFilterCmd) {
|
if ($this->pngFilterCmd) {
|
||||||
if ($this->verbose) {
|
if ($this->verbose) {
|
||||||
@@ -3679,6 +3831,7 @@ class CImage
|
|||||||
$format = $this->outputFormat;
|
$format = $this->outputFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->log("### Output");
|
||||||
$this->log("Output format is: $format");
|
$this->log("Output format is: $format");
|
||||||
|
|
||||||
if (!$this->verbose && $format == 'json') {
|
if (!$this->verbose && $format == 'json') {
|
||||||
@@ -3712,7 +3865,8 @@ class CImage
|
|||||||
$this->fastTrackCache->addHeader($header);
|
$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) {
|
if ($this->verbose) {
|
||||||
$this->log("304 not modified");
|
$this->log("304 not modified");
|
||||||
@@ -3727,10 +3881,8 @@ class CImage
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Get details on image
|
$this->loadImageDetails($file);
|
||||||
$info = getimagesize($file);
|
$mime = $this->getMimeType();
|
||||||
!empty($info) or $this->raiseError("The file doesn't seem to be an image.");
|
|
||||||
$mime = $info['mime'];
|
|
||||||
$size = filesize($file);
|
$size = filesize($file);
|
||||||
|
|
||||||
if ($this->verbose) {
|
if ($this->verbose) {
|
||||||
@@ -3784,18 +3936,18 @@ class CImage
|
|||||||
$lastModified = filemtime($this->pathToImage);
|
$lastModified = filemtime($this->pathToImage);
|
||||||
$details['srcGmdate'] = gmdate("D, d M Y H:i:s", $lastModified);
|
$details['srcGmdate'] = gmdate("D, d M Y H:i:s", $lastModified);
|
||||||
|
|
||||||
$details['cache'] = basename($this->cacheFileName);
|
$details['cache'] = basename($this->cacheFileName ?? "");
|
||||||
$lastModified = filemtime($this->cacheFileName);
|
$lastModified = filemtime($this->cacheFileName ?? "");
|
||||||
$details['cacheGmdate'] = gmdate("D, d M Y H:i:s", $lastModified);
|
$details['cacheGmdate'] = gmdate("D, d M Y H:i:s", $lastModified);
|
||||||
|
|
||||||
$this->load($file);
|
$this->load($file);
|
||||||
|
|
||||||
$details['filename'] = basename($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['width'] = $this->width;
|
||||||
$details['height'] = $this->height;
|
$details['height'] = $this->height;
|
||||||
$details['aspectRatio'] = round($this->width / $this->height, 3);
|
$details['aspectRatio'] = round($this->width / $this->height, 3);
|
||||||
$details['size'] = filesize($file);
|
$details['size'] = filesize($file ?? "");
|
||||||
$details['colors'] = $this->colorsTotal($this->image);
|
$details['colors'] = $this->colorsTotal($this->image);
|
||||||
$details['includedFiles'] = count(get_included_files());
|
$details['includedFiles'] = count(get_included_files());
|
||||||
$details['memoryPeek'] = round(memory_get_peak_usage()/1024/1024, 3) . " MB" ;
|
$details['memoryPeek'] = round(memory_get_peak_usage()/1024/1024, 3) . " MB" ;
|
||||||
@@ -3893,6 +4045,7 @@ class CImage
|
|||||||
private function verboseOutput()
|
private function verboseOutput()
|
||||||
{
|
{
|
||||||
$log = null;
|
$log = null;
|
||||||
|
$this->log("### Summary of verbose log");
|
||||||
$this->log("As JSON: \n" . $this->json());
|
$this->log("As JSON: \n" . $this->json());
|
||||||
$this->log("Memory peak: " . round(memory_get_peak_usage() /1024/1024) . "M");
|
$this->log("Memory peak: " . round(memory_get_peak_usage() /1024/1024) . "M");
|
||||||
$this->log("Memory limit: " . ini_get('memory_limit'));
|
$this->log("Memory limit: " . ini_get('memory_limit'));
|
||||||
@@ -3993,6 +4146,15 @@ class CCache
|
|||||||
return $path;
|
return $path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($create && defined('WINDOWS2WSL')) {
|
||||||
|
// Special case to solve Windows 2 WSL integration
|
||||||
|
$path = $this->path . "/" . $subdir;
|
||||||
|
|
||||||
|
if (mkdir($path)) {
|
||||||
|
return realpath($path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($create && is_writable($this->path)) {
|
if ($create && is_writable($this->path)) {
|
||||||
$path = $this->path . "/" . $subdir;
|
$path = $this->path . "/" . $subdir;
|
||||||
|
|
||||||
@@ -4299,6 +4461,22 @@ class CFastTrackCache
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom exception handler.
|
||||||
|
*/
|
||||||
|
set_exception_handler(function ($exception) {
|
||||||
|
errorPage(
|
||||||
|
"<p><b>img.php: Uncaught exception:</b> <p>"
|
||||||
|
. $exception->getMessage()
|
||||||
|
. "</p><pre>"
|
||||||
|
. $exception->getTraceAsString()
|
||||||
|
. "</pre>",
|
||||||
|
500
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get configuration options from file, if the file exists, else use $config
|
* Get configuration options from file, if the file exists, else use $config
|
||||||
* if its defined or create an empty $config.
|
* if its defined or create an empty $config.
|
||||||
@@ -4461,7 +4639,7 @@ $hotlinkingWhitelist = getConfig('hotlinking_whitelist', array());
|
|||||||
|
|
||||||
$serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null;
|
$serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null;
|
||||||
$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
|
$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
|
||||||
$refererHost = parse_url($referer, PHP_URL_HOST);
|
$refererHost = parse_url($referer ?? "", PHP_URL_HOST);
|
||||||
|
|
||||||
if (!$allowHotlinking) {
|
if (!$allowHotlinking) {
|
||||||
if ($passwordMatch) {
|
if ($passwordMatch) {
|
||||||
@@ -4594,11 +4772,11 @@ if (isset($shortcut)
|
|||||||
/**
|
/**
|
||||||
* src - the source image file.
|
* src - the source image file.
|
||||||
*/
|
*/
|
||||||
$srcImage = urldecode(get('src'))
|
$srcImage = urldecode(get('src', ""))
|
||||||
or errorPage('Must set src-attribute.', 404);
|
or errorPage('Must set src-attribute.', 404);
|
||||||
|
|
||||||
// Get settings for src-alt as backup image
|
// Get settings for src-alt as backup image
|
||||||
$srcAltImage = urldecode(get('src-alt', null));
|
$srcAltImage = urldecode(get('src-alt', ""));
|
||||||
$srcAltConfig = getConfig('src_alt', null);
|
$srcAltConfig = getConfig('src_alt', null);
|
||||||
if (empty($srcAltImage)) {
|
if (empty($srcAltImage)) {
|
||||||
$srcAltImage = $srcAltConfig;
|
$srcAltImage = $srcAltConfig;
|
||||||
@@ -4715,7 +4893,7 @@ if (isset($sizes[$newWidth])) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Support width as % of original width
|
// Support width as % of original width
|
||||||
if ($newWidth[strlen($newWidth)-1] == '%') {
|
if ($newWidth && $newWidth[strlen($newWidth)-1] == '%') {
|
||||||
is_numeric(substr($newWidth, 0, -1))
|
is_numeric(substr($newWidth, 0, -1))
|
||||||
or errorPage('Width % not numeric.', 404);
|
or errorPage('Width % not numeric.', 404);
|
||||||
} else {
|
} else {
|
||||||
@@ -4740,7 +4918,7 @@ if (isset($sizes[$newHeight])) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// height
|
// height
|
||||||
if ($newHeight[strlen($newHeight)-1] == '%') {
|
if ($newHeight && $newHeight[strlen($newHeight)-1] == '%') {
|
||||||
is_numeric(substr($newHeight, 0, -1))
|
is_numeric(substr($newHeight, 0, -1))
|
||||||
or errorPage('Height % out of range.', 404);
|
or errorPage('Height % out of range.', 404);
|
||||||
} else {
|
} else {
|
||||||
@@ -4771,7 +4949,7 @@ $aspectRatioConstant = getConfig('aspect_ratio_constant', function () {
|
|||||||
|
|
||||||
// Check to replace predefined aspect ratio
|
// Check to replace predefined aspect ratio
|
||||||
$aspectRatios = call_user_func($aspectRatioConstant);
|
$aspectRatios = call_user_func($aspectRatioConstant);
|
||||||
$negateAspectRatio = ($aspectRatio[0] == '!') ? true : false;
|
$negateAspectRatio = ($aspectRatio && $aspectRatio[0] == '!') ? true : false;
|
||||||
$aspectRatio = $negateAspectRatio ? substr($aspectRatio, 1) : $aspectRatio;
|
$aspectRatio = $negateAspectRatio ? substr($aspectRatio, 1) : $aspectRatio;
|
||||||
|
|
||||||
if (isset($aspectRatios[$aspectRatio])) {
|
if (isset($aspectRatios[$aspectRatio])) {
|
||||||
@@ -5131,6 +5309,9 @@ verbose("upscale = $upscale");
|
|||||||
* Get details for post processing
|
* Get details for post processing
|
||||||
*/
|
*/
|
||||||
$postProcessing = getConfig('postprocessing', array(
|
$postProcessing = getConfig('postprocessing', array(
|
||||||
|
'png_lossy' => false,
|
||||||
|
'png_lossy_cmd' => '/usr/local/bin/pngquant --force --output',
|
||||||
|
|
||||||
'png_filter' => false,
|
'png_filter' => false,
|
||||||
'png_filter_cmd' => '/usr/local/bin/optipng -q',
|
'png_filter_cmd' => '/usr/local/bin/optipng -q',
|
||||||
|
|
||||||
@@ -5143,6 +5324,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.
|
* alias - Save resulting image to another alias name.
|
||||||
* Password always apply, must be defined.
|
* Password always apply, must be defined.
|
||||||
@@ -5183,6 +5373,18 @@ if ($cacheControl) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* interlace - Enable configuration for interlaced progressive JPEG images.
|
||||||
|
*/
|
||||||
|
$interlaceConfig = getConfig('interlace', null);
|
||||||
|
$interlaceValue = getValue('interlace', null);
|
||||||
|
$interlaceDefined = getDefined('interlace', true, null);
|
||||||
|
$interlace = $interlaceValue ?? $interlaceDefined ?? $interlaceConfig;
|
||||||
|
verbose("interlace (configfile) = ", $interlaceConfig);
|
||||||
|
verbose("interlace = ", $interlace);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare a dummy image and use it as source image.
|
* Prepare a dummy image and use it as source image.
|
||||||
*/
|
*/
|
||||||
@@ -5261,7 +5463,7 @@ if ($status) {
|
|||||||
$res = $cache->getStatusOfSubdir("srgb");
|
$res = $cache->getStatusOfSubdir("srgb");
|
||||||
$text .= "Cache srgb $res\n";
|
$text .= "Cache srgb $res\n";
|
||||||
|
|
||||||
$res = $cache->getStatusOfSubdir($fasttrackCache);
|
$res = $cache->getStatusOfSubdir($fastTrackCache);
|
||||||
$text .= "Cache fasttrack $res\n";
|
$text .= "Cache fasttrack $res\n";
|
||||||
|
|
||||||
$text .= "Alias path writable = " . is_writable($aliasPath) . "\n";
|
$text .= "Alias path writable = " . is_writable($aliasPath) . "\n";
|
||||||
@@ -5278,6 +5480,11 @@ if ($status) {
|
|||||||
$no = extension_loaded('gd') ? null : 'NOT';
|
$no = extension_loaded('gd') ? null : 'NOT';
|
||||||
$text .= "Extension gd is $no loaded.<br>";
|
$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) {
|
if (!$no) {
|
||||||
$text .= print_r(gd_info(), 1);
|
$text .= print_r(gd_info(), 1);
|
||||||
}
|
}
|
||||||
@@ -5339,6 +5546,7 @@ if (is_callable($hookBeforeCImage)) {
|
|||||||
'blur' => $blur,
|
'blur' => $blur,
|
||||||
'convolve' => $convolve,
|
'convolve' => $convolve,
|
||||||
'rotateAfter' => $rotateAfter,
|
'rotateAfter' => $rotateAfter,
|
||||||
|
'interlace' => $interlace,
|
||||||
|
|
||||||
// Output format
|
// Output format
|
||||||
'outputFormat' => $outputFormat,
|
'outputFormat' => $outputFormat,
|
||||||
@@ -5346,6 +5554,7 @@ if (is_callable($hookBeforeCImage)) {
|
|||||||
|
|
||||||
// Other
|
// Other
|
||||||
'postProcessing' => $postProcessing,
|
'postProcessing' => $postProcessing,
|
||||||
|
'lossy' => $lossy,
|
||||||
));
|
));
|
||||||
verbose(print_r($allConfig, 1));
|
verbose(print_r($allConfig, 1));
|
||||||
extract($allConfig);
|
extract($allConfig);
|
||||||
@@ -5393,7 +5602,8 @@ EOD;
|
|||||||
/**
|
/**
|
||||||
* Load, process and output the image
|
* Load, process and output the image
|
||||||
*/
|
*/
|
||||||
$img->log("Incoming arguments: " . print_r(verbose(), 1))
|
$img->log("PHP version: " . phpversion())
|
||||||
|
->log("Incoming arguments: " . print_r(verbose(), 1))
|
||||||
->setSaveFolder($cachePath)
|
->setSaveFolder($cachePath)
|
||||||
->useCache($useCache)
|
->useCache($useCache)
|
||||||
->setSource($srcImage, $imagePath)
|
->setSource($srcImage, $imagePath)
|
||||||
@@ -5426,10 +5636,14 @@ $img->log("Incoming arguments: " . print_r(verbose(), 1))
|
|||||||
'blur' => $blur,
|
'blur' => $blur,
|
||||||
'convolve' => $convolve,
|
'convolve' => $convolve,
|
||||||
'rotateAfter' => $rotateAfter,
|
'rotateAfter' => $rotateAfter,
|
||||||
|
'interlace' => $interlace,
|
||||||
|
|
||||||
// Output format
|
// Output format
|
||||||
'outputFormat' => $outputFormat,
|
'outputFormat' => $outputFormat,
|
||||||
'dpr' => $dpr,
|
'dpr' => $dpr,
|
||||||
|
|
||||||
|
// Postprocessing using external tools
|
||||||
|
'lossy' => $lossy,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
->loadImageDetails()
|
->loadImageDetails()
|
||||||
|
22
webroot/tests.php
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$links = [
|
||||||
|
"img.php?src=car.png&v",
|
||||||
|
"img.php?src=car.png&w=700&v",
|
||||||
|
];
|
||||||
|
|
||||||
|
?><!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Links to use for testing</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Links useful for testing</h1>
|
||||||
|
<p>A collection of linkt to use to test various aspects of the cimage process.</p>
|
||||||
|
<ul>
|
||||||
|
<?php foreach ($links as $link) : ?>
|
||||||
|
<li><a href="<?= $link ?>"><?= $link ?></a></li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>
|