mirror of
https://github.com/processwire/processwire.git
synced 2025-08-16 11:44:42 +02:00
Merge branch 'webP-support' of https://github.com/horst-n/processwire into horst-n-webP-support
This commit is contained in:
@@ -634,6 +634,8 @@ $config->imageSizerOptions = array(
|
|||||||
'quality' => 90, // quality: 1-100 where higher is better but bigger
|
'quality' => 90, // quality: 1-100 where higher is better but bigger
|
||||||
'hidpiQuality' => 60, // Same as above quality setting, but specific to hidpi images
|
'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)
|
'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
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -10,6 +10,8 @@
|
|||||||
* @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
|
||||||
@@ -60,6 +62,22 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
|||||||
*/
|
*/
|
||||||
protected $quality = 90;
|
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
|
* Image interlace setting, false or true
|
||||||
*
|
*
|
||||||
@@ -219,6 +237,8 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
|||||||
'cropping',
|
'cropping',
|
||||||
'interlace',
|
'interlace',
|
||||||
'quality',
|
'quality',
|
||||||
|
'webpQuality',
|
||||||
|
'webpAdd',
|
||||||
'sharpening',
|
'sharpening',
|
||||||
'defaultGamma',
|
'defaultGamma',
|
||||||
'scale',
|
'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
|
* disable cropping, specify boolean false. To enable cropping with default (center), you may also specify
|
||||||
* boolean true.
|
* boolean true.
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return self
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setCropping($cropping = true) {
|
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
|
* @param array $value containing 4 params (x y w h) indexed or associative
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return self
|
||||||
* @throws WireException when given invalid value
|
* @throws WireException when given invalid value
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -878,14 +898,43 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
|||||||
*
|
*
|
||||||
* @param int $n
|
* @param int $n
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return self
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setQuality($n) {
|
public function setQuality($n) {
|
||||||
$n = (int) $n;
|
$n = (int) $n;
|
||||||
if($n < 1) $n = 1;
|
if($n < 1) $n = 1;
|
||||||
if($n > 100) $n = 100;
|
else if($n > 100) $n = 100;
|
||||||
$this->quality = (int) $n;
|
$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;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -928,7 +977,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
|||||||
*
|
*
|
||||||
* @param mixed $value
|
* @param mixed $value
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return self
|
||||||
* @throws WireException
|
* @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)
|
* @param bool $value Whether to auto-rotate or not (default = true)
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return self
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setAutoRotation($value = true) {
|
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)
|
* @param bool $value Whether to upscale or not (default = true)
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return self
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setUpscaling($value = true) {
|
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)
|
* @param bool $value Whether to upscale or not (default = true)
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return self
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setInterlace($value = true) {
|
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
|
* @param float|int $value 0.5 to 4.0 or -1 to disable
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return self
|
||||||
* @throws WireException when given invalid value
|
* @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
|
* @param int $value 10 to 60 recommended, default is 30
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return self
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setTimeLimit($value = 30) {
|
public function setTimeLimit($value = 30) {
|
||||||
@@ -1042,7 +1091,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
|||||||
*
|
*
|
||||||
* @param float $scale
|
* @param float $scale
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return self
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setScale($scale) {
|
public function setScale($scale) {
|
||||||
@@ -1057,7 +1106,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
|||||||
*
|
*
|
||||||
* @param bool $hidpi True or false (default=true)
|
* @param bool $hidpi True or false (default=true)
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return self
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setHidpi($hidpi = true) {
|
public function setHidpi($hidpi = true) {
|
||||||
@@ -1071,7 +1120,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
|||||||
*
|
*
|
||||||
* @param $degrees
|
* @param $degrees
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return self
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setRotate($degrees) {
|
public function setRotate($degrees) {
|
||||||
@@ -1089,7 +1138,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
|||||||
*
|
*
|
||||||
* @param $flip
|
* @param $flip
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return self
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setFlip($flip) {
|
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)
|
* @param bool $value Whether to USM is used or not (default = true)
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return self
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setUseUSM($value = true) {
|
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):
|
* @param array $options May contain the following (show with default values):
|
||||||
* 'quality' => 90,
|
* 'quality' => 90,
|
||||||
|
* 'webpQuality' => 90,
|
||||||
* 'cropping' => true,
|
* 'cropping' => true,
|
||||||
* 'upscaling' => true,
|
* 'upscaling' => true,
|
||||||
* 'autoRotation' => 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)
|
* 'rotate' => 0 (90, 180, 270 or negative versions of those)
|
||||||
* 'flip' => '', (vertical|horizontal)
|
* 'flip' => '', (vertical|horizontal)
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return self
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setOptions(array $options) {
|
public function setOptions(array $options) {
|
||||||
@@ -1148,6 +1198,12 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
|||||||
case 'quality':
|
case 'quality':
|
||||||
$this->setQuality($value);
|
$this->setQuality($value);
|
||||||
break;
|
break;
|
||||||
|
case 'webpQuality':
|
||||||
|
$this->setWebpQuality($value);
|
||||||
|
break;
|
||||||
|
case 'webpAdd':
|
||||||
|
$this->setWebpAdd($value);
|
||||||
|
break;
|
||||||
case 'cropping':
|
case 'cropping':
|
||||||
$this->setCropping($value);
|
$this->setCropping($value);
|
||||||
break;
|
break;
|
||||||
@@ -1207,6 +1263,8 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
|||||||
|
|
||||||
$options = array(
|
$options = array(
|
||||||
'quality' => $this->quality,
|
'quality' => $this->quality,
|
||||||
|
'webpQuality' => $this->webpQuality,
|
||||||
|
'webpAdd' => $this->webpAdd,
|
||||||
'cropping' => $this->cropping,
|
'cropping' => $this->cropping,
|
||||||
'upscaling' => $this->upscaling,
|
'upscaling' => $this->upscaling,
|
||||||
'interlace' => $this->interlace,
|
'interlace' => $this->interlace,
|
||||||
@@ -1387,7 +1445,7 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
|||||||
*
|
*
|
||||||
* @param bool $modified
|
* @param bool $modified
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return self
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setModified($modified) {
|
public function setModified($modified) {
|
||||||
|
@@ -57,6 +57,7 @@ class ImageSizerEngineGD extends ImageSizerEngine {
|
|||||||
// 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) {
|
switch($action) {
|
||||||
|
|
||||||
case '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);
|
||||||
@@ -69,7 +70,16 @@ class ImageSizerEngineGD extends ImageSizerEngine {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
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':
|
case 'install':
|
||||||
/*
|
/*
|
||||||
$gd = gd_info();
|
$gd = gd_info();
|
||||||
@@ -77,6 +87,7 @@ class ImageSizerEngineGD extends ImageSizerEngine {
|
|||||||
$png = isset($gd['PNG Support']) ? $gd['PNG Support'] : false;
|
$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;
|
$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;
|
$freetype = isset($gd['FreeType Support']) ? $gd['FreeType Support'] : false;
|
||||||
|
$webp = isset($gd['WebP Support']) ? $gd['WebP Support'] : false;
|
||||||
$this->config->gdReady = true;
|
$this->config->gdReady = true;
|
||||||
*/
|
*/
|
||||||
return true;
|
return true;
|
||||||
@@ -322,32 +333,74 @@ class ImageSizerEngineGD extends ImageSizerEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// optionally apply interlace bit to the final image.
|
// write to file(s)
|
||||||
// this will result in progressive JPEGs
|
if(file_exists($dstFilename)) $this->wire('files')->unlink($dstFilename);
|
||||||
if($this->interlace && \IMAGETYPE_JPEG == $this->imageType) {
|
|
||||||
if(0 == imageinterlace($thumb, 1)) {
|
|
||||||
// log that setting the interlace bit has failed ?
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// write to file
|
|
||||||
$result = false;
|
$result = false;
|
||||||
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);
|
||||||
$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;
|
break;
|
||||||
|
|
||||||
case \IMAGETYPE_PNG:
|
case \IMAGETYPE_PNG:
|
||||||
|
// 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);
|
||||||
// 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;
|
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);
|
||||||
$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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,6 +410,26 @@ class ImageSizerEngineGD extends ImageSizerEngine {
|
|||||||
|
|
||||||
return $result;
|
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)
|
* Rotate image (@horst)
|
||||||
*
|
*
|
||||||
|
@@ -40,6 +40,11 @@
|
|||||||
* @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 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
|
||||||
* ==================================
|
* ==================================
|
||||||
@@ -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
|
* Returns the full disk path to the image file
|
||||||
*
|
*
|
||||||
@@ -391,6 +435,18 @@ 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':
|
||||||
|
$value = $this->hasWebp();
|
||||||
|
break;
|
||||||
|
case 'webpUrl':
|
||||||
|
case 'webpSrc':
|
||||||
|
case 'urlWebp':
|
||||||
|
case 'srcWebp':
|
||||||
|
$value = $this->webpUrl();
|
||||||
|
break;
|
||||||
|
case 'webpFilename':
|
||||||
|
$value = $this->webpFilename();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
$value = parent::get($key);
|
$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 `int` containing "quality" value.
|
||||||
* - Or you may specify type `bool` containing "upscaling" value.
|
* - Or you may specify type `bool` containing "upscaling" value.
|
||||||
* @return Pageimage Returns a new Pageimage object that is a variation of the original.
|
* @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()) {
|
public function size($width, $height, $options = array()) {
|
||||||
@@ -635,6 +691,8 @@ class Pageimage extends Pagefile {
|
|||||||
'sharpening' => 'soft',
|
'sharpening' => 'soft',
|
||||||
'quality' => 90,
|
'quality' => 90,
|
||||||
'hidpiQuality' => 40,
|
'hidpiQuality' => 40,
|
||||||
|
'webpQuality' => 90,
|
||||||
|
'webpAdd' => false,
|
||||||
'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,
|
||||||
@@ -736,16 +794,32 @@ class Pageimage extends Pagefile {
|
|||||||
$filenameUnvalidated = '';
|
$filenameUnvalidated = '';
|
||||||
$exists = file_exists($filenameFinal);
|
$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
|
// create a new resize if it doesn't already exist or forceNew option is set
|
||||||
if(!$exists && !file_exists($this->filename())) {
|
if(!$exists && !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(!$exists || $options['forceNew']) {
|
||||||
|
|
||||||
// filenameUnvalidated is temporary filename used for resize
|
// 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($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($filenameUnvalidated)) $this->wire('files')->unlink($filenameUnvalidated, true);
|
||||||
|
if(file_exists($filenameUnvalidatedWebp)) $this->wire('files')->unlink($filenameUnvalidatedWebp, true);
|
||||||
|
|
||||||
if(@copy($this->filename(), $filenameUnvalidated)) {
|
if(@copy($this->filename(), $filenameUnvalidated)) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
@@ -756,7 +830,13 @@ class Pageimage extends Pagefile {
|
|||||||
|
|
||||||
/** @var ImageSizerEngine $engine */
|
/** @var ImageSizerEngine $engine */
|
||||||
$engine = $sizer->getEngine();
|
$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
|
// 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
|
// when they are not specified as an option to this resize() method
|
||||||
$engineConfigData = $engine->getConfigData();
|
$engineConfigData = $engine->getConfigData();
|
||||||
@@ -773,6 +853,9 @@ class Pageimage extends Pagefile {
|
|||||||
|
|
||||||
if($sizer->resize($width, $height) && @rename($filenameUnvalidated, $filenameFinal)) {
|
if($sizer->resize($width, $height) && @rename($filenameUnvalidated, $filenameFinal)) {
|
||||||
$this->wire('files')->chmod($filenameFinal);
|
$this->wire('files')->chmod($filenameFinal);
|
||||||
|
if($options['webpAdd'] && file_exists(($filenameUnvalidatedWebp)) && @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";
|
||||||
}
|
}
|
||||||
@@ -805,6 +888,8 @@ class Pageimage extends Pagefile {
|
|||||||
// error condition: unlink copied file
|
// error condition: unlink copied file
|
||||||
if(is_file($filenameFinal)) $this->wire('files')->unlink($filenameFinal, true);
|
if(is_file($filenameFinal)) $this->wire('files')->unlink($filenameFinal, true);
|
||||||
if($filenameUnvalidated && is_file($filenameUnvalidated)) $this->wire('files')->unlink($filenameUnvalidated);
|
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
|
// we also tell PW about it for logging and/or admin purposes
|
||||||
$this->error($this->error);
|
$this->error($this->error);
|
||||||
@@ -1582,6 +1667,17 @@ class Pageimage extends Pagefile {
|
|||||||
$success = $files->unlink($filename, true);
|
$success = $files->unlink($filename, true);
|
||||||
}
|
}
|
||||||
if($success) $deletedFiles[] = $filename;
|
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;
|
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' => "<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
|
||||||
|
*
|
||||||
|
* @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
|
* Debug info
|
||||||
*
|
*
|
||||||
|
@@ -11,7 +11,7 @@ class ImageSizerEngineIMagick extends ImageSizerEngine {
|
|||||||
public static function getModuleInfo() {
|
public static function getModuleInfo() {
|
||||||
return array(
|
return array(
|
||||||
'title' => 'IMagick Image Sizer',
|
'title' => 'IMagick Image Sizer',
|
||||||
'version' => 2,
|
'version' => 3,
|
||||||
'summary' => "Upgrades image manipulations to use PHP's ImageMagick library when possible.",
|
'summary' => "Upgrades image manipulations to use PHP's ImageMagick library when possible.",
|
||||||
'author' => 'Horst Nogajski',
|
'author' => 'Horst Nogajski',
|
||||||
'autoload' => false,
|
'autoload' => false,
|
||||||
@@ -20,10 +20,20 @@ class ImageSizerEngineIMagick extends ImageSizerEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* The (main) IMagick bitimage handler for regular image variations, (JPEG PNG)
|
||||||
|
*
|
||||||
* @var \IMagick|null
|
* @var \IMagick|null
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected $im = null;
|
protected $im = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The (optionally) IMagick bitimage handler for additional WebP copies
|
||||||
|
*
|
||||||
|
* @var \IMagick|null
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected $imWebp = null;
|
||||||
|
|
||||||
// @todo the following need phpdoc
|
// @todo the following need phpdoc
|
||||||
protected $workspaceColorspace;
|
protected $workspaceColorspace;
|
||||||
@@ -80,9 +90,14 @@ class ImageSizerEngineIMagick extends ImageSizerEngine {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected function release() {
|
protected function release() {
|
||||||
if(!is_object($this->im)) return;
|
if(is_object($this->im)) {
|
||||||
$this->im->clear();
|
$this->im->clear();
|
||||||
$this->im->destroy();
|
$this->im->destroy();
|
||||||
|
}
|
||||||
|
if(is_object($this->imWebp)) {
|
||||||
|
$this->imWebp->clear();
|
||||||
|
$this->imWebp->destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -146,7 +161,22 @@ class ImageSizerEngineIMagick extends ImageSizerEngine {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
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 </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;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'install':
|
case 'install':
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -176,7 +206,7 @@ class ImageSizerEngineIMagick extends ImageSizerEngine {
|
|||||||
protected function processResize($srcFilename, $dstFilename, $fullWidth, $fullHeight, $finalWidth, $finalHeight) {
|
protected function processResize($srcFilename, $dstFilename, $fullWidth, $fullHeight, $finalWidth, $finalHeight) {
|
||||||
|
|
||||||
$this->setTimeLimit(120);
|
$this->setTimeLimit(120);
|
||||||
|
|
||||||
// start image magick
|
// start image magick
|
||||||
$this->im = new \IMagick();
|
$this->im = new \IMagick();
|
||||||
|
|
||||||
@@ -352,8 +382,12 @@ 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)
|
||||||
|
if($this->webpAdd) {
|
||||||
|
$this->imWebp = clone $this->im; // make a copy before compressions take effect
|
||||||
|
}
|
||||||
|
|
||||||
// prepare to save file
|
|
||||||
$this->im->setImageFormat($this->imageFormat);
|
$this->im->setImageFormat($this->imageFormat);
|
||||||
$this->im->setImageType($this->imageType);
|
$this->im->setImageType($this->imageType);
|
||||||
if(in_array(strtoupper($this->imageFormat), array('JPG', 'JPEG'))) {
|
if(in_array(strtoupper($this->imageFormat), array('JPG', 'JPEG'))) {
|
||||||
@@ -367,8 +401,8 @@ class ImageSizerEngineIMagick extends ImageSizerEngine {
|
|||||||
$this->im->setImageCompressionQuality($this->quality);
|
$this->im->setImageCompressionQuality($this->quality);
|
||||||
}
|
}
|
||||||
|
|
||||||
// save to file
|
// write to file
|
||||||
$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
|
||||||
@@ -378,11 +412,30 @@ class ImageSizerEngineIMagick extends ImageSizerEngine {
|
|||||||
$this->release();
|
$this->release();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set modified flag and delete optional webp dependency file
|
||||||
|
$this->modified = true;
|
||||||
|
$return = true;
|
||||||
|
$path_parts = pathinfo($srcFilename);
|
||||||
|
$webpFilename = $path_parts['dirname'] . '/' . $path_parts['filename'] . '.webp';
|
||||||
|
if(file_exists($webpFilename)) $this->wire('files')->unlink($webpFilename);
|
||||||
|
|
||||||
|
// optionally create a WebP dependency file
|
||||||
|
if($this->webpAdd) {
|
||||||
|
// prepare for webp output
|
||||||
|
$this->imWebp->setImageFormat('webp');
|
||||||
|
$this->imWebp->setImageCompressionQuality($this->webpQuality);
|
||||||
|
$this->imWebp->setOption('webp:method', '6');
|
||||||
|
//$this->imWebp->setOption('webp:lossless', 'true'); // is this useful?
|
||||||
|
//$this->imWebp->setImageAlphaChannel(imagick::ALPHACHANNEL_ACTIVATE); // is this useful?
|
||||||
|
//$this->imWebp->setBackgroundColor(new ImagickPixel('transparent')); // is this useful?
|
||||||
|
// save to file
|
||||||
|
$return = $this->imWebp->writeImage($webpFilename);
|
||||||
|
}
|
||||||
|
|
||||||
// release and return to event-object
|
// release and return to event-object
|
||||||
$this->release();
|
$this->release();
|
||||||
$this->modified = true;
|
return $return;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user