mirror of
https://github.com/processwire/processwire.git
synced 2025-08-10 08:44:46 +02:00
Additional updates to PR #141 expanding WEBP support
This commit is contained in:
@@ -55,6 +55,14 @@ class ImageSizer extends Wire {
|
|||||||
*/
|
*/
|
||||||
static protected $knownEngines = null;
|
static protected $knownEngines = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Names of engines that failed the supported() checks
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected $failedEngineNames = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module/class name of engine that must only be used (for cases where you want to force a specific engine)
|
* Module/class name of engine that must only be used (for cases where you want to force a specific engine)
|
||||||
*
|
*
|
||||||
@@ -84,7 +92,6 @@ class ImageSizer extends Wire {
|
|||||||
*
|
*
|
||||||
* @param string $filename Filename to resize. Omit only if instantiating class for a getEngines() call.
|
* @param string $filename Filename to resize. Omit only if instantiating class for a getEngines() call.
|
||||||
* @param array $options Initial options to the engine.
|
* @param array $options Initial options to the engine.
|
||||||
* @throws WireException
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function __construct($filename = '', $options = array()) {
|
public function __construct($filename = '', $options = array()) {
|
||||||
@@ -152,21 +159,50 @@ class ImageSizer extends Wire {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$engine = null;
|
$engine = null;
|
||||||
|
$bestFallbackEngine = null; // first engine that was supported but failed webp check
|
||||||
|
$engineNames = $this->getEngines();
|
||||||
|
$engineNames[] = $this->defaultEngineName;
|
||||||
|
|
||||||
// find first supported engine, according to knownEngines priority
|
// find first supported engine, according to knownEngines priority
|
||||||
foreach($this->getEngines() as $engineName) {
|
foreach($engineNames as $engineName) {
|
||||||
|
|
||||||
if($this->forceEngineName && $engineName != $this->forceEngineName) continue;
|
if($this->forceEngineName && $engineName != $this->forceEngineName) continue;
|
||||||
$e = $this->wire('modules')->get($engineName);
|
|
||||||
|
if($engineName === $this->defaultEngineName) {
|
||||||
|
$engineClass = __NAMESPACE__ . "\\$engineName";
|
||||||
|
$e = $this->wire(new $engineClass());
|
||||||
|
} else {
|
||||||
|
$e = $this->wire('modules')->get($engineName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$e) continue;
|
||||||
|
|
||||||
|
/** @var ImageSizerEngine $e */
|
||||||
$e->prepare($filename, $options, $inspectionResult);
|
$e->prepare($filename, $options, $inspectionResult);
|
||||||
if($e->supported()) {
|
$supported = $e->supported();
|
||||||
|
|
||||||
|
if($supported && !empty($options['webpAdd']) && !$e->supported('webp')) {
|
||||||
|
// engine does not support requested webp extra image
|
||||||
|
if(!$bestFallbackEngine) $bestFallbackEngine = $e;
|
||||||
|
|
||||||
|
} else if($supported) {
|
||||||
|
// found supported engine
|
||||||
$engine = $e;
|
$engine = $e;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->failedEngineNames[$engineName] = $engineName;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!$engine) {
|
if(!$engine) {
|
||||||
// fallback to default
|
// no engine found
|
||||||
$engine = $this->newDefaultImageSizerEngine($filename, $options, $inspectionResult);
|
if($bestFallbackEngine) {
|
||||||
|
// if there is a next best fallback, use it
|
||||||
|
$engine = $bestFallbackEngine;
|
||||||
|
} else {
|
||||||
|
// otherwise fallback to default
|
||||||
|
$engine = $this->newDefaultImageSizerEngine($filename, $options, $inspectionResult);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $engine;
|
return $engine;
|
||||||
@@ -294,11 +330,10 @@ class ImageSizer extends Wire {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setModified($modified) {
|
public function setModified($modified) {
|
||||||
if($this->engine) $this->engine->modified = $modified ? true : false;
|
if($this->engine) $this->engine->setModified($modified ? true : false);
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// setters (@todo phpdocs)
|
|
||||||
public function setAutoRotation($value = true) { return $this->setOptions(array('autoRotation', $value)); }
|
public function setAutoRotation($value = true) { return $this->setOptions(array('autoRotation', $value)); }
|
||||||
public function setCropExtra($value) { return $this->setOptions(array('cropExtra', $value)); }
|
public function setCropExtra($value) { return $this->setOptions(array('cropExtra', $value)); }
|
||||||
public function setCropping($cropping = true) { return $this->setOptions(array('cropping', $cropping)); }
|
public function setCropping($cropping = true) { return $this->setOptions(array('cropping', $cropping)); }
|
||||||
@@ -312,7 +347,6 @@ class ImageSizer extends Wire {
|
|||||||
public function setTimeLimit($value = 30) { return $this->setOptions(array('timeLimit', $value)); }
|
public function setTimeLimit($value = 30) { return $this->setOptions(array('timeLimit', $value)); }
|
||||||
public function setUpscaling($value = true) { return $this->setOptions(array('upscaling', $value)); }
|
public function setUpscaling($value = true) { return $this->setOptions(array('upscaling', $value)); }
|
||||||
public function setUseUSM($value = true) { return $this->setOptions(array('useUSM', $value)); }
|
public function setUseUSM($value = true) { return $this->setOptions(array('useUSM', $value)); }
|
||||||
|
|
||||||
public function getWidth() {
|
public function getWidth() {
|
||||||
$image = $this->getEngine()->get('image');
|
$image = $this->getEngine()->get('image');
|
||||||
return $image['width'];
|
return $image['width'];
|
||||||
@@ -321,12 +355,12 @@ class ImageSizer extends Wire {
|
|||||||
$image = $this->getEngine()->get('image');
|
$image = $this->getEngine()->get('image');
|
||||||
return $image['height'];
|
return $image['height'];
|
||||||
}
|
}
|
||||||
|
public function getFilename() { return $this->getEngine()->getFilename(); }
|
||||||
public function getFilename() { return $this->getEngine()->filename; }
|
public function getExtension() { return $this->getEngine()->getExtension(); }
|
||||||
public function getExtension() { return $this->getEngine()->extension; }
|
public function getImageType() { return $this->getEngine()->getImageType(); }
|
||||||
public function getImageType() { return $this->getEngine()->imageType; }
|
public function isModified() { return $this->getEngine()->getModified(); }
|
||||||
public function isModified() { return $this->getEngine()->modified; }
|
|
||||||
public function getOptions() { return $this->getEngine()->getOptions(); }
|
public function getOptions() { return $this->getEngine()->getOptions(); }
|
||||||
|
public function getFailedEngineNames() { return $this->failedEngineNames; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current ImageSizerEngine
|
* Get the current ImageSizerEngine
|
||||||
@@ -533,7 +567,7 @@ class ImageSizer extends Wire {
|
|||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
$sizer = new ImageSizerEngineGD($filename);
|
$sizer = new ImageSizerEngineGD();
|
||||||
if($wire) $wire->wire($sizer);
|
if($wire) $wire->wire($sizer);
|
||||||
$result = false !== $sizer->writeBackIPTC($filename) ? true : false;
|
$result = false !== $sizer->writeBackIPTC($filename) ? true : false;
|
||||||
return $result;
|
return $result;
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
* @property bool $webpAdd
|
* @property bool $webpAdd
|
||||||
* @property int $webpQuality
|
* @property int $webpQuality
|
||||||
* @property bool|null $webpResult
|
* @property bool|null $webpResult
|
||||||
|
* @property bool|null $webpOnly
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
abstract class ImageSizerEngine extends WireData implements Module, ConfigurableModule {
|
abstract class ImageSizerEngine extends WireData implements Module, ConfigurableModule {
|
||||||
@@ -79,6 +80,14 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
|||||||
*/
|
*/
|
||||||
protected $webpAdd = false;
|
protected $webpAdd = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only create the webp file?
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected $webpOnly = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* webp result (null=not known or not applicable)
|
* webp result (null=not known or not applicable)
|
||||||
*
|
*
|
||||||
@@ -931,13 +940,27 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
|||||||
/**
|
/**
|
||||||
* Set flag to also create a webp file or not
|
* Set flag to also create a webp file or not
|
||||||
*
|
*
|
||||||
* @param bool $value
|
* @param bool $webpAdd
|
||||||
*
|
* @param bool|null $webpOnly
|
||||||
* @return self
|
* @return self
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setWebpAdd($value) {
|
public function setWebpAdd($webpAdd, $webpOnly = null) {
|
||||||
$this->webpAdd = (bool) $value;
|
$this->webpAdd = (bool) $webpAdd;
|
||||||
|
if(is_bool($webpOnly)) $this->webpOnly = $webpOnly;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set flag to only create a webp file
|
||||||
|
*
|
||||||
|
* @param bool value$
|
||||||
|
* @return self
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function setWebpOnly($value) {
|
||||||
|
$this->webpOnly = (bool) $value;
|
||||||
|
if($this->webpOnly) $this->webpAdd = true; // webpAdd required for webpOnly
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1207,6 +1230,9 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
|||||||
case 'webpAdd':
|
case 'webpAdd':
|
||||||
$this->setWebpAdd($value);
|
$this->setWebpAdd($value);
|
||||||
break;
|
break;
|
||||||
|
case 'webpOnly':
|
||||||
|
$this->webpOnly = (bool) $value;
|
||||||
|
break;
|
||||||
case 'cropping':
|
case 'cropping':
|
||||||
$this->setCropping($value);
|
$this->setCropping($value);
|
||||||
break;
|
break;
|
||||||
@@ -1287,6 +1313,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
|||||||
'quality' => $this->quality,
|
'quality' => $this->quality,
|
||||||
'webpQuality' => $this->webpQuality,
|
'webpQuality' => $this->webpQuality,
|
||||||
'webpAdd' => $this->webpAdd,
|
'webpAdd' => $this->webpAdd,
|
||||||
|
'webpOnly' => $this->webpOnly,
|
||||||
'cropping' => $this->cropping,
|
'cropping' => $this->cropping,
|
||||||
'upscaling' => $this->upscaling,
|
'upscaling' => $this->upscaling,
|
||||||
'interlace' => $this->interlace,
|
'interlace' => $this->interlace,
|
||||||
@@ -1328,6 +1355,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
|||||||
);
|
);
|
||||||
|
|
||||||
if($key === 'webpResult') return $this->webpResult;
|
if($key === 'webpResult') return $this->webpResult;
|
||||||
|
if($key === 'webpOnly') return $this->webpOnly;
|
||||||
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];
|
||||||
@@ -1476,6 +1504,16 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get whether the image was modified
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function getModified() {
|
||||||
|
return $this->modified;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if cropping is needed, if yes, populate x- and y-position to params $w1 and $h1
|
* Check if cropping is needed, if yes, populate x- and y-position to params $w1 and $h1
|
||||||
*
|
*
|
||||||
|
@@ -36,14 +36,6 @@ class ImageSizerEngineGD extends ImageSizerEngine {
|
|||||||
*/
|
*/
|
||||||
protected $gammaLinearized;
|
protected $gammaLinearized;
|
||||||
|
|
||||||
/**
|
|
||||||
* webp-only toggle for future use
|
|
||||||
*
|
|
||||||
* @var bool
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
protected $webpOnly = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Webp support available?
|
* Webp support available?
|
||||||
*
|
*
|
||||||
|
@@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Extra extension for Pagefile or Pageimage objects
|
* Extra extension for Pagefile or Pageimage objects
|
||||||
*
|
*
|
||||||
|
* Properties
|
||||||
|
* ==========
|
||||||
* @property string $url Local URL/path to file
|
* @property string $url Local URL/path to file
|
||||||
* @property string $httpUrl Full HTTP URL with scheme and host
|
* @property string $httpUrl Full HTTP URL with scheme and host
|
||||||
* @property string $URL No-cache version of url
|
* @property string $URL No-cache version of url
|
||||||
@@ -14,9 +16,16 @@
|
|||||||
* @property string $ext Alias of extension
|
* @property string $ext Alias of extension
|
||||||
* @property bool $exists Does the file exist?
|
* @property bool $exists Does the file exist?
|
||||||
* @property int $filesize Size of file in bytes
|
* @property int $filesize Size of file in bytes
|
||||||
* @property Pageimage $pagefile Source Pageimage objerct
|
* @property Pagefile|Pageimage $pagefile Source Pageimage object
|
||||||
*
|
*
|
||||||
* @method create()
|
* The following properties affect the behavior of the URL-related methods
|
||||||
|
* =======================================================================
|
||||||
|
* @property bool $useSrcUrlOnFail Use source Pagefile URL if extra image does not exist and cannot be created? (default=false)
|
||||||
|
* @property bool $useSrcUrlOnSize Use source Pagefile URL if extra file is larger than source file? (default=false)
|
||||||
|
*
|
||||||
|
* Hookable methods
|
||||||
|
* ================
|
||||||
|
* @method bool create()
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -41,7 +50,7 @@ class PagefileExtra extends WireData {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected $filenamePrevious = '';
|
protected $filenamePrevious = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct
|
* Construct
|
||||||
*
|
*
|
||||||
@@ -53,6 +62,8 @@ class PagefileExtra extends WireData {
|
|||||||
$pagefile->wire($this);
|
$pagefile->wire($this);
|
||||||
$this->setPagefile($pagefile);
|
$this->setPagefile($pagefile);
|
||||||
$this->setExtension($extension);
|
$this->setExtension($extension);
|
||||||
|
$this->useSrcUrlOnFail = true;
|
||||||
|
$this->useSrcUrlOnSize = false;
|
||||||
return parent::__construct();
|
return parent::__construct();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,10 +90,12 @@ class PagefileExtra extends WireData {
|
|||||||
/**
|
/**
|
||||||
* Does the extra file currently exist?
|
* Does the extra file currently exist?
|
||||||
*
|
*
|
||||||
|
* @param bool $clear Clear stat cache before checking? (default=false)
|
||||||
* @return bool
|
* @return bool
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function exists() {
|
public function exists($clear = false) {
|
||||||
|
if($clear) clearstatcache();
|
||||||
return is_readable($this->filename());
|
return is_readable($this->filename());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +106,7 @@ class PagefileExtra extends WireData {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function filesize() {
|
public function filesize() {
|
||||||
return $this->exists() ? filesize($this->filename()) : 0;
|
return (int) @filesize($this->filename());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -122,13 +135,26 @@ class PagefileExtra extends WireData {
|
|||||||
/**
|
/**
|
||||||
* Return the URL to the extra file, creating it if it does not already exist
|
* Return the URL to the extra file, creating it if it does not already exist
|
||||||
*
|
*
|
||||||
|
* @param bool $fallback Allow falling back to source Pagefile URL when appropriate?
|
||||||
* @return string
|
* @return string
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function url() {
|
public function url($fallback = true) {
|
||||||
if(!$this->exists()) $this->create();
|
if(!$this->exists()) {
|
||||||
$pathinfo = pathinfo($this->pagefile->url());
|
$this->create();
|
||||||
return $pathinfo['dirname'] . '/' . $pathinfo['filename'] . '.' . $this->extension;
|
if($fallback && !$this->exists() && $this->useSrcUrlOnFail) {
|
||||||
|
// return original pagefile URL if the extra cannot be created
|
||||||
|
return $this->pagefile->url();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if($fallback && $this->useSrcUrlOnSize && $this->filesize() > $this->pagefile->filesize()) {
|
||||||
|
$url = $this->pagefile->url();
|
||||||
|
} else {
|
||||||
|
$pathinfo = pathinfo($this->pagefile->url());
|
||||||
|
$url = $pathinfo['dirname'] . '/' . $pathinfo['filename'] . '.' . $this->extension;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $url;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -169,8 +195,12 @@ class PagefileExtra extends WireData {
|
|||||||
*
|
*
|
||||||
* Must be implemented by a hook or by descending class
|
* Must be implemented by a hook or by descending class
|
||||||
*
|
*
|
||||||
|
* @return bool Returns true on success, false on fail
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public function ___create() { }
|
public function ___create() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get property
|
* Get property
|
||||||
@@ -212,7 +242,8 @@ class PagefileExtra extends WireData {
|
|||||||
$value = $this->pagefile;
|
$value = $this->pagefile;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$value = $this->pagefile->get($key);
|
$value = parent::get($key);
|
||||||
|
if($value === null) $value = $this->pagefile->get($key);
|
||||||
}
|
}
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
@@ -645,7 +645,8 @@ class Pageimage extends Pagefile {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected function ___size($width, $height, $options) {
|
protected function ___size($width, $height, $options) {
|
||||||
|
|
||||||
|
$this->error = '';
|
||||||
if($this->ext == 'svg') return $this;
|
if($this->ext == 'svg') return $this;
|
||||||
|
|
||||||
if(!is_array($options)) {
|
if(!is_array($options)) {
|
||||||
@@ -678,6 +679,8 @@ class Pageimage extends Pagefile {
|
|||||||
'hidpiQuality' => 40,
|
'hidpiQuality' => 40,
|
||||||
'webpQuality' => 90,
|
'webpQuality' => 90,
|
||||||
'webpAdd' => false,
|
'webpAdd' => false,
|
||||||
|
'webpName' => '', // use this for the webp file basename rather than mirroring from the jpg/png
|
||||||
|
'webpOnly' => false, // only keep the webp version (requires webpAdd option)
|
||||||
'suffix' => array(), // can be array of suffixes or string of 1 suffix
|
'suffix' => array(), // can be array of suffixes or string of 1 suffix
|
||||||
'forceNew' => false, // force it to create new image even if already exists
|
'forceNew' => false, // force it to create new image even if already exists
|
||||||
'hidpi' => false,
|
'hidpi' => false,
|
||||||
@@ -691,8 +694,6 @@ class Pageimage extends Pagefile {
|
|||||||
'allowOriginal' => false, // Return original image if already at requested dimensions? (must be only specified option)
|
'allowOriginal' => false, // Return original image if already at requested dimensions? (must be only specified option)
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->error = '';
|
|
||||||
|
|
||||||
/** @var WireFileTools $files */
|
/** @var WireFileTools $files */
|
||||||
/** @var Config $config */
|
/** @var Config $config */
|
||||||
$files = $this->wire('files');
|
$files = $this->wire('files');
|
||||||
@@ -786,11 +787,16 @@ class Pageimage extends Pagefile {
|
|||||||
|
|
||||||
$filenameFinal = $this->pagefiles->path() . $basename;
|
$filenameFinal = $this->pagefiles->path() . $basename;
|
||||||
$filenameFinalExists = file_exists($filenameFinal);
|
$filenameFinalExists = file_exists($filenameFinal);
|
||||||
$filenameFinalWebp = $this->pagefiles->path() . $basenameNoExt . '.webp';
|
|
||||||
|
if(!empty($options['webpName'])) {
|
||||||
|
$filenameFinalWebp = $this->pagefiles->path() . basename($options['webpName'], '.webp') . '.webp';
|
||||||
|
} else {
|
||||||
|
$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)) $options['forceNew'] = true;
|
if($options['webpAdd'] && !file_exists($filenameFinalWebp)) $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(!$filenameFinalExists && !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
|
||||||
@@ -801,7 +807,7 @@ class Pageimage extends Pagefile {
|
|||||||
// 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;
|
||||||
$filenameUnvalidatedWebp = $tempDir . basename($filenameFinalWebp);
|
$filenameUnvalidatedWebp = $tempDir . $basenameNoExt . '.webp';
|
||||||
|
|
||||||
if($filenameFinalExists && $options['forceNew']) $files->unlink($filenameFinal, true);
|
if($filenameFinalExists && $options['forceNew']) $files->unlink($filenameFinal, true);
|
||||||
if(file_exists($filenameFinalWebp) && $options['forceNew']) $files->unlink($filenameFinalWebp, true);
|
if(file_exists($filenameFinalWebp) && $options['forceNew']) $files->unlink($filenameFinalWebp, true);
|
||||||
@@ -822,7 +828,9 @@ class Pageimage extends Pagefile {
|
|||||||
|
|
||||||
/* 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(!empty($options['webpAdd']) && !$engine->supported('webp')) {
|
if(!empty($options['webpAdd']) && !$engine->supported('webp')) {
|
||||||
|
// no engines support webp
|
||||||
$options['webpAdd'] = false;
|
$options['webpAdd'] = false;
|
||||||
|
$options['webpOnly'] = false;
|
||||||
$engine->setOptions($options);
|
$engine->setOptions($options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -840,7 +848,12 @@ class Pageimage extends Pagefile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($sizer->resize($width, $height) && $files->rename($filenameUnvalidated, $filenameFinal)) {
|
if($sizer->resize($width, $height)) {
|
||||||
|
if($options['webpAdd'] && $options['webpOnly']) {
|
||||||
|
if(is_file($filenameUnvalidated)) $files->unlink($filenameUnvalidated);
|
||||||
|
} else if(!$files->rename($filenameUnvalidated, $filenameFinal)) {
|
||||||
|
$this->error = "Rename failed: $filenameUnvalidated => $filenameFinal";
|
||||||
|
}
|
||||||
if($options['webpAdd'] && file_exists($filenameUnvalidatedWebp)) {
|
if($options['webpAdd'] && file_exists($filenameUnvalidatedWebp)) {
|
||||||
$files->rename($filenameUnvalidatedWebp, $filenameFinalWebp);
|
$files->rename($filenameUnvalidatedWebp, $filenameFinalWebp);
|
||||||
}
|
}
|
||||||
@@ -848,7 +861,7 @@ class Pageimage extends Pagefile {
|
|||||||
$this->error = "ImageSizer::resize($width, $height) failed for $filenameUnvalidated";
|
$this->error = "ImageSizer::resize($width, $height) failed for $filenameUnvalidated";
|
||||||
}
|
}
|
||||||
|
|
||||||
if($debug) $this->wire('log')->save('image-sizer',
|
if($debug && empty($options['webpOnly'])) $this->wire('log')->save('image-sizer',
|
||||||
str_replace('ImageSizerEngine', '', $sizer->getEngine()) . ' ' .
|
str_replace('ImageSizerEngine', '', $sizer->getEngine()) . ' ' .
|
||||||
($this->error ? "FAILED Resize: " : "Resized: ") . "$originalName => " . basename($filenameFinal) . " " .
|
($this->error ? "FAILED Resize: " : "Resized: ") . "$originalName => " . basename($filenameFinal) . " " .
|
||||||
"({$width}x{$height}) " . Debug::timer($timer) . " secs $originalSize => " . filesize($filenameFinal) . " bytes " .
|
"({$width}x{$height}) " . Debug::timer($timer) . " secs $originalSize => " . filesize($filenameFinal) . " bytes " .
|
||||||
@@ -1896,6 +1909,8 @@ class Pageimage extends Pagefile {
|
|||||||
$webp = $this->extras('webp');
|
$webp = $this->extras('webp');
|
||||||
if(!$webp) {
|
if(!$webp) {
|
||||||
$webp = new PagefileExtra($this, 'webp');
|
$webp = new PagefileExtra($this, 'webp');
|
||||||
|
$webp->useSrcUrlOnFail = true; // use this pagefile URL instead if we fail to create a webp
|
||||||
|
$webp->useSrcUrlOnSize = true; // use webp URL only if it results in a smaller file
|
||||||
$this->extras('webp', $webp);
|
$this->extras('webp', $webp);
|
||||||
$webp->addHookAfter('create', $this, 'hookWebpCreate');
|
$webp->addHookAfter('create', $this, 'hookWebpCreate');
|
||||||
}
|
}
|
||||||
@@ -1911,13 +1926,30 @@ class Pageimage extends Pagefile {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function hookWebpCreate(HookEvent $event) {
|
public function hookWebpCreate(HookEvent $event) {
|
||||||
if(!$this->original) return;
|
$original = $this->original;
|
||||||
/** @var PagefileExtra $webp */
|
/** @var PagefileExtra $webp */
|
||||||
$webp = $event->object;
|
$webp = $event->object;
|
||||||
$webp->unlink();
|
$webp->unlink();
|
||||||
$options = self::$lastSizeOptions;
|
if($original) {
|
||||||
|
// we are in an image resized from an original
|
||||||
|
$options = self::$lastSizeOptions;
|
||||||
|
$width = $options['_width'];
|
||||||
|
$height = $options['_height'];
|
||||||
|
} else {
|
||||||
|
// we are the original
|
||||||
|
// create a file with same name as original but with .webp extension
|
||||||
|
$original = $this;
|
||||||
|
$options = array(
|
||||||
|
'allowOriginal' => false,
|
||||||
|
'webpName' => basename($this->basename(), ".$this->ext"),
|
||||||
|
'webpOnly' => true
|
||||||
|
);
|
||||||
|
$width = $this->width;
|
||||||
|
$height = 0;
|
||||||
|
}
|
||||||
$options['webpAdd'] = true;
|
$options['webpAdd'] = true;
|
||||||
$this->original->size($options['_width'], $options['_height'], $options);
|
$original->size($width, $height, $options);
|
||||||
|
$event->return = empty($this->error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -275,7 +275,7 @@ class PageimageDebugInfo extends WireData {
|
|||||||
$return = $content;
|
$return = $content;
|
||||||
} else {
|
} else {
|
||||||
// build output for HTML
|
// build output for HTML
|
||||||
$return = "<pre>" . $this->wire('sanitizer')->entities($content) . "</pre>";
|
$return = "<pre style='overflow:auto'>$content</pre>";
|
||||||
}
|
}
|
||||||
|
|
||||||
return $return;
|
return $return;
|
||||||
|
@@ -36,13 +36,12 @@ class ImageSizerEngineIMagick extends ImageSizerEngine {
|
|||||||
protected $imWebp = null;
|
protected $imWebp = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Webp support available?
|
* Static cache of formats and whether or not supported, as used by the supportsFormat() method (RJC)
|
||||||
*
|
*
|
||||||
* @var bool|null
|
* @var array of ['FORMAT' => true|false]
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static protected $webpSupport = null;
|
static protected $formatSupport = array();
|
||||||
|
|
||||||
|
|
||||||
// @todo the following need phpdoc
|
// @todo the following need phpdoc
|
||||||
protected $workspaceColorspace;
|
protected $workspaceColorspace;
|
||||||
@@ -116,7 +115,7 @@ class ImageSizerEngineIMagick extends ImageSizerEngine {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected function validSourceImageFormats() {
|
protected function validSourceImageFormats() {
|
||||||
return array('JPG', 'JPEG', 'PNG24');
|
return array('JPG', 'JPEG', 'PNG24', 'PNG8', 'PNG', 'GIF', 'GIF87');
|
||||||
//return array(
|
//return array(
|
||||||
// 'PNG', 'PNG8', 'PNG24',
|
// 'PNG', 'PNG8', 'PNG24',
|
||||||
// 'JPG', 'JPEG',
|
// 'JPG', 'JPEG',
|
||||||
@@ -131,16 +130,33 @@ class ImageSizerEngineIMagick extends ImageSizerEngine {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected function validTargetImageFormats() {
|
protected function validTargetImageFormats() {
|
||||||
return $this->validSourceImageFormats();
|
$formats = $this->validSourceImageFormats();
|
||||||
|
if($this->supportsFormat('WEBP')) $formats[] = 'WEBP';
|
||||||
|
return $formats;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the given image format supported by this IMagick for source and target? (RJC)
|
||||||
|
*
|
||||||
|
* @param string $format String like png, jpg, jpg, png8, png24, png24-trans, png24-alpha, etc.
|
||||||
|
* @return bool
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function supportsFormat($format) {
|
||||||
|
if(strpos($format, '-')) list($format,) = explode('-', $format);
|
||||||
|
$format = strtoupper($format);
|
||||||
|
if(isset(self::$formatSupport[$format])) return self::$formatSupport[$format];
|
||||||
|
try {
|
||||||
|
$im = new \IMagick();
|
||||||
|
$formats = $im->queryformats($format);
|
||||||
|
$supported = count($formats) > 0;
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
$supported = false;
|
||||||
|
}
|
||||||
|
self::$formatSupport[$format] = $supported;
|
||||||
|
return $supported;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Is IMagick supported? Is the current image(sub)format supported?
|
|
||||||
*
|
|
||||||
* @param string $action
|
|
||||||
* @return bool
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
/**
|
/**
|
||||||
* Is IMagick supported? Is the current image(sub)format supported?
|
* Is IMagick supported? Is the current image(sub)format supported?
|
||||||
*
|
*
|
||||||
@@ -154,40 +170,21 @@ class ImageSizerEngineIMagick extends ImageSizerEngine {
|
|||||||
if(!class_exists("\\IMagick")) return false;
|
if(!class_exists("\\IMagick")) return false;
|
||||||
|
|
||||||
// and if it passes the mandatory requirements, we check particularly aspects here
|
// and if it passes the mandatory requirements, we check particularly aspects here
|
||||||
switch($action) {
|
$supported = false;
|
||||||
|
if($action === 'imageformat') {
|
||||||
case 'imageformat':
|
// compare current imagefile infos fetched from ImageInspector
|
||||||
// compare current imagefile infos fetched from ImageInspector
|
$requested = $this->getImageInfo(false);
|
||||||
$requested = $this->getImageInfo(false);
|
$supported = $this->supportsFormat($requested);
|
||||||
switch($requested) {
|
} else if($action === 'webp') {
|
||||||
case 'jpg':
|
$supported = $this->supportsFormat('WEBP');
|
||||||
return true;
|
} else if($action === 'install') {
|
||||||
case 'png24':
|
$supported = true;
|
||||||
case 'png24-trans':
|
|
||||||
case 'png24-alpha':
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'webp':
|
|
||||||
if(self::$webpSupport === null) {
|
|
||||||
$im = new \IMagick();
|
|
||||||
$formats = $im->queryformats('WEBP*');
|
|
||||||
self::$webpSupport = count($formats) > 0;
|
|
||||||
}
|
|
||||||
return self::$webpSupport;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'install':
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $supported;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process the image resize
|
* Process the image resize
|
||||||
*
|
*
|
||||||
@@ -232,16 +229,16 @@ class ImageSizerEngineIMagick extends ImageSizerEngine {
|
|||||||
$this->imageFormat = strtoupper($this->im->getImageFormat());
|
$this->imageFormat = strtoupper($this->im->getImageFormat());
|
||||||
|
|
||||||
// only for JPEGs and 24bit PNGs
|
// only for JPEGs and 24bit PNGs
|
||||||
if(!in_array($this->imageFormat, array('JPG', 'JPEG', 'PNG24'))) {
|
if(!in_array($this->imageFormat, $this->validSourceImageFormats())) {
|
||||||
$this->release();
|
$this->release();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check validity against PW
|
// check validity against PW (this does not seem to be reachable due to above code, so commented it out —Ryan)
|
||||||
if(!in_array($this->imageFormat, $this->validSourceImageFormats())) {
|
// if(!in_array($this->imageFormat, $this->validSourceImageFormats())) {
|
||||||
$this->release();
|
// $this->release();
|
||||||
throw new WireException(sprintf($this->_("loaded file '%s' is not in the list of valid images"), basename($dstFilename)));
|
// throw new WireException(sprintf($this->_("loaded file '%s' is not in the list of valid images"), basename($dstFilename)));
|
||||||
}
|
// }
|
||||||
|
|
||||||
// check and retrieve different image parts and information: ICC, Colorspace, Colordepth, Metadata, etc
|
// check and retrieve different image parts and information: ICC, Colorspace, Colordepth, Metadata, etc
|
||||||
$this->imageColorspace = $this->im->getImageColorspace();
|
$this->imageColorspace = $this->im->getImageColorspace();
|
||||||
@@ -385,46 +382,53 @@ class ImageSizerEngineIMagick extends ImageSizerEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->im->setImageDepth(($this->imageDepth > 8 ? 8 : $this->imageDepth));
|
$this->im->setImageDepth(($this->imageDepth > 8 ? 8 : $this->imageDepth));
|
||||||
|
|
||||||
|
// determine whether webp should be created as well (or on its own)
|
||||||
|
$webpOnly = $this->webpOnly && $this->supported('webp');
|
||||||
|
$webpAdd = $webpOnly || ($this->webpAdd && $this->supported('webp'));
|
||||||
|
|
||||||
// prepare to save file(s)
|
if($webpOnly) {
|
||||||
if($this->webpAdd && $this->supported('webp')) {
|
// only a webp file will be created
|
||||||
$this->imWebp = clone $this->im; // make a copy before compressions take effect
|
$this->imWebp = $this->im;
|
||||||
}
|
|
||||||
|
|
||||||
$this->im->setImageFormat($this->imageFormat);
|
|
||||||
$this->im->setImageType($this->imageType);
|
|
||||||
if(in_array(strtoupper($this->imageFormat), array('JPG', 'JPEG'))) {
|
|
||||||
$this->im->setImageCompression(\Imagick::COMPRESSION_JPEG);
|
|
||||||
$this->im->setImageCompressionQuality($this->quality);
|
|
||||||
} else if(in_array(strtoupper($this->imageFormat), array('PNG', 'PNG8', 'PNG24'))) {
|
|
||||||
$this->im->setImageCompression(\Imagick::COMPRESSION_ZIP);
|
|
||||||
$this->im->setImageCompressionQuality($this->quality);
|
|
||||||
} else {
|
} else {
|
||||||
$this->im->setImageCompression(\Imagick::COMPRESSION_UNDEFINED);
|
if($webpAdd) $this->imWebp = clone $this->im; // make a copy before compressions take effect
|
||||||
$this->im->setImageCompressionQuality($this->quality);
|
$this->im->setImageFormat($this->imageFormat);
|
||||||
}
|
$this->im->setImageType($this->imageType);
|
||||||
|
if(in_array(strtoupper($this->imageFormat), array('JPG', 'JPEG'))) {
|
||||||
|
$this->im->setImageCompression(\Imagick::COMPRESSION_JPEG);
|
||||||
|
$this->im->setImageCompressionQuality($this->quality);
|
||||||
|
} else if(in_array(strtoupper($this->imageFormat), array('PNG', 'PNG8', 'PNG24'))) {
|
||||||
|
$this->im->setImageCompression(\Imagick::COMPRESSION_ZIP);
|
||||||
|
$this->im->setImageCompressionQuality($this->quality);
|
||||||
|
} else {
|
||||||
|
$this->im->setImageCompression(\Imagick::COMPRESSION_UNDEFINED);
|
||||||
|
$this->im->setImageCompressionQuality($this->quality);
|
||||||
|
}
|
||||||
|
|
||||||
// write to file
|
// write to file
|
||||||
if(file_exists($dstFilename)) $this->wire('files')->unlink($dstFilename);
|
if(file_exists($dstFilename)) $this->wire('files')->unlink($dstFilename);
|
||||||
@clearstatcache(dirname($dstFilename));
|
@clearstatcache(dirname($dstFilename));
|
||||||
##if(!$this->im->writeImage($this->destFilename)) {
|
##if(!$this->im->writeImage($this->destFilename)) {
|
||||||
// We use this approach for saving so that it behaves the same like core ImageSizer with images that
|
// We use this approach for saving so that it behaves the same like core ImageSizer with images that
|
||||||
// have a wrong extension in their filename. When using writeImage() it automatically corrects the
|
// have a wrong extension in their filename. When using writeImage() it automatically corrects the
|
||||||
// mimetype to match the fileextension, <- we want to avoid this!
|
// mimetype to match the fileextension, <- we want to avoid this!
|
||||||
if(!file_put_contents($dstFilename, $this->im)) {
|
if(!file_put_contents($dstFilename, $this->im)) {
|
||||||
$this->release();
|
$this->release();
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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;
|
||||||
|
|
||||||
|
// if there is a corresponding webp file present, remove it
|
||||||
$pathinfo = pathinfo($srcFilename);
|
$pathinfo = pathinfo($srcFilename);
|
||||||
$webpFilename = $pathinfo['dirname'] . '/' . $pathinfo['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 && $this->imWebp) {
|
if($webpAdd) {
|
||||||
// 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);
|
||||||
@@ -438,6 +442,7 @@ class ImageSizerEngineIMagick extends ImageSizerEngine {
|
|||||||
|
|
||||||
// release and return to event-object
|
// release and return to event-object
|
||||||
$this->release();
|
$this->release();
|
||||||
|
|
||||||
return $return;
|
return $return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user