mirror of
https://github.com/processwire/processwire.git
synced 2025-08-15 03:05:26 +02:00
Updates to @horst-n PR #141 for webp image support
This commit is contained in:
@@ -3,15 +3,13 @@
|
|||||||
/**
|
/**
|
||||||
* ImageSizer Engine Module (Abstract)
|
* ImageSizer Engine Module (Abstract)
|
||||||
*
|
*
|
||||||
* Copyright (C) 2016 by Horst Nogajski and Ryan Cramer
|
* Copyright (C) 2016-2019 by Horst Nogajski and Ryan Cramer
|
||||||
* This file licensed under Mozilla Public License v2.0 http://mozilla.org/MPL/2.0/
|
* This file licensed under Mozilla Public License v2.0 http://mozilla.org/MPL/2.0/
|
||||||
*
|
*
|
||||||
* @property bool $autoRotation
|
* @property bool $autoRotation
|
||||||
* @property bool $upscaling
|
* @property bool $upscaling
|
||||||
* @property bool $interlace
|
* @property bool $interlace
|
||||||
* @property array|string|bool $cropping
|
* @property array|string|bool $cropping
|
||||||
* @property bool $webpAdd
|
|
||||||
* @property int $webpQuality
|
|
||||||
* @property int $quality
|
* @property int $quality
|
||||||
* @property string $sharpening
|
* @property string $sharpening
|
||||||
* @property float $defaultGamma
|
* @property float $defaultGamma
|
||||||
@@ -20,6 +18,9 @@
|
|||||||
* @property string $flip
|
* @property string $flip
|
||||||
* @property bool $useUSM
|
* @property bool $useUSM
|
||||||
* @property int $enginePriority Priority for use among other ImageSizerEngine modules (0=disabled, 1=first, 2=second, 3=and so on)
|
* @property int $enginePriority Priority for use among other ImageSizerEngine modules (0=disabled, 1=first, 2=second, 3=and so on)
|
||||||
|
* @property bool $webpAdd
|
||||||
|
* @property int $webpQuality
|
||||||
|
* @property bool|null $webpResult
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
abstract class ImageSizerEngine extends WireData implements Module, ConfigurableModule {
|
abstract class ImageSizerEngine extends WireData implements Module, ConfigurableModule {
|
||||||
@@ -78,6 +79,14 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
|||||||
*/
|
*/
|
||||||
protected $webpAdd = false;
|
protected $webpAdd = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* webp result (null=not known or not applicable)
|
||||||
|
*
|
||||||
|
* @var bool|null
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected $webpResult = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Image interlace setting, false or true
|
* Image interlace setting, false or true
|
||||||
*
|
*
|
||||||
@@ -902,10 +911,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setQuality($n) {
|
public function setQuality($n) {
|
||||||
$n = (int) $n;
|
$this->quality = $this->getIntegerValue($n, 1, 100);
|
||||||
if($n < 1) $n = 1;
|
|
||||||
else if($n > 100) $n = 100;
|
|
||||||
$this->quality = $n;
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -918,10 +924,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setWebpQuality($n) {
|
public function setWebpQuality($n) {
|
||||||
$n = (int) $n;
|
$this->webpQuality = $this->getIntegerValue($n, 1, 100);
|
||||||
if($n < 1) $n = 1;
|
|
||||||
else if($n > 100) $n = 100;
|
|
||||||
$this->webpQuality = $n;
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1252,6 +1255,25 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
|||||||
if(in_array(strtolower($value), array('0', 'off', 'false', 'no', 'n', 'none'))) return false;
|
if(in_array(strtolower($value), array('0', 'off', 'false', 'no', 'n', 'none'))) return false;
|
||||||
return ((int) $value) > 0;
|
return ((int) $value) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get integer value within given range
|
||||||
|
*
|
||||||
|
* @param int $n Number to require in given range
|
||||||
|
* @param int $min Minimum allowed number
|
||||||
|
* @param int $max Maximum allowed number
|
||||||
|
* @return int
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function getIntegerValue($n, $min, $max) {
|
||||||
|
$n = (int) $n;
|
||||||
|
if($n < $min) {
|
||||||
|
$n = $min;
|
||||||
|
} else if($n > $max) {
|
||||||
|
$n = $max;
|
||||||
|
}
|
||||||
|
return $n;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an array of the current options
|
* Return an array of the current options
|
||||||
@@ -1305,6 +1327,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
|||||||
'options'
|
'options'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if($key === 'webpResult') return $this->webpResult;
|
||||||
if(in_array($key, $keys)) return $this->$key;
|
if(in_array($key, $keys)) return $this->$key;
|
||||||
if(in_array($key, $this->optionNames)) return $this->$key;
|
if(in_array($key, $this->optionNames)) return $this->$key;
|
||||||
if(isset($this->options[$key])) return $this->options[$key];
|
if(isset($this->options[$key])) return $this->options[$key];
|
||||||
|
@@ -8,10 +8,12 @@
|
|||||||
*
|
*
|
||||||
* Other user contributions as noted.
|
* Other user contributions as noted.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2016 by Horst Nogajski and Ryan Cramer
|
* Copyright (C) 2016-2019 by Horst Nogajski and Ryan Cramer
|
||||||
* This file licensed under Mozilla Public License v2.0 http://mozilla.org/MPL/2.0/
|
* This file licensed under Mozilla Public License v2.0 http://mozilla.org/MPL/2.0/
|
||||||
*
|
*
|
||||||
* https://processwire.com
|
* https://processwire.com
|
||||||
|
*
|
||||||
|
* @method bool imSaveReady($im, $filename)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class ImageSizerEngineGD extends ImageSizerEngine {
|
class ImageSizerEngineGD extends ImageSizerEngine {
|
||||||
@@ -34,6 +36,22 @@ class ImageSizerEngineGD extends ImageSizerEngine {
|
|||||||
*/
|
*/
|
||||||
protected $gammaLinearized;
|
protected $gammaLinearized;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* webp-only toggle for future use
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected $webpOnly = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Webp support available?
|
||||||
|
*
|
||||||
|
* @var bool|null
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static protected $webpSupport = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get formats GD and resize
|
* Get formats GD and resize
|
||||||
*
|
*
|
||||||
@@ -72,12 +90,12 @@ class ImageSizerEngineGD extends ImageSizerEngine {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'webp':
|
case 'webp':
|
||||||
if(!isset($this->wire('config')->webpSupportGD)) {
|
if(self::$webpSupport === null) {
|
||||||
// only call it once
|
// only call it once
|
||||||
$gd = gd_info();
|
$gd = gd_info();
|
||||||
$this->wire('config')->webpSupportGD = isset($gd['WebP Support']) ? $gd['WebP Support'] : false;
|
self::$webpSupport = isset($gd['WebP Support']) ? $gd['WebP Support'] : false;
|
||||||
}
|
}
|
||||||
return $this->wire('config')->webpSupportGD;
|
return self::$webpSupport;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'install':
|
case 'install':
|
||||||
@@ -335,61 +353,29 @@ class ImageSizerEngineGD extends ImageSizerEngine {
|
|||||||
|
|
||||||
// write to file(s)
|
// write to file(s)
|
||||||
if(file_exists($dstFilename)) $this->wire('files')->unlink($dstFilename);
|
if(file_exists($dstFilename)) $this->wire('files')->unlink($dstFilename);
|
||||||
$result = false;
|
|
||||||
|
$result = null; // null=not yet known
|
||||||
|
|
||||||
switch($this->imageType) {
|
switch($this->imageType) {
|
||||||
|
|
||||||
case \IMAGETYPE_GIF:
|
case \IMAGETYPE_GIF:
|
||||||
// correct gamma from linearized 1.0 back to 2.0
|
// correct gamma from linearized 1.0 back to 2.0
|
||||||
$this->gammaCorrection($thumb, false);
|
$this->gammaCorrection($thumb, false);
|
||||||
|
// save the final GIF image file
|
||||||
// If only a WebP file is required
|
if($this->imSaveReady($thumb, $srcFilename)) $result = imagegif($thumb, $dstFilename);
|
||||||
if($this->webpOnly) {
|
|
||||||
$result = $this->imSaveWebP($thumb, $srcFilename, $this->webpQuality);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// optionally save an additional WebP file
|
|
||||||
if($this->webpAdd) {
|
|
||||||
$resultWebp = $this->imSaveWebP($thumb, $srcFilename, $this->webpQuality);
|
|
||||||
}
|
|
||||||
|
|
||||||
// save the final GIF image file
|
|
||||||
$result = imagegif($thumb, $dstFilename);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case \IMAGETYPE_PNG:
|
case \IMAGETYPE_PNG:
|
||||||
// optionally correct gamma from linearized 1.0 back to 2.0
|
// optionally correct gamma from linearized 1.0 back to 2.0
|
||||||
if(!$this->hasAlphaChannel()) $this->gammaCorrection($thumb, false);
|
if(!$this->hasAlphaChannel()) $this->gammaCorrection($thumb, false);
|
||||||
|
// save the final PNG image file and always use highest compression level (9) per @horst
|
||||||
// If only a WebP file is required
|
if($this->imSaveReady($thumb, $srcFilename)) $result = imagepng($thumb, $dstFilename, 9);
|
||||||
if($this->webpOnly) {
|
|
||||||
$result = $this->imSaveWebP($thumb, $srcFilename, $this->webpQuality);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// optionally save an additional WebP file
|
|
||||||
if($this->webpAdd) {
|
|
||||||
$resultWebp = $this->imSaveWebP($thumb, $srcFilename, $this->webpQuality);
|
|
||||||
}
|
|
||||||
|
|
||||||
// save the final PNG image file and always use highest compression level (9) per @horst
|
|
||||||
$result = imagepng($thumb, $dstFilename, 9);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case \IMAGETYPE_JPEG:
|
case \IMAGETYPE_JPEG:
|
||||||
// correct gamma from linearized 1.0 back to 2.0
|
// correct gamma from linearized 1.0 back to 2.0
|
||||||
$this->gammaCorrection($thumb, false);
|
$this->gammaCorrection($thumb, false);
|
||||||
|
if($this->imSaveReady($thumb, $srcFilename)) {
|
||||||
// If only a WebP file is required
|
|
||||||
if($this->webpOnly) {
|
|
||||||
$result = $this->imSaveWebP($thumb, $srcFilename, $this->webpQuality);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// optionally save an additional WebP file
|
|
||||||
if($this->webpAdd) {
|
|
||||||
$resultWebp = $this->imSaveWebP($thumb, $srcFilename, $this->webpQuality);
|
|
||||||
}
|
|
||||||
|
|
||||||
// optionally apply interlace bit to the final image. this will result in progressive JPEGs
|
// optionally apply interlace bit to the final image. this will result in progressive JPEGs
|
||||||
if($this->interlace) {
|
if($this->interlace) {
|
||||||
if(0 == imageinterlace($thumb, 1)) {
|
if(0 == imageinterlace($thumb, 1)) {
|
||||||
@@ -397,26 +383,46 @@ class ImageSizerEngineGD extends ImageSizerEngine {
|
|||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// save the final JPEG image file
|
// save the final JPEG image file
|
||||||
$result = imagejpeg($thumb, $dstFilename, $this->quality);
|
$result = imagejpeg($thumb, $dstFilename, $this->quality);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
$result = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// release the last GD image object
|
// release the last GD image object
|
||||||
if(isset($thumb) && is_resource($thumb)) @imagedestroy($thumb);
|
if(isset($thumb) && is_resource($thumb)) @imagedestroy($thumb);
|
||||||
if(isset($thumb)) $thumb = null;
|
if(isset($thumb)) $thumb = null;
|
||||||
|
if($result === null) $result = $this->webpResult; // if webpOnly option used
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called before saving of image, returns true if save should proceed, false if not
|
||||||
|
*
|
||||||
|
* Also Creates a webp file when settings indicate it should.
|
||||||
|
*
|
||||||
|
* @param resource $im
|
||||||
|
* @param string $filename Source filename
|
||||||
|
* @return bool
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function ___imSaveReady($im, $filename) {
|
||||||
|
if($this->webpOnly || $this->webpAdd) {
|
||||||
|
$this->webpResult = $this->imSaveWebP($im, $filename, $this->webpQuality);
|
||||||
|
}
|
||||||
|
return $this->webpOnly ? false : true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create WebP image (@horst)
|
* Create WebP image (@horst)
|
||||||
* Is requested by image options: ["webpAdd" => true] OR ["webpOnly" => true]
|
* Is requested by image options: ["webpAdd" => true] OR ["webpOnly" => true]
|
||||||
*
|
*
|
||||||
* @param resource $im
|
* @param resource $im
|
||||||
* @param string $dstFilename
|
* @param string $filename
|
||||||
* @param int $quality
|
* @param int $quality
|
||||||
*
|
*
|
||||||
* @return boolean true | false
|
* @return boolean true | false
|
||||||
@@ -582,7 +588,7 @@ class ImageSizerEngineGD extends ImageSizerEngine {
|
|||||||
* with mode = true it linearizes an image to 1
|
* with mode = true it linearizes an image to 1
|
||||||
* with mode = false it set it back to the originating gamma value
|
* with mode = false it set it back to the originating gamma value
|
||||||
*
|
*
|
||||||
* @param GD -image-resource $image
|
* @param resource $image
|
||||||
* @param bool $mode
|
* @param bool $mode
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -817,8 +823,8 @@ class ImageSizerEngineGD extends ImageSizerEngine {
|
|||||||
*
|
*
|
||||||
* Intended for use by the resize() method
|
* Intended for use by the resize() method
|
||||||
*
|
*
|
||||||
* @param GD -resource $im, destination resource needs to be prepared
|
* @param resource $im, destination resource needs to be prepared
|
||||||
* @param GD -resource $image, with GIF we need to read from source resource
|
* @param resource $image, with GIF we need to read from source resource
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected function prepareImageLayer(&$im, &$image) {
|
protected function prepareImageLayer(&$im, &$image) {
|
||||||
|
@@ -63,6 +63,12 @@ class Pagefile extends WireData {
|
|||||||
*/
|
*/
|
||||||
protected $pagefiles;
|
protected $pagefiles;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var PagefileExtra[]
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected $extras = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extra file data
|
* Extra file data
|
||||||
*
|
*
|
||||||
@@ -952,8 +958,13 @@ class Pagefile extends WireData {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function unlink() {
|
public function unlink() {
|
||||||
if(!strlen($this->basename) || !is_file($this->filename)) return true;
|
/** @var WireFileTools $files */
|
||||||
return $this->wire('files')->unlink($this->filename, true);
|
if(!strlen($this->basename) || !is_file($this->filename)) return true;
|
||||||
|
$files = $this->wire('files');
|
||||||
|
foreach($this->extras() as $extra) {
|
||||||
|
$extra->unlink();
|
||||||
|
}
|
||||||
|
return $files->unlink($this->filename, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -968,10 +979,17 @@ class Pagefile extends WireData {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function rename($basename) {
|
public function rename($basename) {
|
||||||
|
foreach($this->extras() as $extra) {
|
||||||
|
$extra->filename(); // init
|
||||||
|
}
|
||||||
$basename = $this->pagefiles->cleanBasename($basename, true);
|
$basename = $this->pagefiles->cleanBasename($basename, true);
|
||||||
if($this->wire('files')->rename($this->filename, $this->pagefiles->path . $basename, true)) {
|
if($this->wire('files')->rename($this->filename, $this->pagefiles->path . $basename, true)) {
|
||||||
$this->set('basename', $basename);
|
$this->set('basename', $basename);
|
||||||
return $this->basename();
|
$basename = $this->basename();
|
||||||
|
foreach($this->extras() as $extra) {
|
||||||
|
$extra->rename();
|
||||||
|
}
|
||||||
|
return $basename;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -986,8 +1004,13 @@ class Pagefile extends WireData {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function copyToPath($path) {
|
public function copyToPath($path) {
|
||||||
$result = copy($this->filename, $path . $this->basename());
|
/** @var WireFileTools $files */
|
||||||
if($this->config->chmodFile) chmod($path . $this->basename(), octdec($this->config->chmodFile));
|
$files = $this->wire('files');
|
||||||
|
$result = $files->copy($this->filename(), $path);
|
||||||
|
foreach($this->extras() as $extra) {
|
||||||
|
if(!$extra->exists()) continue;
|
||||||
|
$files->copy($extra->filename, $path);
|
||||||
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1040,6 +1063,25 @@ class Pagefile extends WireData {
|
|||||||
return $this->pagefiles->isTemp($this, $set);
|
return $this->pagefiles->isTemp($this, $set);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all extras, add an extra, or get an extra
|
||||||
|
*
|
||||||
|
* #pw-internal
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param PagefileExtra $value
|
||||||
|
* @return PagefileExtra[]|PagefileExtra|null
|
||||||
|
* @since 3.0.132
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function extras($name = null, PagefileExtra $value = null) {
|
||||||
|
if($name === null) return $this->extras;
|
||||||
|
if($value !== null && $value instanceof PagefileExtra) {
|
||||||
|
$this->extras[$name] = $value;
|
||||||
|
}
|
||||||
|
return isset($this->extras[$name]) ? $this->extras[$name] : null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Debug info
|
* Debug info
|
||||||
*
|
*
|
||||||
|
228
wire/core/PagefileExtra.php
Normal file
228
wire/core/PagefileExtra.php
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
<?php namespace ProcessWire;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extra extension for Pagefile or Pageimage objects
|
||||||
|
*
|
||||||
|
* @property string $url Local URL/path to file
|
||||||
|
* @property string $httpUrl Full HTTP URL with scheme and host
|
||||||
|
* @property string $URL No-cache version of url
|
||||||
|
* @property string $HTTPURL No-cache version of httpUrl
|
||||||
|
* @property string $filename Full disk path/file
|
||||||
|
* @property string $pathname Alias of filename
|
||||||
|
* @property string $basename Just the basename without path
|
||||||
|
* @property string $extension File extension
|
||||||
|
* @property string $ext Alias of extension
|
||||||
|
* @property bool $exists Does the file exist?
|
||||||
|
* @property int $filesize Size of file in bytes
|
||||||
|
* @property Pageimage $pagefile Source Pageimage objerct
|
||||||
|
*
|
||||||
|
* @method create()
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class PagefileExtra extends WireData {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Pagefile|Pageimage
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected $pagefile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected $extension = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Previous filename, if it changed
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected $filenamePrevious = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct
|
||||||
|
*
|
||||||
|
* @param Pagefile|Pageimage $pagefile
|
||||||
|
* @param $extension
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct(Pagefile $pagefile, $extension) {
|
||||||
|
$pagefile->wire($this);
|
||||||
|
$this->setPagefile($pagefile);
|
||||||
|
$this->setExtension($extension);
|
||||||
|
return parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set Pagefile instance this extra is connected to
|
||||||
|
*
|
||||||
|
* @param Pagefile $pagefile
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function setPagefile(Pagefile $pagefile) {
|
||||||
|
$this->pagefile = $pagefile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set extension for this extra
|
||||||
|
*
|
||||||
|
* @param $extension
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function setExtension($extension) {
|
||||||
|
$this->extension = $extension;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the extra file currently exist?
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function exists() {
|
||||||
|
return is_readable($this->filename());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the file size in bytes
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function filesize() {
|
||||||
|
return $this->exists() ? filesize($this->filename()) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the full server disk path to the extra file, whether it exists or not
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function filename() {
|
||||||
|
$pathinfo = pathinfo($this->pagefile->filename());
|
||||||
|
$filename = $pathinfo['dirname'] . '/' . $pathinfo['filename'] . '.' . $this->extension;
|
||||||
|
if(empty($this->filenamePrevious)) $this->filenamePrevious = $filename;
|
||||||
|
return $filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return just the basename (no path)
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function basename() {
|
||||||
|
return basename($this->filename());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the URL to the extra file, creating it if it does not already exist
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function url() {
|
||||||
|
if(!$this->exists()) $this->create();
|
||||||
|
$pathinfo = pathinfo($this->pagefile->url());
|
||||||
|
return $pathinfo['dirname'] . '/' . $pathinfo['filename'] . '.' . $this->extension;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the HTTP URL to the extra file
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function httpUrl() {
|
||||||
|
return str_replace($this->pagefile->url(), $this->url(), $this->pagefile->httpUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unlink/delete the extra file
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function unlink() {
|
||||||
|
if(!$this->exists()) return false;
|
||||||
|
return $this->wire('files')->unlink($this->filename());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rename the extra file to be consistent with Pagefile name
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function rename() {
|
||||||
|
if(!$this->exists()) return false;
|
||||||
|
if(!$this->filenamePrevious) return false;
|
||||||
|
return $this->wire('files')->rename($this->filenamePrevious, $this->filename());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the extra file
|
||||||
|
*
|
||||||
|
* Must be implemented by a hook or by descending class
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function ___create() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get property
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* @return bool|int|mixed|null|string
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function get($key) {
|
||||||
|
switch($key) {
|
||||||
|
case 'exists':
|
||||||
|
$value = $this->exists();
|
||||||
|
break;
|
||||||
|
case 'filesize':
|
||||||
|
$value = $this->filesize();
|
||||||
|
break;
|
||||||
|
case 'url':
|
||||||
|
$value = $this->url();
|
||||||
|
break;
|
||||||
|
case 'filename':
|
||||||
|
case 'pathname':
|
||||||
|
$value = $this->filename();
|
||||||
|
break;
|
||||||
|
case 'filenamePrevious':
|
||||||
|
$value = $this->filenamePrevious && $this->filenamePrevious != $this->filename() ? $this->filenamePrevious : '';
|
||||||
|
break;
|
||||||
|
case 'basename':
|
||||||
|
$value = $this->basename();
|
||||||
|
break;
|
||||||
|
case 'ext':
|
||||||
|
case 'extension':
|
||||||
|
$value = $this->extension;
|
||||||
|
break;
|
||||||
|
case 'URL':
|
||||||
|
case 'HTTPURL':
|
||||||
|
$value = str_replace($this->pagefile->url(), $this->url(), $this->pagefile->$key);
|
||||||
|
break;
|
||||||
|
case 'pagefile':
|
||||||
|
$value = $this->pagefile;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$value = $this->pagefile->get($key);
|
||||||
|
}
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function __toString() {
|
||||||
|
return $this->basename();
|
||||||
|
}
|
||||||
|
}
|
@@ -40,11 +40,7 @@
|
|||||||
* @property-read string $suffixStr String of file suffix(es) separated by comma.
|
* @property-read string $suffixStr String of file suffix(es) separated by comma.
|
||||||
* @property-read string $alt Convenient alias for the 'description' property, unless overridden (since 3.0.125).
|
* @property-read string $alt Convenient alias for the 'description' property, unless overridden (since 3.0.125).
|
||||||
* @property-read string $src Convenient alias for the 'url' property, unless overridden (since 3.0.125).
|
* @property-read string $src Convenient alias for the 'url' property, unless overridden (since 3.0.125).
|
||||||
* @property-read string $urlWebp The url property of an optional WebP-dependency file (since 3.0.132).
|
* @property-read PagefileExtra $webp Access webp version of image (since 3.0.132)
|
||||||
* @property-read string $srcWebp Convenient alias for the 'urlWebp' property (since 3.0.132).
|
|
||||||
* @property-read string $webpUrl Convenient alias for the 'urlWebp' property (since 3.0.132).
|
|
||||||
* @property-read string $webpSrc Convenient alias for the 'urlWebp' property (since 3.0.132).
|
|
||||||
* @property-read bool $hasWebp Does exist an optional WebP-dependency file for this image variation? (since 3.0.132)
|
|
||||||
*
|
*
|
||||||
* Properties inherited from Pagefile
|
* Properties inherited from Pagefile
|
||||||
* ==================================
|
* ==================================
|
||||||
@@ -72,6 +68,7 @@
|
|||||||
* @property Pagefiles $pagefiles The Pagefiles WireArray that contains this file. #pw-group-other
|
* @property Pagefiles $pagefiles The Pagefiles WireArray that contains this file. #pw-group-other
|
||||||
* @property Page $page The Page object that this file is part of. #pw-group-other
|
* @property Page $page The Page object that this file is part of. #pw-group-other
|
||||||
* @property Field $field The Field object that this file is part of. #pw-group-other
|
* @property Field $field The Field object that this file is part of. #pw-group-other
|
||||||
|
* @property PageimageDebugInfo $debugInfo
|
||||||
*
|
*
|
||||||
* Hookable methods
|
* Hookable methods
|
||||||
* ================
|
* ================
|
||||||
@@ -122,7 +119,13 @@ class Pageimage extends Pagefile {
|
|||||||
private $imageInfo = array(
|
private $imageInfo = array(
|
||||||
'width' => 0,
|
'width' => 0,
|
||||||
'height' => 0,
|
'height' => 0,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var PageimageDebugInfo|null
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private $pageimageDebugInfo = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Last size error, if one occurred.
|
* Last size error, if one occurred.
|
||||||
@@ -132,6 +135,14 @@ class Pageimage extends Pagefile {
|
|||||||
*/
|
*/
|
||||||
protected $error = '';
|
protected $error = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last Pageimage::size() $options argument
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static protected $lastSizeOptions = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new Pageimage
|
* Construct a new Pageimage
|
||||||
*
|
*
|
||||||
@@ -161,6 +172,7 @@ class Pageimage extends Pagefile {
|
|||||||
public function __clone() {
|
public function __clone() {
|
||||||
$this->imageInfo['width'] = 0;
|
$this->imageInfo['width'] = 0;
|
||||||
$this->imageInfo['height'] = 0;
|
$this->imageInfo['height'] = 0;
|
||||||
|
$this->extras = array();
|
||||||
parent::__clone();
|
parent::__clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,45 +192,6 @@ class Pageimage extends Pagefile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the web accessible URL to this image files webP dependency, also if no webp copy exists!
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public function webpUrl() {
|
|
||||||
$path_parts = pathinfo($this->url);
|
|
||||||
$webpUrl = $path_parts['dirname'] . '/' . $path_parts['filename'] . '.webp';
|
|
||||||
return $webpUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the filesystem path to this image files webP dependency
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public function webpFilename() {
|
|
||||||
if(!$this->hasWebp()) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
$path_parts = pathinfo($this->filename);
|
|
||||||
$webpFilename = $path_parts['dirname'] . '/' . $path_parts['filename'] . '.webp';
|
|
||||||
return $webpFilename;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return if this image file has a webP dependency file
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public function hasWebp() {
|
|
||||||
$path_parts = pathinfo($this->filename());
|
|
||||||
$webpFilename = $path_parts['dirname'] . '/' . $path_parts['filename'] . '.webp';
|
|
||||||
return is_readable($webpFilename);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the full disk path to the image file
|
* Returns the full disk path to the image file
|
||||||
*
|
*
|
||||||
@@ -435,17 +408,21 @@ class Pageimage extends Pagefile {
|
|||||||
$value = parent::get('src');
|
$value = parent::get('src');
|
||||||
if($value === null) $value = $this->url();
|
if($value === null) $value = $this->url();
|
||||||
break;
|
break;
|
||||||
case 'hasWebp':
|
case 'webp':
|
||||||
$value = $this->hasWebp();
|
$value = $this->webp();
|
||||||
|
break;
|
||||||
|
case 'hasWebp':
|
||||||
|
$value = $this->webp()->exists();
|
||||||
break;
|
break;
|
||||||
case 'webpUrl':
|
case 'webpUrl':
|
||||||
case 'webpSrc':
|
$value = $this->webp()->url();
|
||||||
case 'urlWebp':
|
|
||||||
case 'srcWebp':
|
|
||||||
$value = $this->webpUrl();
|
|
||||||
break;
|
break;
|
||||||
case 'webpFilename':
|
case 'webpFilename':
|
||||||
$value = $this->webpFilename();
|
$value = $this->webp()->filename();
|
||||||
|
break;
|
||||||
|
case 'debugInfo':
|
||||||
|
if(!$this->pageimageDebugInfo) $this->pageimageDebugInfo = new PageimageDebugInfo($this);
|
||||||
|
$value = $this->pageimageDebugInfo;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$value = parent::get($key);
|
$value = parent::get($key);
|
||||||
@@ -596,6 +573,8 @@ class Pageimage extends Pagefile {
|
|||||||
* - `focus` (bool): Should resizes that result in crop use focus area if available? (default=true).
|
* - `focus` (bool): Should resizes that result in crop use focus area if available? (default=true).
|
||||||
* In order for focus to be applicable, resize must include both width and height.
|
* In order for focus to be applicable, resize must include both width and height.
|
||||||
* - `allowOriginal` (bool): Return original if already at width/height? May not be combined with other options. (default=false)
|
* - `allowOriginal` (bool): Return original if already at width/height? May not be combined with other options. (default=false)
|
||||||
|
* - `webpAdd` (bool): Also create a secondary .webp image variation? (default=false)
|
||||||
|
* - `webpQuality` (int): Quality setting for extra webp images (default=90).
|
||||||
*
|
*
|
||||||
* **Possible values for "cropping" option**
|
* **Possible values for "cropping" option**
|
||||||
*
|
*
|
||||||
@@ -640,10 +619,16 @@ class Pageimage extends Pagefile {
|
|||||||
public function size($width, $height, $options = array()) {
|
public function size($width, $height, $options = array()) {
|
||||||
|
|
||||||
if($this->wire('hooks')->isHooked('Pageimage::size()')) {
|
if($this->wire('hooks')->isHooked('Pageimage::size()')) {
|
||||||
return $this->__call('size', array($width, $height, $options));
|
$result = $this->__call('size', array($width, $height, $options));
|
||||||
} else {
|
} else {
|
||||||
return $this->___size($width, $height, $options);
|
$result = $this->___size($width, $height, $options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$options['_width'] = $width;
|
||||||
|
$options['_height'] = $height;
|
||||||
|
self::$lastSizeOptions = $options;
|
||||||
|
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -707,10 +692,14 @@ class Pageimage extends Pagefile {
|
|||||||
);
|
);
|
||||||
|
|
||||||
$this->error = '';
|
$this->error = '';
|
||||||
|
|
||||||
|
/** @var WireFileTools $files */
|
||||||
/** @var Config $config */
|
/** @var Config $config */
|
||||||
|
$files = $this->wire('files');
|
||||||
$config = $this->wire('config');
|
$config = $this->wire('config');
|
||||||
$debug = $config->debug;
|
$debug = $config->debug;
|
||||||
$configOptions = $config->imageSizerOptions;
|
$configOptions = $config->imageSizerOptions;
|
||||||
|
|
||||||
if(!is_array($configOptions)) $configOptions = array();
|
if(!is_array($configOptions)) $configOptions = array();
|
||||||
$options = array_merge($defaultOptions, $configOptions, $options);
|
$options = array_merge($defaultOptions, $configOptions, $options);
|
||||||
if($options['cropping'] === 1) $options['cropping'] = true;
|
if($options['cropping'] === 1) $options['cropping'] = true;
|
||||||
@@ -789,36 +778,36 @@ class Pageimage extends Pagefile {
|
|||||||
$nameHeight = is_int($options['nameHeight']) ? $options['nameHeight'] : $height;
|
$nameHeight = is_int($options['nameHeight']) ? $options['nameHeight'] : $height;
|
||||||
|
|
||||||
// i.e. myfile.100x100.jpg or myfile.100x100nw-suffix1-suffix2.jpg
|
// i.e. myfile.100x100.jpg or myfile.100x100nw-suffix1-suffix2.jpg
|
||||||
$basename .= '.' . $nameWidth . 'x' . $nameHeight . $crop . $suffixStr . "." . $this->ext();
|
$basenameNoExt = $basename . '.' . $nameWidth . 'x' . $nameHeight . $crop . $suffixStr; // basename without ext
|
||||||
$filenameFinal = $this->pagefiles->path() . $basename;
|
$basename = $basenameNoExt . '.' . $this->ext(); // basename with ext
|
||||||
|
|
||||||
$filenameUnvalidated = '';
|
$filenameUnvalidated = '';
|
||||||
$exists = file_exists($filenameFinal);
|
$filenameUnvalidatedWebp = '';
|
||||||
|
|
||||||
$path_parts = pathinfo($filenameFinal);
|
$filenameFinal = $this->pagefiles->path() . $basename;
|
||||||
$filenameFinalWebp = $this->pagefiles->path() . $path_parts['filename'] . '.webp';
|
$filenameFinalExists = file_exists($filenameFinal);
|
||||||
|
$filenameFinalWebp = $this->pagefiles->path() . $basenameNoExt . '.webp';
|
||||||
|
|
||||||
// force new creation if requested webp copy doesn't exist, (regardless if regular variation exists or not)
|
// force new creation if requested webp copy doesn't exist, (regardless if regular variation exists or not)
|
||||||
if($options['webpAdd'] && !file_exists($filenameFinalWebp)) {
|
if($options['webpAdd'] && !file_exists($filenameFinalWebp)) $options['forceNew'] = true;
|
||||||
$options['forceNew'] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a new resize if it doesn't already exist or forceNew option is set
|
// create a new resize if it doesn't already exist or forceNew option is set
|
||||||
if(!$exists && !file_exists($this->filename())) {
|
if(!$filenameFinalExists && !file_exists($this->filename())) {
|
||||||
// no original file exists to create variation from
|
// no original file exists to create variation from
|
||||||
$this->error = "Original image does not exist to create size variation";
|
$this->error = "Original image does not exist to create size variation";
|
||||||
|
|
||||||
} else if(!$exists || $options['forceNew']) {
|
} else if(!$filenameFinalExists || $options['forceNew']) {
|
||||||
|
|
||||||
// filenameUnvalidated is temporary filename used for resize
|
// filenameUnvalidated is temporary filename used for resize
|
||||||
$tempDir = $this->pagefiles->page->filesManager()->getTempPath();
|
$tempDir = $this->pagefiles->page->filesManager()->getTempPath();
|
||||||
$filenameUnvalidated = $tempDir . $basename;
|
$filenameUnvalidated = $tempDir . $basename;
|
||||||
$path_parts = pathinfo($filenameUnvalidated);
|
$filenameUnvalidatedWebp = $tempDir . basename($filenameFinalWebp);
|
||||||
$filenameUnvalidatedWebp = $tempDir . $path_parts['filename'] . '.webp';
|
|
||||||
|
|
||||||
if($exists && $options['forceNew']) $this->wire('files')->unlink($filenameFinal, true);
|
if($filenameFinalExists && $options['forceNew']) $files->unlink($filenameFinal, true);
|
||||||
if(file_exists($filenameFinalWebp) && $options['forceNew']) $this->wire('files')->unlink($filenameFinalWebp, true);
|
if(file_exists($filenameFinalWebp) && $options['forceNew']) $files->unlink($filenameFinalWebp, true);
|
||||||
|
|
||||||
if(file_exists($filenameUnvalidated)) $this->wire('files')->unlink($filenameUnvalidated, true);
|
if(file_exists($filenameUnvalidated)) $files->unlink($filenameUnvalidated, true);
|
||||||
if(file_exists($filenameUnvalidatedWebp)) $this->wire('files')->unlink($filenameUnvalidatedWebp, true);
|
if(file_exists($filenameUnvalidatedWebp)) $files->unlink($filenameUnvalidatedWebp, true);
|
||||||
|
|
||||||
if(@copy($this->filename(), $filenameUnvalidated)) {
|
if(@copy($this->filename(), $filenameUnvalidated)) {
|
||||||
try {
|
try {
|
||||||
@@ -832,7 +821,7 @@ class Pageimage extends Pagefile {
|
|||||||
$engine = $sizer->getEngine();
|
$engine = $sizer->getEngine();
|
||||||
|
|
||||||
/* if the current engine installation does not support webp, modify the options param */
|
/* if the current engine installation does not support webp, modify the options param */
|
||||||
if(isset($options['webpAdd']) && $options['webpAdd'] && !$engine->supported('webp')) {
|
if(!empty($options['webpAdd']) && !$engine->supported('webp')) {
|
||||||
$options['webpAdd'] = false;
|
$options['webpAdd'] = false;
|
||||||
$engine->setOptions($options);
|
$engine->setOptions($options);
|
||||||
}
|
}
|
||||||
@@ -851,23 +840,18 @@ class Pageimage extends Pagefile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($sizer->resize($width, $height) && @rename($filenameUnvalidated, $filenameFinal)) {
|
if($sizer->resize($width, $height) && $files->rename($filenameUnvalidated, $filenameFinal)) {
|
||||||
$this->wire('files')->chmod($filenameFinal);
|
if($options['webpAdd'] && file_exists($filenameUnvalidatedWebp)) {
|
||||||
if($options['webpAdd'] && file_exists(($filenameUnvalidatedWebp)) && @rename($filenameUnvalidatedWebp, $filenameFinalWebp)) {
|
$files->rename($filenameUnvalidatedWebp, $filenameFinalWebp);
|
||||||
$this->wire('files')->chmod($filenameFinalWebp);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$this->error = "ImageSizer::resize($width, $height) failed for $filenameUnvalidated";
|
$this->error = "ImageSizer::resize($width, $height) failed for $filenameUnvalidated";
|
||||||
}
|
}
|
||||||
|
|
||||||
$timer = $debug ? Debug::timer($timer) : null;
|
|
||||||
if($debug) $this->wire('log')->save('image-sizer',
|
if($debug) $this->wire('log')->save('image-sizer',
|
||||||
str_replace('ImageSizerEngine', '', $sizer->getEngine()) . ' ' .
|
str_replace('ImageSizerEngine', '', $sizer->getEngine()) . ' ' .
|
||||||
($this->error ? "FAILED Resize: " : "Resized: ") .
|
($this->error ? "FAILED Resize: " : "Resized: ") . "$originalName => " . basename($filenameFinal) . " " .
|
||||||
"$originalName => " .
|
"({$width}x{$height}) " . Debug::timer($timer) . " secs $originalSize => " . filesize($filenameFinal) . " bytes " .
|
||||||
basename($filenameFinal) . " " .
|
|
||||||
"({$width}x{$height}) $timer secs " .
|
|
||||||
"$originalSize => " . filesize($filenameFinal) . " bytes " .
|
|
||||||
"(quality=$options[quality], sharpening=$options[sharpening]) "
|
"(quality=$options[quality], sharpening=$options[sharpening]) "
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -885,11 +869,11 @@ class Pageimage extends Pagefile {
|
|||||||
// if desired, user can check for property of $pageimage->error to see if an error occurred.
|
// if desired, user can check for property of $pageimage->error to see if an error occurred.
|
||||||
// if an error occurred, that error property will be populated with details
|
// if an error occurred, that error property will be populated with details
|
||||||
if($this->error) {
|
if($this->error) {
|
||||||
// error condition: unlink copied file
|
// error condition: unlink copied files
|
||||||
if(is_file($filenameFinal)) $this->wire('files')->unlink($filenameFinal, true);
|
if($filenameFinal && is_file($filenameFinal)) $files->unlink($filenameFinal, true);
|
||||||
if($filenameUnvalidated && is_file($filenameUnvalidated)) $this->wire('files')->unlink($filenameUnvalidated);
|
if($filenameUnvalidated && is_file($filenameUnvalidated)) $files->unlink($filenameUnvalidated);
|
||||||
if(is_file($filenameFinalWebp)) $this->wire('files')->unlink($filenameFinalWebp, true);
|
if($filenameFinalWebp && is_file($filenameFinalWebp)) $files->unlink($filenameFinalWebp, true);
|
||||||
if(is_file($filenameUnvalidatedWebp)) $this->wire('files')->unlink($filenameUnvalidatedWebp, true);
|
if($filenameUnvalidatedWebp && is_file($filenameUnvalidatedWebp)) $files->unlink($filenameUnvalidatedWebp);
|
||||||
|
|
||||||
// we also tell PW about it for logging and/or admin purposes
|
// we also tell PW about it for logging and/or admin purposes
|
||||||
$this->error($this->error);
|
$this->error($this->error);
|
||||||
@@ -1668,16 +1652,13 @@ class Pageimage extends Pagefile {
|
|||||||
}
|
}
|
||||||
if($success) $deletedFiles[] = $filename;
|
if($success) $deletedFiles[] = $filename;
|
||||||
|
|
||||||
// Also remove WebP variation, if there exist one
|
foreach($this->extras() as $extra) {
|
||||||
$path_parts = pathinfo($filename);
|
if($options['dryRun']) {
|
||||||
$webp = dirname($filename) . '/' . $path_parts['filename'] . '.webp';
|
$deletedFiles[] = $extra->filename();
|
||||||
if(!is_file($webp)) continue;
|
} else if($extra->unlink()) {
|
||||||
if($options['dryRun']) {
|
$deletedFiles[] = $extra->filename();
|
||||||
$success = true;
|
}
|
||||||
} else {
|
|
||||||
$success = $files->unlink($webp, true);
|
|
||||||
}
|
}
|
||||||
if($success) $deletedFiles[] = $webp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!$options['dryRun']) $this->variations = null;
|
if(!$options['dryRun']) $this->variations = null;
|
||||||
@@ -1728,7 +1709,7 @@ class Pageimage extends Pagefile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy this Pageimage and any of it's variations to another path
|
* Copy this Pageimage and any of its variations to another path
|
||||||
*
|
*
|
||||||
* #pw-internal
|
* #pw-internal
|
||||||
*
|
*
|
||||||
@@ -1739,10 +1720,8 @@ class Pageimage extends Pagefile {
|
|||||||
public function copyToPath($path) {
|
public function copyToPath($path) {
|
||||||
if(parent::copyToPath($path)) {
|
if(parent::copyToPath($path)) {
|
||||||
foreach($this->getVariations() as $variation) {
|
foreach($this->getVariations() as $variation) {
|
||||||
if(is_file($variation->filename)) {
|
if(!is_file($variation->filename)) continue;
|
||||||
copy($variation->filename, $path . $variation->basename);
|
$this->wire('files')->copy($variation->filename, $path);
|
||||||
if($this->config->chmodFile) chmod($path . $variation->basename, octdec($this->config->chmodFile));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1906,222 +1885,95 @@ class Pageimage extends Pagefile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get verbose DebugInfo, optionally with individual options array, @horst
|
* Get WebP "extra" version of this Pageimage
|
||||||
* (without invoking the magic debug)
|
*
|
||||||
|
* @return PagefileExtra
|
||||||
|
* @since 3.0.132
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function webp() {
|
||||||
|
$webp = $this->extras('webp');
|
||||||
|
if(!$webp) {
|
||||||
|
$webp = new PagefileExtra($this, 'webp');
|
||||||
|
$this->extras('webp', $webp);
|
||||||
|
$webp->addHookAfter('create', $this, 'hookWebpCreate');
|
||||||
|
}
|
||||||
|
return $webp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook to PageimageExtra (.webp) create method
|
||||||
*
|
*
|
||||||
* @param array $options The individual options you also passes with your image variation creation
|
* #pw-internal
|
||||||
* @param bool $returnType 'string'|'array'|'object', default is 'string' and returns markup or plain text
|
*
|
||||||
* @return array|object|string
|
* @param HookEvent $event
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function getDebugInfo($options = array(), $returnType = 'string') {
|
public function hookWebpCreate(HookEvent $event) {
|
||||||
static $depth = 0;
|
if(!$this->original) return;
|
||||||
$depth++;
|
/** @var PagefileExtra $webp */
|
||||||
|
$webp = $event->object;
|
||||||
// fetch imagesizer, some infos and some options
|
$webp->unlink();
|
||||||
$oSizer = new ImageSizer($this->filename, $options);
|
$options = self::$lastSizeOptions;
|
||||||
$osInfo = $oSizer->getImageInfo(true);
|
$options['webpAdd'] = true;
|
||||||
$finalOptions = $oSizer->getOptions();
|
$this->original->size($options['_width'], $options['_height'], $options);
|
||||||
|
|
||||||
// build some info parts and fetch some from parent (pagefile)
|
|
||||||
$thumb = array('thumb' => "<img src='{$this->url}' style='max-width:120px; max-height:120px; ".($this->width() >= $this->height() ? 'width:100px; height:auto;' : 'height:100px; width:auto;')."' alt='' />");
|
|
||||||
$original = $this->original ? array('original' => $this->original->basename, 'basename' => $this->basename) : array('original' => '{SELF}', 'basename' => $this->basename);
|
|
||||||
$parent = array('files' => array_merge(
|
|
||||||
$original,
|
|
||||||
parent::__debugInfo(),
|
|
||||||
array(
|
|
||||||
'suffix' => isset($finalOptions['suffix']) ? $finalOptions['suffix'] : '',
|
|
||||||
'extension' => $osInfo['extension']
|
|
||||||
)
|
|
||||||
));
|
|
||||||
// rearange parts
|
|
||||||
unset($parent['files']['filesize']);
|
|
||||||
$parent['files']['filesize'] = filesize($this->filename);
|
|
||||||
|
|
||||||
// VARIATIONS
|
|
||||||
if($depth < 2) {
|
|
||||||
$variationArray = array();
|
|
||||||
$variations = $this->getVariations(array('info' => true, 'verbose' => false));
|
|
||||||
foreach($variations as $name) $variationArray[] = $name;
|
|
||||||
}
|
|
||||||
$depth--;
|
|
||||||
unset($variations, $name);
|
|
||||||
|
|
||||||
// start collecting the $info
|
|
||||||
$info = array_merge($thumb, $parent,
|
|
||||||
array('variations' => $variationArray),
|
|
||||||
array('imageinfo' => array(
|
|
||||||
'imageType' => $osInfo['info']['imageType'],
|
|
||||||
'mime' => $osInfo['info']['mime'],
|
|
||||||
'width' => $this->width(),
|
|
||||||
'height' => $this->height(),
|
|
||||||
'focus' => $this->hasFocus ? $this->focusStr : NULL,
|
|
||||||
'description' => $parent['files']['description'],
|
|
||||||
'tags' => $parent['files']['tags'],
|
|
||||||
))
|
|
||||||
);
|
|
||||||
unset($info['files']['tags'], $info['files']['description']);
|
|
||||||
|
|
||||||
// beautify the output, remove unnecessary items
|
|
||||||
if(isset($info['files']['filedata']) && isset($info['files']['filedata']['focus'])) unset($info['files']['filedata']['focus']);
|
|
||||||
if(empty($info['files']['filedata'])) unset($info['files']['filedata']);
|
|
||||||
unset($osInfo['info']['mime'], $osInfo['info']['imageType']);
|
|
||||||
|
|
||||||
// add the rest from osInfo to the final $info array
|
|
||||||
foreach($osInfo['info'] as $k => $v) $info['imageinfo'][$k] = $v;
|
|
||||||
$info['imageinfo']['iptcRaw'] = $osInfo['iptcRaw'];
|
|
||||||
unset($osInfo, $thumb, $original, $parent);
|
|
||||||
|
|
||||||
// WEBP
|
|
||||||
$webp = array('webp_copy' => array(
|
|
||||||
'hasWebp' => $this->hasWebp(),
|
|
||||||
'webpUrl' => (!$this->hasWebp() ? NULL : $this->webpUrl),
|
|
||||||
'webpQuality' => (!isset($finalOptions['webpQuality']) ? NULL : $finalOptions['webpQuality']),
|
|
||||||
'filesize' => (!$this->hasWebp() ? 0 : filesize($this->webpFilename())),
|
|
||||||
'savings' => (!$this->hasWebp() ? 0 : intval($info['files']['filesize'] - filesize($this->webpFilename()))),
|
|
||||||
'savings_percent' => (!$this->hasWebp() ? 0 : 100 - intval(filesize($this->webpFilename()) / ($info['files']['filesize'] / 100))),
|
|
||||||
));
|
|
||||||
|
|
||||||
// ENGINES
|
|
||||||
$a = [];
|
|
||||||
$modules = $this->wire('modules');
|
|
||||||
$engines = array_merge($oSizer->getEngines(), array('ImageSizerEngineGD'));
|
|
||||||
foreach($engines as $moduleName) {
|
|
||||||
$configData = $modules->getModuleConfigData($moduleName);
|
|
||||||
$priority = isset($configData['enginePriority']) ? (int) $configData['enginePriority'] : 0;
|
|
||||||
$a[$moduleName] = "priority {$priority}";
|
|
||||||
}
|
|
||||||
asort($a, SORT_STRING);
|
|
||||||
$enginesArray = array(
|
|
||||||
'neededEngineSupport' => strtoupper($oSizer->getImageInfo()),
|
|
||||||
'installedEngines' => $a,
|
|
||||||
'selectedEngine' => $oSizer->getEngine()->className,
|
|
||||||
'engineWebpSupport' => $oSizer->getEngine()->supported('webp')
|
|
||||||
);
|
|
||||||
unset($a, $moduleName, $configData, $engines, $priority, $modules, $oSizer);
|
|
||||||
|
|
||||||
// merge all into $info
|
|
||||||
$info = array_merge($info, $webp,
|
|
||||||
array('engines' => $enginesArray),
|
|
||||||
// OPTIONS
|
|
||||||
array('options_hierarchy' => array(
|
|
||||||
'imageSizerOptions' => $this->wire('config')->imageSizerOptions,
|
|
||||||
'individualOptions' => $options,
|
|
||||||
'finalOptions' => $finalOptions
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
unset($variationArray, $webp, $enginesArray, $options, $finalOptions);
|
|
||||||
|
|
||||||
// If not in browser environment, remove the thumb image
|
|
||||||
if(!isset($_SERVER['HTTP_HOST'])) unset($info['thumb']);
|
|
||||||
|
|
||||||
if('array' == $returnType) {
|
|
||||||
// return as array
|
|
||||||
return $info;
|
|
||||||
} else if('object' == $returnType) {
|
|
||||||
// return as object
|
|
||||||
$object = new \stdClass();
|
|
||||||
foreach($info as $group => $array) {
|
|
||||||
$object->$group = new \stdClass();
|
|
||||||
if('thumb' == $group) {
|
|
||||||
$object->$group = $array;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$this->array_to_object($array, $object->$group);
|
|
||||||
}
|
|
||||||
return $object;
|
|
||||||
}
|
|
||||||
|
|
||||||
// make a beautyfied var_dump
|
|
||||||
$tmp = $info;
|
|
||||||
$info = array();
|
|
||||||
foreach($tmp as $group => $array) {
|
|
||||||
$info[mb_strtoupper($group)] = $array;
|
|
||||||
}
|
|
||||||
unset($tmp, $group, $array);
|
|
||||||
ob_start();
|
|
||||||
var_dump($info);
|
|
||||||
$content = ob_get_contents();
|
|
||||||
ob_end_clean();
|
|
||||||
$m = 0;
|
|
||||||
preg_match_all('#^(.*)=>#mU', $content, $stack);
|
|
||||||
$lines = $stack[1];
|
|
||||||
$indents = array_map('strlen', $lines);
|
|
||||||
if($indents) $m = max($indents) + 1;
|
|
||||||
$content = preg_replace_callback(
|
|
||||||
'#^(.*)=>\\n\s+(\S)#Um',
|
|
||||||
function($match) use ($m) {
|
|
||||||
return $match[1] . str_repeat(' ', ($m - strlen($match[1]) > 1 ? $m - strlen($match[1]) : 1)) . $match[2];
|
|
||||||
},
|
|
||||||
$content
|
|
||||||
);
|
|
||||||
$content = preg_replace('#^((\s*).*){$#m', "\\1\n\\2{", $content);
|
|
||||||
$content = str_replace(array('<pre>', '</pre>'), '', $content);
|
|
||||||
if(isset($_SERVER['HTTP_HOST'])) {
|
|
||||||
// build output for HTML
|
|
||||||
$return = "<pre style=\"margin:10px; padding:10px; background-color:#F2F2F2; color:#000; border:1px solid #333; font-family:'Hack Regular', 'Source Code Pro', 'Envy Code R', 'Noto mono', 'Liberation Mono', 'Consolas', 'Lucida Console', 'DejaVu Sans Mono', 'LetterGothicStd', 'Courier New', 'Courier', monospace; font-size:12px; line-height:15px; overflow:auto;\">{$content}</pre>";
|
|
||||||
} else {
|
|
||||||
// output for Console
|
|
||||||
$return = $content;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method that converts a multidim array to a multidim object for the getDebugInfo method
|
* Get all extras, add an extra, or get an extra
|
||||||
*
|
*
|
||||||
* @param array $array the input array
|
* #pw-internal
|
||||||
* @param object $object the initial object, gets passed recursive by reference through all loops
|
*
|
||||||
* @param bool $multidim set this to true to avoid multidimensional object
|
* @param string $name
|
||||||
* @return object the final multidim object
|
* @param PagefileExtra $value
|
||||||
*
|
* @return PagefileExtra[]
|
||||||
|
* @since 3.0.132
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
private function array_to_object($array, &$object, $multidim = true) {
|
public function extras($name = null, PagefileExtra $value = null) {
|
||||||
foreach($array as $key => $value) {
|
if($name) return parent::extras($name, $value);
|
||||||
if($multidim && is_array($value)) {
|
$extras = parent::extras();
|
||||||
$object->$key = new \stdClass();
|
$extras['webp'] = $this->webp();
|
||||||
$this->array_to_object($value, $object->$key, false);
|
return $extras;
|
||||||
} else {
|
|
||||||
$object->$key = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $object;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Debug info
|
* Basic debug info
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function __debugInfo() {
|
public function __debugInfo() {
|
||||||
static $depth = 0;
|
return $this->debugInfo->getBasicDebugInfo();
|
||||||
$depth++;
|
}
|
||||||
$info = parent::__debugInfo();
|
|
||||||
$info['width'] = $this->width();
|
/**
|
||||||
$info['height'] = $this->height();
|
* Verbose debug info (via @horst)
|
||||||
$info['suffix'] = $this->suffixStr;
|
*
|
||||||
if($this->hasFocus) $info['focus'] = $this->focusStr;
|
* Optionally with individual options array.
|
||||||
if(isset($info['filedata']) && isset($info['filedata']['focus'])) unset($info['filedata']['focus']);
|
*
|
||||||
if(empty($info['filedata'])) unset($info['filedata']);
|
* @param array $options The individual options you also passes with your image variation creation
|
||||||
$original = $this->original;
|
* @param string $returnType 'string'|'array'|'object', default is 'string' and returns markup or plain text
|
||||||
if($original && $original !== $this) $info['original'] = $original->basename;
|
* @return array|object|string
|
||||||
if($depth < 2) {
|
* @since 3.0.132
|
||||||
$info['variations'] = array();
|
*
|
||||||
$variations = $this->getVariations(array('info' => true, 'verbose' => false));
|
*/
|
||||||
foreach($variations as $name) {
|
public function getDebugInfo($options = array(), $returnType = 'string') {
|
||||||
$info['variations'][] = $name;
|
return $this->debugInfo->getVerboseDebugInfo($options, $returnType);
|
||||||
}
|
}
|
||||||
if(empty($info['variations'])) unset($info['variations']);
|
|
||||||
}
|
/**
|
||||||
$depth--;
|
* Get debug info from parent class
|
||||||
return $info;
|
*
|
||||||
|
* #pw-internal
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* @since 3.0.132
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function _parentDebugInfo() {
|
||||||
|
return parent::__debugInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
306
wire/core/PageimageDebugInfo.php
Normal file
306
wire/core/PageimageDebugInfo.php
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
<?php namespace ProcessWire;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Debug info for Pageimage
|
||||||
|
*
|
||||||
|
* By Horst Nogajski for ProcessWire
|
||||||
|
*
|
||||||
|
* @property string $url
|
||||||
|
* @property string $filename
|
||||||
|
* @property string $basename
|
||||||
|
* @property Pageimage $original
|
||||||
|
* @property int $width
|
||||||
|
* @property int $height
|
||||||
|
* @property bool $hasFocus
|
||||||
|
* @property string $focusStr
|
||||||
|
* @property string $suffixStr
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class PageimageDebugInfo extends WireData {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Pageimage
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected $pageimage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct
|
||||||
|
*
|
||||||
|
* @param Pageimage $pageimage
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct(Pageimage $pageimage) {
|
||||||
|
$pageimage->wire($this);
|
||||||
|
$this->pageimage = $pageimage;
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get property
|
||||||
|
*
|
||||||
|
* This primarily delegates to the Pageimage object so that its properties can be accessed
|
||||||
|
* directly from this class.
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* @return mixed|null
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function get($key) {
|
||||||
|
$value = $this->pageimage->get($key);
|
||||||
|
if($value === null) $value = parent::get($key);
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get basic debug info, like that used for Pageimage::__debugInfo()
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function getBasicDebugInfo() {
|
||||||
|
static $depth = 0;
|
||||||
|
$depth++;
|
||||||
|
$info = $this->pageimage->_parentDebugInfo();
|
||||||
|
$info['width'] = $this->pageimage->width();
|
||||||
|
$info['height'] = $this->pageimage->height();
|
||||||
|
$info['suffix'] = $this->pageimage->suffixStr;
|
||||||
|
if($this->pageimage->hasFocus) $info['focus'] = $this->pageimage->focusStr;
|
||||||
|
if(isset($info['filedata']) && isset($info['filedata']['focus'])) unset($info['filedata']['focus']);
|
||||||
|
if(empty($info['filedata'])) unset($info['filedata']);
|
||||||
|
$original = $this->original;
|
||||||
|
if($original && $original !== $this) $info['original'] = $original->basename;
|
||||||
|
if($depth < 2) {
|
||||||
|
$info['variations'] = array();
|
||||||
|
$variations = $this->pageimage->getVariations(array('info' => true, 'verbose' => false));
|
||||||
|
foreach($variations as $name) {
|
||||||
|
$info['variations'][] = $name;
|
||||||
|
}
|
||||||
|
if(empty($info['variations'])) unset($info['variations']);
|
||||||
|
}
|
||||||
|
$depth--;
|
||||||
|
return $info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get verbose DebugInfo, optionally with individual options array, @horst
|
||||||
|
*
|
||||||
|
* (without invoking the magic debug)
|
||||||
|
*
|
||||||
|
* @param array $options The individual options you also passes with your image variation creation
|
||||||
|
* @param string $returnType 'string'|'array'|'object', default is 'string' and returns markup or plain text
|
||||||
|
* @return array|object|string
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function getVerboseDebugInfo($options = array(), $returnType = 'string') {
|
||||||
|
static $depth = 0;
|
||||||
|
$depth++;
|
||||||
|
|
||||||
|
// fetch imagesizer, some infos and some options
|
||||||
|
$oSizer = new ImageSizer($this->filename, $options);
|
||||||
|
$this->wire($oSizer);
|
||||||
|
$osInfo = $oSizer->getImageInfo(true);
|
||||||
|
$finalOptions = $oSizer->getOptions();
|
||||||
|
|
||||||
|
// build some info parts and fetch some from parent (pagefile)
|
||||||
|
$thumbStyle = "max-width:120px; max-height:120px;";
|
||||||
|
$thumbStyle .= $this->width >= $this->height ? 'width:100px; height:auto;' : 'height:100px; width:auto;';
|
||||||
|
$thumb = array(
|
||||||
|
'thumb' => "<img src='$this->url' style='$thumbStyle' alt='' />"
|
||||||
|
);
|
||||||
|
|
||||||
|
if($this->original) {
|
||||||
|
$original = array(
|
||||||
|
'original' => $this->original->basename,
|
||||||
|
'basename' => $this->basename
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$original = array(
|
||||||
|
'original' => '{SELF}',
|
||||||
|
'basename' => $this->basename
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$parent = array(
|
||||||
|
'files' => array_merge(
|
||||||
|
$original,
|
||||||
|
$this->pageimage->_parentDebugInfo(),
|
||||||
|
array(
|
||||||
|
'suffix' => isset($finalOptions['suffix']) ? $finalOptions['suffix'] : '',
|
||||||
|
'extension' => $osInfo['extension']
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// rearange parts
|
||||||
|
unset($parent['files']['filesize']);
|
||||||
|
$parent['files']['filesize'] = filesize($this->filename);
|
||||||
|
|
||||||
|
// VARIATIONS
|
||||||
|
$variationArray = array();
|
||||||
|
if($depth < 2) {
|
||||||
|
$variations = $this->pageimage->getVariations(array('info' => true, 'verbose' => false));
|
||||||
|
foreach($variations as $name) $variationArray[] = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
$depth--;
|
||||||
|
unset($variations, $name);
|
||||||
|
|
||||||
|
// start collecting the $info
|
||||||
|
$info = array_merge($thumb, $parent,
|
||||||
|
array(
|
||||||
|
'variations' => $variationArray
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'imageinfo' => array(
|
||||||
|
'imageType' => $osInfo['info']['imageType'],
|
||||||
|
'mime' => $osInfo['info']['mime'],
|
||||||
|
'width' => $this->width,
|
||||||
|
'height' => $this->height,
|
||||||
|
'focus' => $this->hasFocus ? $this->focusStr : NULL,
|
||||||
|
'description' => $parent['files']['description'],
|
||||||
|
'tags' => $parent['files']['tags'],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
unset($info['files']['tags'], $info['files']['description']);
|
||||||
|
|
||||||
|
// beautify the output, remove unnecessary items
|
||||||
|
if(isset($info['files']['filedata']) && isset($info['files']['filedata']['focus'])) unset($info['files']['filedata']['focus']);
|
||||||
|
if(empty($info['files']['filedata'])) unset($info['files']['filedata']);
|
||||||
|
unset($osInfo['info']['mime'], $osInfo['info']['imageType']);
|
||||||
|
|
||||||
|
// add the rest from osInfo to the final $info array
|
||||||
|
foreach($osInfo['info'] as $k => $v) $info['imageinfo'][$k] = $v;
|
||||||
|
$info['imageinfo']['iptcRaw'] = $osInfo['iptcRaw'];
|
||||||
|
unset($osInfo, $thumb, $original, $parent);
|
||||||
|
|
||||||
|
// WEBP
|
||||||
|
$webp = $this->pageimage->webp();
|
||||||
|
$webpSize = $webp->exists() ? filesize($webp->filename()) : 0;
|
||||||
|
$webpInfo = array(
|
||||||
|
'webp_copy' => array(
|
||||||
|
'hasWebp' => $webpSize ? true : false,
|
||||||
|
'webpUrl' => (!$webpSize ? NULL : $webp->url()),
|
||||||
|
'webpQuality' => (!isset($finalOptions['webpQuality']) ? NULL : $finalOptions['webpQuality']),
|
||||||
|
'filesize' => $webpSize,
|
||||||
|
'savings' => (!$webpSize ? 0 : intval($info['files']['filesize'] - $webpSize)),
|
||||||
|
'savings_percent' => (!$webpSize ? 0 : 100 - intval($webpSize / ($info['files']['filesize'] / 100))),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// ENGINES
|
||||||
|
$a = array();
|
||||||
|
$modules = $this->wire('modules');
|
||||||
|
$engines = array_merge($oSizer->getEngines(), array('ImageSizerEngineGD'));
|
||||||
|
foreach($engines as $moduleName) {
|
||||||
|
$configData = $modules->getModuleConfigData($moduleName);
|
||||||
|
$priority = isset($configData['enginePriority']) ? (int) $configData['enginePriority'] : 0;
|
||||||
|
$a[$moduleName] = "priority {$priority}";
|
||||||
|
}
|
||||||
|
asort($a, SORT_STRING);
|
||||||
|
$enginesArray = array(
|
||||||
|
'neededEngineSupport' => strtoupper($oSizer->getImageInfo()),
|
||||||
|
'installedEngines' => $a,
|
||||||
|
'selectedEngine' => $oSizer->getEngine()->className,
|
||||||
|
'engineWebpSupport' => $oSizer->getEngine()->supported('webp')
|
||||||
|
);
|
||||||
|
unset($a, $moduleName, $configData, $engines, $priority, $modules, $oSizer);
|
||||||
|
|
||||||
|
// merge all into $info
|
||||||
|
$info = array_merge($info, $webpInfo,
|
||||||
|
array(
|
||||||
|
'engines' => $enginesArray
|
||||||
|
),
|
||||||
|
// OPTIONS
|
||||||
|
array(
|
||||||
|
'options_hierarchy' => array(
|
||||||
|
'imageSizerOptions' => $this->wire('config')->imageSizerOptions,
|
||||||
|
'individualOptions' => $options,
|
||||||
|
'finalOptions' => $finalOptions
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
unset($variationArray, $webpInfo, $enginesArray, $options, $finalOptions);
|
||||||
|
|
||||||
|
// If not in browser environment, remove the thumb image
|
||||||
|
if($this->wire('config')->cli) unset($info['thumb']);
|
||||||
|
|
||||||
|
if('array' == $returnType) {
|
||||||
|
// return as array
|
||||||
|
return $info;
|
||||||
|
} else if('object' == $returnType) {
|
||||||
|
// return as object
|
||||||
|
$object = new \stdClass();
|
||||||
|
foreach($info as $group => $array) {
|
||||||
|
$object->$group = new \stdClass();
|
||||||
|
if('thumb' == $group) {
|
||||||
|
$object->$group = $array;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$this->arrayToObject($array, $object->$group);
|
||||||
|
}
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make a beautified var_dump
|
||||||
|
$tmp = $info;
|
||||||
|
$info = array();
|
||||||
|
foreach($tmp as $group => $array) {
|
||||||
|
$info[mb_strtoupper($group)] = $array;
|
||||||
|
}
|
||||||
|
unset($tmp, $group, $array);
|
||||||
|
ob_start();
|
||||||
|
var_dump($info);
|
||||||
|
$content = ob_get_contents();
|
||||||
|
ob_end_clean();
|
||||||
|
$m = 0;
|
||||||
|
preg_match_all('#^(.*)=>#mU', $content, $stack);
|
||||||
|
$lines = $stack[1];
|
||||||
|
$indents = array_map('strlen', $lines);
|
||||||
|
if($indents) $m = max($indents) + 1;
|
||||||
|
$content = preg_replace_callback(
|
||||||
|
'#^(.*)=>\\n\s+(\S)#Um',
|
||||||
|
function($match) use($m) {
|
||||||
|
return $match[1] . str_repeat(' ', ($m - strlen($match[1]) > 1 ? $m - strlen($match[1]) : 1)) . $match[2];
|
||||||
|
},
|
||||||
|
$content
|
||||||
|
);
|
||||||
|
$content = preg_replace('#^((\s*).*){$#m', "\\1\n\\2{", $content);
|
||||||
|
$content = str_replace(array('<pre>', '</pre>'), '', $content);
|
||||||
|
|
||||||
|
if($this->wire('config')->cli) {
|
||||||
|
// output for Console
|
||||||
|
$return = $content;
|
||||||
|
} else {
|
||||||
|
// build output for HTML
|
||||||
|
$return = "<pre>" . $this->wire('sanitizer')->entities($content) . "</pre>";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method that converts a multidim array to a multidim object for the getDebugInfo method
|
||||||
|
*
|
||||||
|
* @param array $array the input array
|
||||||
|
* @param object $object the initial object, gets passed recursive by reference through all loops
|
||||||
|
* @param bool $multidim set this to true to avoid multidimensional object
|
||||||
|
* @return object the final multidim object
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function arrayToObject($array, &$object, $multidim = true) {
|
||||||
|
foreach($array as $key => $value) {
|
||||||
|
if($multidim && is_array($value)) {
|
||||||
|
$object->$key = new \stdClass();
|
||||||
|
$this->arrayToObject($value, $object->$key, false);
|
||||||
|
} else {
|
||||||
|
$object->$key = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@@ -35,6 +35,15 @@ class ImageSizerEngineIMagick extends ImageSizerEngine {
|
|||||||
*/
|
*/
|
||||||
protected $imWebp = null;
|
protected $imWebp = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Webp support available?
|
||||||
|
*
|
||||||
|
* @var bool|null
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static protected $webpSupport = null;
|
||||||
|
|
||||||
|
|
||||||
// @todo the following need phpdoc
|
// @todo the following need phpdoc
|
||||||
protected $workspaceColorspace;
|
protected $workspaceColorspace;
|
||||||
protected $imageFormat;
|
protected $imageFormat;
|
||||||
@@ -163,18 +172,12 @@ class ImageSizerEngineIMagick extends ImageSizerEngine {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'webp':
|
case 'webp':
|
||||||
if(!isset($this->wire('config')->webpSupportIM)) {
|
if(self::$webpSupport === null) {
|
||||||
// only call it once
|
$im = new \IMagick();
|
||||||
ob_start();
|
$formats = $im->queryformats('WEBP*');
|
||||||
phpinfo(INFO_MODULES);
|
self::$webpSupport = count($formats) > 0;
|
||||||
$dump = ob_get_clean();
|
|
||||||
$list = array();
|
|
||||||
if(preg_match('#ImageMagick supported formats </td><td.*?>(.*?)</td>#msi', $dump, $matches) && isset($matches[1])) {
|
|
||||||
$list = explode(',', str_replace(' ', '', mb_strtolower($matches[1])));
|
|
||||||
}
|
|
||||||
$this->wire('config')->webpSupportIM = in_array('webp', $list);
|
|
||||||
}
|
}
|
||||||
return $this->wire('config')->webpSupportIM;
|
return self::$webpSupport;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'install':
|
case 'install':
|
||||||
@@ -384,7 +387,7 @@ class ImageSizerEngineIMagick extends ImageSizerEngine {
|
|||||||
$this->im->setImageDepth(($this->imageDepth > 8 ? 8 : $this->imageDepth));
|
$this->im->setImageDepth(($this->imageDepth > 8 ? 8 : $this->imageDepth));
|
||||||
|
|
||||||
// prepare to save file(s)
|
// prepare to save file(s)
|
||||||
if($this->webpAdd) {
|
if($this->webpAdd && $this->supported('webp')) {
|
||||||
$this->imWebp = clone $this->im; // make a copy before compressions take effect
|
$this->imWebp = clone $this->im; // make a copy before compressions take effect
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -416,12 +419,12 @@ class ImageSizerEngineIMagick extends ImageSizerEngine {
|
|||||||
// set modified flag and delete optional webp dependency file
|
// set modified flag and delete optional webp dependency file
|
||||||
$this->modified = true;
|
$this->modified = true;
|
||||||
$return = true;
|
$return = true;
|
||||||
$path_parts = pathinfo($srcFilename);
|
$pathinfo = pathinfo($srcFilename);
|
||||||
$webpFilename = $path_parts['dirname'] . '/' . $path_parts['filename'] . '.webp';
|
$webpFilename = $pathinfo['dirname'] . '/' . $pathinfo['filename'] . '.webp';
|
||||||
if(file_exists($webpFilename)) $this->wire('files')->unlink($webpFilename);
|
if(file_exists($webpFilename)) $this->wire('files')->unlink($webpFilename);
|
||||||
|
|
||||||
// optionally create a WebP dependency file
|
// optionally create a WebP dependency file
|
||||||
if($this->webpAdd) {
|
if($this->webpAdd && $this->imWebp) {
|
||||||
// prepare for webp output
|
// prepare for webp output
|
||||||
$this->imWebp->setImageFormat('webp');
|
$this->imWebp->setImageFormat('webp');
|
||||||
$this->imWebp->setImageCompressionQuality($this->webpQuality);
|
$this->imWebp->setImageCompressionQuality($this->webpQuality);
|
||||||
|
Reference in New Issue
Block a user