diff --git a/wire/config.php b/wire/config.php
index fbe1cfe9..857649d8 100644
--- a/wire/config.php
+++ b/wire/config.php
@@ -634,6 +634,8 @@ $config->imageSizerOptions = array(
'quality' => 90, // quality: 1-100 where higher is better but bigger
'hidpiQuality' => 60, // Same as above quality setting, but specific to hidpi images
'defaultGamma' => 2.0, // defaultGamma: 0.5 to 4.0 or -1 to disable gamma correction (default=2.0)
+ 'webpAdd' => false, // set this to true, if the imagesizer engines should create a Webp copy with every (new) image variation
+ 'webpQuality' => 90, // webpQuality: 1-100 where higher is better but bigger
);
/**
diff --git a/wire/core/ImageSizerEngine.php b/wire/core/ImageSizerEngine.php
index 6268044f..d2a670dc 100755
--- a/wire/core/ImageSizerEngine.php
+++ b/wire/core/ImageSizerEngine.php
@@ -10,6 +10,8 @@
* @property bool $upscaling
* @property bool $interlace
* @property array|string|bool $cropping
+ * @property bool $webpAdd
+ * @property int $webpQuality
* @property int $quality
* @property string $sharpening
* @property float $defaultGamma
@@ -60,6 +62,22 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
*/
protected $quality = 90;
+ /**
+ * WebP Image quality setting, 1..100
+ *
+ * @var int
+ *
+ */
+ protected $webpQuality = 90;
+
+ /**
+ * Also create a WebP Image with this variation?
+ *
+ * @var bool
+ *
+ */
+ protected $webpAdd = false;
+
/**
* Image interlace setting, false or true
*
@@ -219,6 +237,8 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
'cropping',
'interlace',
'quality',
+ 'webpQuality',
+ 'webpAdd',
'sharpening',
'defaultGamma',
'scale',
@@ -819,7 +839,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
* disable cropping, specify boolean false. To enable cropping with default (center), you may also specify
* boolean true.
*
- * @return $this
+ * @return self
*
*/
public function setCropping($cropping = true) {
@@ -834,7 +854,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
*
* @param array $value containing 4 params (x y w h) indexed or associative
*
- * @return $this
+ * @return self
* @throws WireException when given invalid value
*
*/
@@ -878,14 +898,43 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
*
* @param int $n
*
- * @return $this
+ * @return self
*
*/
public function setQuality($n) {
$n = (int) $n;
if($n < 1) $n = 1;
- if($n > 100) $n = 100;
- $this->quality = (int) $n;
+ else if($n > 100) $n = 100;
+ $this->quality = $n;
+ return $this;
+ }
+
+ /**
+ * Set the image quality 1-100 for WebP output, where 100 is highest quality
+ *
+ * @param int $n
+ *
+ * @return self
+ *
+ */
+ public function setWebpQuality($n) {
+ $n = (int) $n;
+ if($n < 1) $n = 1;
+ else if($n > 100) $n = 100;
+ $this->webpQuality = $n;
+ return $this;
+ }
+
+ /**
+ * Set flag to also create a webp file or not
+ *
+ * @param bool $value
+ *
+ * @return self
+ *
+ */
+ public function setWebpAdd($value) {
+ $this->webpAdd = (bool) $value;
return $this;
}
@@ -928,7 +977,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
*
* @param mixed $value
*
- * @return $this
+ * @return self
* @throws WireException
*
*/
@@ -957,7 +1006,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
*
* @param bool $value Whether to auto-rotate or not (default = true)
*
- * @return $this
+ * @return self
*
*/
public function setAutoRotation($value = true) {
@@ -970,7 +1019,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
*
* @param bool $value Whether to upscale or not (default = true)
*
- * @return $this
+ * @return self
*
*/
public function setUpscaling($value = true) {
@@ -983,7 +1032,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
*
* @param bool $value Whether to upscale or not (default = true)
*
- * @return $this
+ * @return self
*
*/
public function setInterlace($value = true) {
@@ -996,7 +1045,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
*
* @param float|int $value 0.5 to 4.0 or -1 to disable
*
- * @return $this
+ * @return self
* @throws WireException when given invalid value
*
*/
@@ -1016,7 +1065,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
*
* @param int $value 10 to 60 recommended, default is 30
*
- * @return $this
+ * @return self
*
*/
public function setTimeLimit($value = 30) {
@@ -1042,7 +1091,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
*
* @param float $scale
*
- * @return $this
+ * @return self
*
*/
public function setScale($scale) {
@@ -1057,7 +1106,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
*
* @param bool $hidpi True or false (default=true)
*
- * @return $this
+ * @return self
*
*/
public function setHidpi($hidpi = true) {
@@ -1071,7 +1120,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
*
* @param $degrees
*
- * @return $this
+ * @return self
*
*/
public function setRotate($degrees) {
@@ -1089,7 +1138,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
*
* @param $flip
*
- * @return $this
+ * @return self
*
*/
public function setFlip($flip) {
@@ -1103,7 +1152,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
*
* @param bool $value Whether to USM is used or not (default = true)
*
- * @return $this
+ * @return self
*
*/
public function setUseUSM($value = true) {
@@ -1116,6 +1165,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
*
* @param array $options May contain the following (show with default values):
* 'quality' => 90,
+ * 'webpQuality' => 90,
* 'cropping' => true,
* 'upscaling' => true,
* 'autoRotation' => true,
@@ -1125,7 +1175,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
* 'rotate' => 0 (90, 180, 270 or negative versions of those)
* 'flip' => '', (vertical|horizontal)
*
- * @return $this
+ * @return self
*
*/
public function setOptions(array $options) {
@@ -1148,6 +1198,12 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
case 'quality':
$this->setQuality($value);
break;
+ case 'webpQuality':
+ $this->setWebpQuality($value);
+ break;
+ case 'webpAdd':
+ $this->setWebpAdd($value);
+ break;
case 'cropping':
$this->setCropping($value);
break;
@@ -1207,6 +1263,8 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
$options = array(
'quality' => $this->quality,
+ 'webpQuality' => $this->webpQuality,
+ 'webpAdd' => $this->webpAdd,
'cropping' => $this->cropping,
'upscaling' => $this->upscaling,
'interlace' => $this->interlace,
@@ -1387,7 +1445,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
*
* @param bool $modified
*
- * @return $this
+ * @return self
*
*/
public function setModified($modified) {
diff --git a/wire/core/ImageSizerEngineGD.php b/wire/core/ImageSizerEngineGD.php
index 4da72c6a..97bad910 100755
--- a/wire/core/ImageSizerEngineGD.php
+++ b/wire/core/ImageSizerEngineGD.php
@@ -57,6 +57,7 @@ class ImageSizerEngineGD extends ImageSizerEngine {
// and if it passes the mandatory requirements, we check particularly aspects here
switch($action) {
+
case 'imageformat':
// compare current imagefile infos fetched from ImageInspector
$requested = $this->getImageInfo(false);
@@ -69,7 +70,16 @@ class ImageSizerEngineGD extends ImageSizerEngine {
return true;
}
break;
-
+
+ case 'webp':
+ if(!isset($this->wire('config')->webpSupportGD)) {
+ // only call it once
+ $gd = gd_info();
+ $this->wire('config')->webpSupportGD = isset($gd['WebP Support']) ? $gd['WebP Support'] : false;
+ }
+ return $this->wire('config')->webpSupportGD;
+ break;
+
case 'install':
/*
$gd = gd_info();
@@ -77,6 +87,7 @@ class ImageSizerEngineGD extends ImageSizerEngine {
$png = isset($gd['PNG Support']) ? $gd['PNG Support'] : false;
$gif = isset($gd['GIF Read Support']) && isset($gd['GIF Create Support']) ? $gd['GIF Create Support'] : false;
$freetype = isset($gd['FreeType Support']) ? $gd['FreeType Support'] : false;
+ $webp = isset($gd['WebP Support']) ? $gd['WebP Support'] : false;
$this->config->gdReady = true;
*/
return true;
@@ -322,32 +333,74 @@ class ImageSizerEngineGD extends ImageSizerEngine {
}
}
- // optionally apply interlace bit to the final image.
- // this will result in progressive JPEGs
- if($this->interlace && \IMAGETYPE_JPEG == $this->imageType) {
- if(0 == imageinterlace($thumb, 1)) {
- // log that setting the interlace bit has failed ?
- // ...
- }
- }
-
- // write to file
+ // write to file(s)
+ if(file_exists($dstFilename)) $this->wire('files')->unlink($dstFilename);
$result = false;
switch($this->imageType) {
+
case \IMAGETYPE_GIF:
// correct gamma from linearized 1.0 back to 2.0
$this->gammaCorrection($thumb, false);
- $result = imagegif($thumb, $dstFilename);
+
+ // 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);
+ }
+
+ // save the final GIF image file
+ $result = imagegif($thumb, $dstFilename);
+ }
break;
+
case \IMAGETYPE_PNG:
+ // optionally correct gamma from linearized 1.0 back to 2.0
if(!$this->hasAlphaChannel()) $this->gammaCorrection($thumb, false);
- // always use highest compression level for PNG (9) per @horst
- $result = imagepng($thumb, $dstFilename, 9);
+
+ // 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);
+ }
+
+ // save the final PNG image file and always use highest compression level (9) per @horst
+ $result = imagepng($thumb, $dstFilename, 9);
+ }
break;
+
case \IMAGETYPE_JPEG:
// correct gamma from linearized 1.0 back to 2.0
$this->gammaCorrection($thumb, false);
- $result = imagejpeg($thumb, $dstFilename, $this->quality);
+
+ // 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
+ if($this->interlace) {
+ if(0 == imageinterlace($thumb, 1)) {
+ // log that setting the interlace bit has failed ?
+ // ...
+ }
+ }
+
+ // save the final JPEG image file
+ $result = imagejpeg($thumb, $dstFilename, $this->quality);
+ }
break;
}
@@ -357,6 +410,26 @@ class ImageSizerEngineGD extends ImageSizerEngine {
return $result;
}
+
+ /**
+ * Create WebP image (@horst)
+ * Is requested by image options: ["webpAdd" => true] OR ["webpOnly" => true]
+ *
+ * @param resource $im
+ * @param string $dstFilename
+ * @param int $quality
+ *
+ * @return boolean true | false
+ *
+ */
+ protected function imSaveWebP($im, $filename, $quality = 90) {
+ if(!function_exists('imagewebp')) return false;
+ $path_parts = pathinfo($filename);
+ $webpFilename = $path_parts['dirname'] . '/' . $path_parts['filename'] . '.webp';
+ if(file_exists($webpFilename)) $this->wire('files')->unlink($webpFilename);
+ return imagewebp($im, $webpFilename, $quality);
+ }
+
/**
* Rotate image (@horst)
*
diff --git a/wire/core/Pageimage.php b/wire/core/Pageimage.php
index bc3c5d16..82baba46 100644
--- a/wire/core/Pageimage.php
+++ b/wire/core/Pageimage.php
@@ -40,6 +40,11 @@
* @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 $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 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
* ==================================
@@ -175,6 +180,45 @@ 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
*
@@ -391,6 +435,18 @@ class Pageimage extends Pagefile {
$value = parent::get('src');
if($value === null) $value = $this->url();
break;
+ case 'hasWebp':
+ $value = $this->hasWebp();
+ break;
+ case 'webpUrl':
+ case 'webpSrc':
+ case 'urlWebp':
+ case 'srcWebp':
+ $value = $this->webpUrl();
+ break;
+ case 'webpFilename':
+ $value = $this->webpFilename();
+ break;
default:
$value = parent::get($key);
}
@@ -578,7 +634,7 @@ class Pageimage extends Pagefile {
* - Or you may specify type `int` containing "quality" value.
* - Or you may specify type `bool` containing "upscaling" value.
* @return Pageimage Returns a new Pageimage object that is a variation of the original.
- * If the specified dimensions/options are the same as the original, then the original then the original will be returned.
+ * If the specified dimensions/options are the same as the original, then the original will be returned.
*
*/
public function size($width, $height, $options = array()) {
@@ -635,6 +691,8 @@ class Pageimage extends Pagefile {
'sharpening' => 'soft',
'quality' => 90,
'hidpiQuality' => 40,
+ 'webpQuality' => 90,
+ 'webpAdd' => false,
'suffix' => array(), // can be array of suffixes or string of 1 suffix
'forceNew' => false, // force it to create new image even if already exists
'hidpi' => false,
@@ -736,16 +794,32 @@ class Pageimage extends Pagefile {
$filenameUnvalidated = '';
$exists = file_exists($filenameFinal);
+ $path_parts = pathinfo($filenameFinal);
+ $filenameFinalWebp = $this->pagefiles->path() . $path_parts['filename'] . '.webp';
+ // 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;
+ }
+
// create a new resize if it doesn't already exist or forceNew option is set
if(!$exists && !file_exists($this->filename())) {
// no original file exists to create variation from
$this->error = "Original image does not exist to create size variation";
} else if(!$exists || $options['forceNew']) {
+
// filenameUnvalidated is temporary filename used for resize
- $filenameUnvalidated = $this->pagefiles->page->filesManager()->getTempPath() . $basename;
+ $tempDir = $this->pagefiles->page->filesManager()->getTempPath();
+ $filenameUnvalidated = $tempDir . $basename;
+ $path_parts = pathinfo($filenameUnvalidated);
+ $filenameUnvalidatedWebp = $tempDir . $path_parts['filename'] . '.webp';
+
if($exists && $options['forceNew']) $this->wire('files')->unlink($filenameFinal, true);
+ if(file_exists($filenameFinalWebp) && $options['forceNew']) $this->wire('files')->unlink($filenameFinalWebp, true);
+
if(file_exists($filenameUnvalidated)) $this->wire('files')->unlink($filenameUnvalidated, true);
+ if(file_exists($filenameUnvalidatedWebp)) $this->wire('files')->unlink($filenameUnvalidatedWebp, true);
+
if(@copy($this->filename(), $filenameUnvalidated)) {
try {
@@ -756,7 +830,13 @@ class Pageimage extends Pagefile {
/** @var ImageSizerEngine $engine */
$engine = $sizer->getEngine();
-
+
+ /* if the current engine installation does not support webp, modify the options param */
+ if(isset($options['webpAdd']) && $options['webpAdd'] && !$engine->supported('webp')) {
+ $options['webpAdd'] = false;
+ $engine->setOptions($options);
+ }
+
// allow for ImageSizerEngine module settings for quality and sharpening to override system defaults
// when they are not specified as an option to this resize() method
$engineConfigData = $engine->getConfigData();
@@ -773,6 +853,9 @@ class Pageimage extends Pagefile {
if($sizer->resize($width, $height) && @rename($filenameUnvalidated, $filenameFinal)) {
$this->wire('files')->chmod($filenameFinal);
+ if($options['webpAdd'] && file_exists(($filenameUnvalidatedWebp)) && @rename($filenameUnvalidatedWebp, $filenameFinalWebp)) {
+ $this->wire('files')->chmod($filenameFinalWebp);
+ }
} else {
$this->error = "ImageSizer::resize($width, $height) failed for $filenameUnvalidated";
}
@@ -805,6 +888,8 @@ class Pageimage extends Pagefile {
// error condition: unlink copied file
if(is_file($filenameFinal)) $this->wire('files')->unlink($filenameFinal, true);
if($filenameUnvalidated && is_file($filenameUnvalidated)) $this->wire('files')->unlink($filenameUnvalidated);
+ if(is_file($filenameFinalWebp)) $this->wire('files')->unlink($filenameFinalWebp, true);
+ if(is_file($filenameUnvalidatedWebp)) $this->wire('files')->unlink($filenameUnvalidatedWebp, true);
// we also tell PW about it for logging and/or admin purposes
$this->error($this->error);
@@ -1582,6 +1667,17 @@ class Pageimage extends Pagefile {
$success = $files->unlink($filename, true);
}
if($success) $deletedFiles[] = $filename;
+
+ // Also remove WebP variation, if there exist one
+ $path_parts = pathinfo($filename);
+ $webp = dirname($filename) . '/' . $path_parts['filename'] . '.webp';
+ if(!is_file($webp)) continue;
+ if($options['dryRun']) {
+ $success = true;
+ } else {
+ $success = $files->unlink($webp, true);
+ }
+ if($success) $deletedFiles[] = $webp;
}
if(!$options['dryRun']) $this->variations = null;
@@ -1810,6 +1906,194 @@ class Pageimage extends Pagefile {
}
}
+
+ /**
+ * 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 bool $returnType 'string'|'array'|'object', default is 'string' and returns markup or plain text
+ * @return array|object|string
+ *
+ */
+ public function getDebugInfo($options = array(), $returnType = 'string') {
+ static $depth = 0;
+ $depth++;
+
+ // fetch imagesizer, some infos and some options
+ $oSizer = new ImageSizer($this->filename, $options);
+ $osInfo = $oSizer->getImageInfo(true);
+ $finalOptions = $oSizer->getOptions();
+
+ // build some info parts and fetch some from parent (pagefile)
+ $thumb = array('thumb' => "");
+ $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('
', ''), '', $content); + if(isset($_SERVER['HTTP_HOST'])) { + // build output for HTML + $return = "
{$content}"; + } else { + // output for Console + $return = $content; + } + + 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 array_to_object($array, &$object, $multidim = true) { + foreach($array as $key => $value) { + if($multidim && is_array($value)) { + $object->$key = new \stdClass(); + $this->array_to_object($value, $object->$key, false); + } else { + $object->$key = $value; + } + } + return $object; + } + + + /** * Debug info * diff --git a/wire/modules/Image/ImageSizerEngineIMagick/ImageSizerEngineIMagick.module b/wire/modules/Image/ImageSizerEngineIMagick/ImageSizerEngineIMagick.module index ee8fc37e..9cecb6a0 100755 --- a/wire/modules/Image/ImageSizerEngineIMagick/ImageSizerEngineIMagick.module +++ b/wire/modules/Image/ImageSizerEngineIMagick/ImageSizerEngineIMagick.module @@ -11,7 +11,7 @@ class ImageSizerEngineIMagick extends ImageSizerEngine { public static function getModuleInfo() { return array( 'title' => 'IMagick Image Sizer', - 'version' => 2, + 'version' => 3, 'summary' => "Upgrades image manipulations to use PHP's ImageMagick library when possible.", 'author' => 'Horst Nogajski', 'autoload' => false, @@ -20,10 +20,20 @@ class ImageSizerEngineIMagick extends ImageSizerEngine { } /** + * The (main) IMagick bitimage handler for regular image variations, (JPEG PNG) + * * @var \IMagick|null * */ protected $im = null; + + /** + * The (optionally) IMagick bitimage handler for additional WebP copies + * + * @var \IMagick|null + * + */ + protected $imWebp = null; // @todo the following need phpdoc protected $workspaceColorspace; @@ -80,9 +90,14 @@ class ImageSizerEngineIMagick extends ImageSizerEngine { * */ protected function release() { - if(!is_object($this->im)) return; - $this->im->clear(); - $this->im->destroy(); + if(is_object($this->im)) { + $this->im->clear(); + $this->im->destroy(); + } + if(is_object($this->imWebp)) { + $this->imWebp->clear(); + $this->imWebp->destroy(); + } } /** @@ -146,7 +161,22 @@ class ImageSizerEngineIMagick extends ImageSizerEngine { return false; } break; - + + case 'webp': + if(!isset($this->wire('config')->webpSupportIM)) { + // only call it once + ob_start(); + phpinfo(INFO_MODULES); + $dump = ob_get_clean(); + $list = array(); + if(preg_match('#ImageMagick supported formats