File "OptionsTrait.php"
Full Path: /var/www/html/wordpress/wp-content/plugins/wp-optimize/vendor/rosell-dk/webp-convert/src/Convert/Converters/BaseTraits/OptionsTrait.php
File size: 23.97 KB
MIME-type: text/x-php
Charset: utf-8
<?php
namespace WebPConvert\Convert\Converters\BaseTraits;
use WebPConvert\Convert\Converters\Stack;
use WebPConvert\Convert\Exceptions\ConversionFailed\ConversionSkippedException;
use WebPConvert\Options\Exceptions\InvalidOptionValueException;
use WebPConvert\Options\Exceptions\InvalidOptionTypeException;
use WebPConvert\Options\GhostOption;
use WebPConvert\Options\Options;
use WebPConvert\Options\OptionFactory;
/**
* Trait for handling options
*
* This trait is currently only used in the AbstractConverter class. It has been extracted into a
* trait in order to bundle the methods concerning options.
*
* @package WebPConvert
* @author Bjørn Rosell <[email protected]>
* @since Class available since Release 2.0.0
*/
trait OptionsTrait
{
abstract public function log($msg, $style = '');
abstract public function logLn($msg, $style = '');
abstract protected function getMimeTypeOfSource();
/** @var array Provided conversion options (array of simple objects)*/
public $providedOptions;
/** @var array Calculated conversion options (merge of default options and provided options)*/
protected $options;
/** @var Options */
protected $options2;
/**
* Get the "general" options (options that are standard in the meaning that they
* are generally available (unless specifically marked as unsupported by a given converter)
*
* @param string $imageType (png | jpeg) The image type - determines the defaults
*
* @return array Array of options
*/
public function getGeneralOptions($imageType)
{
$isPng = ($imageType == 'png');
/*
return [
//new IntegerOption('auto-limit-adjustment', 5, -100, 100),
new BooleanOption('log-call-arguments', false),
new BooleanOption('skip', false),
new BooleanOption('use-nice', false),
new ArrayOption('jpeg', []),
new ArrayOption('png', [])
];*/
$introMd = 'https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/' .
'converting/introduction-for-converting.md';
return OptionFactory::createOptions([
['encoding', 'string', [
'title' => 'Encoding',
'description' => 'Set encoding for the webp. ' .
'If you choose "auto", webp-convert will ' .
'convert to both lossy and lossless and pick the smallest result',
'default' => 'auto',
'enum' => ['auto', 'lossy', 'lossless'],
'ui' => [
'component' => 'select',
'links' => [['Guide', $introMd . '#auto-selecting-between-losslesslossy-encoding']],
]
]],
['quality', 'int', [
'title' => 'Quality (Lossy)',
'description' =>
'Quality for lossy encoding. ' .
'In case you enable "auto-limit", you can consider this property a maximum quality.',
'default' => ($isPng ? 85 : 75),
'default-png' => 85,
'default-jpeg' => 75,
//'minimum' => 0,
//'maximum' => 100,
"oneOf" => [
["type" => "number", "minimum" => 0, 'maximum' => 100],
["type" => "string", "enum" => ["auto"]]
],
'ui' => [
'component' => 'slider',
'display' => "option('encoding') != 'lossless'"
]
]],
['auto-limit', 'boolean', [
'title' => 'Auto-limit',
'description' =>
'Enable this option to prevent an unnecessarily high quality setting for low ' .
'quality jpegs. It works by adjusting quality setting down to the quality of the jpeg. ' .
'Converting ie a jpeg with quality:50 to ie quality:80 does not get you better quality ' .
'than converting it to quality:80, but it does get you a much bigger file - so you ' .
'really should enable this option.' . "\n\n" .
'The option is ignored for PNG and never adjusts quality up. ' . "\n\n" .
'The feature requires Imagick, ImageMagick or Gmagick in order to detect the quality of ' .
'the jpeg. ' . "\n\n" .
'PS: The "auto-limit" option is relative new. However, before this option, you could achieve ' .
'the same by setting quality to "auto" and specifying a "max-quality" and a "default-quality". ' .
'These are deprecated now, but still works.',
'default' => true,
'ui' => [
'component' => 'checkbox',
'advanced' => true,
'links' => [
[
'Guide',
$introMd . '#preventing-unnecessarily-high-quality-setting-for-low-quality-jpegs'
]
],
'display' => "option('encoding') != 'lossless'"
]
]],
['alpha-quality', 'int', [
'title' => 'Alpha quality',
'description' =>
'Quality of alpha channel. ' .
'Often, there is no need for high quality transparency layer and in some cases you ' .
'can tweak this all the way down to 10 and save a lot in file size. The option only ' .
'has effect with lossy encoding, and of course only on images with transparency.',
'default' => 85,
'minimum' => 0,
'maximum' => 100,
'ui' => [
'component' => 'slider',
'links' => [['Guide', $introMd . '#alpha-quality']],
'display' => "(option('encoding') != 'lossless') && (imageType!='jpeg')"
]
]],
['near-lossless', 'int', [
'title' => '"Near lossless" quality',
'description' =>
'This option allows you to get impressively better compression for lossless encoding, with ' .
'minimal impact on visual quality. The range is 0 (maximum preprocessing) to 100 (no ' .
'preprocessing). Read the guide for more info.',
'default' => 60,
'minimum' => 0,
'maximum' => 100,
'ui' => [
'component' => 'slider',
'links' => [['Guide', $introMd . '#near-lossless']],
'display' => "option('encoding') != 'lossy'"
]
]],
['metadata', 'string', [
'title' => 'Metadata',
'description' =>
'Determines which metadata that should be copied over to the webp. ' .
'Setting it to "all" preserves all metadata, setting it to "none" strips all metadata. ' .
'*cwebp* can take a comma-separated list of which kinds of metadata that should be copied ' .
'(ie "exif,icc"). *gd* will always remove all metadata and *ffmpeg* will always keep all ' .
'metadata. The rest can either strip all or keep all (they will keep all, unless the option ' .
'is set to *none*)',
'default' => 'none',
'ui' => [
'component' => 'multi-select',
'options' => ['all', 'none', 'exif', 'icc', 'xmp'],
]
// TODO: set regex validation
]],
['method', 'int', [
'title' => 'Reduction effort (0-6)',
'description' =>
'Controls the trade off between encoding speed and the compressed file size and quality. ' .
'Possible values range from 0 to 6. 0 is fastest. 6 results in best quality and compression. ' .
'PS: The option corresponds to the "method" option in libwebp',
'default' => 6,
'minimum' => 0,
'maximum' => 6,
'ui' => [
'component' => 'slider',
'advanced' => true,
]
]],
['sharp-yuv', 'boolean', [
'title' => 'Sharp YUV',
'description' =>
'Better RGB->YUV color conversion (sharper and more accurate) at the expense of a little extra ' .
'conversion time.',
'default' => true,
'ui' => [
'component' => 'checkbox',
'advanced' => true,
'links' => [
['Ctrl.blog', 'https://www.ctrl.blog/entry/webp-sharp-yuv.html'],
],
]
]],
['auto-filter', 'boolean', [
'title' => 'Auto-filter',
'description' =>
'Turns auto-filter on. ' .
'This algorithm will spend additional time optimizing the filtering strength to reach a well-' .
'balanced quality. Unfortunately, it is extremely expensive in terms of computation. It takes ' .
'about 5-10 times longer to do a conversion. A 1MB picture which perhaps typically takes about ' .
'2 seconds to convert, will takes about 15 seconds to convert with auto-filter. ',
'default' => false,
'ui' => [
'component' => 'checkbox',
'advanced' => true,
]
]],
['low-memory', 'boolean', [
'title' => 'Low memory',
'description' =>
'Reduce memory usage of lossy encoding at the cost of ~30% longer encoding time and marginally ' .
'larger output size. Only effective when the *method* option is 3 or more. Read more in ' .
'[the docs](https://developers.google.com/speed/webp/docs/cwebp)',
'default' => false,
'ui' => [
'component' => 'checkbox',
'advanced' => true,
'display' => "(option('encoding') != 'lossless') && (option('method')>2)"
]
]],
['preset', 'string', [
'title' => 'Preset',
'description' =>
'Using a preset will set many of the other options to suit a particular type of ' .
'source material. It even overrides them. It does however not override the quality option. ' .
'"none" means that no preset will be set',
'default' => 'none',
'enum' => ['none', 'default', 'photo', 'picture', 'drawing', 'icon', 'text'],
'ui' => [
'component' => 'select',
'advanced' => true,
]
]],
['size-in-percentage', 'int', ['default' => null, 'minimum' => 0, 'maximum' => 100, 'allow-null' => true]],
['skip', 'boolean', ['default' => false]],
['log-call-arguments', 'boolean', ['default' => false]],
// TODO: use-nice should not be a "general" option
//['use-nice', 'boolean', ['default' => false]],
['jpeg', 'array', ['default' => []]],
['png', 'array', ['default' => []]],
// Deprecated options
['default-quality', 'int', [
'default' => ($isPng ? 85 : 75),
'minimum' => 0,
'maximum' => 100,
'deprecated' => true]
],
['max-quality', 'int', ['default' => 85, 'minimum' => 0, 'maximum' => 100, 'deprecated' => true]],
]);
}
/**
* Get the unique options for a converter
*
* @param string $imageType (png | jpeg) The image type - determines the defaults
*
* @return array Array of options
*/
public function getUniqueOptions($imageType)
{
return [];
}
/**
* Create options.
*
* The options created here will be available to all converters.
* Individual converters may add options by overriding this method.
*
* @param string $imageType (png | jpeg) The image type - determines the defaults
*
* @return void
*/
protected function createOptions($imageType = 'png')
{
$this->options2 = new Options();
$this->options2->addOptions(... $this->getGeneralOptions($imageType));
$this->options2->addOptions(... $this->getUniqueOptions($imageType));
}
/**
* Set "provided options" (options provided by the user when calling convert().
*
* This also calculates the protected options array, by merging in the default options, merging
* jpeg and png options and merging prefixed options (such as 'vips-quality').
* The resulting options array are set in the protected property $this->options and can be
* retrieved using the public ::getOptions() function.
*
* @param array $providedOptions (optional)
* @return void
*/
public function setProvidedOptions($providedOptions = [])
{
$imageType = ($this->getMimeTypeOfSource() == 'image/png' ? 'png' : 'jpeg');
$this->createOptions($imageType);
$this->providedOptions = $providedOptions;
if (isset($this->providedOptions['png'])) {
if ($this->getMimeTypeOfSource() == 'image/png') {
$this->providedOptions = array_merge($this->providedOptions, $this->providedOptions['png']);
// $this->logLn(print_r($this->providedOptions, true));
unset($this->providedOptions['png']);
}
}
if (isset($this->providedOptions['jpeg'])) {
if ($this->getMimeTypeOfSource() == 'image/jpeg') {
$this->providedOptions = array_merge($this->providedOptions, $this->providedOptions['jpeg']);
unset($this->providedOptions['jpeg']);
}
}
// merge down converter-prefixed options
$converterId = self::getConverterId();
$strLen = strlen($converterId);
foreach ($this->providedOptions as $optionKey => $optionValue) {
if (substr($optionKey, 0, $strLen + 1) == ($converterId . '-')) {
$this->providedOptions[substr($optionKey, $strLen + 1)] = $optionValue;
unset($this->providedOptions[$optionKey]);
}
}
// Create options (Option objects)
foreach ($this->providedOptions as $optionId => $optionValue) {
$this->options2->setOrCreateOption($optionId, $optionValue);
}
//$this->logLn(print_r($this->options2->getOptions(), true));
//$this->logLn($this->options2->getOption('hello'));
// Create flat associative array of options
$this->options = $this->options2->getOptions();
// - Merge $defaultOptions into provided options
//$this->options = array_merge($this->getDefaultOptions(), $this->providedOptions);
//$this->logOptions();
}
/**
* Get the resulting options after merging provided options with default options.
*
* Note that the defaults depends on the mime type of the source. For example, the default value for quality
* is "auto" for jpegs, and 85 for pngs.
*
* @return array An associative array of options: ['metadata' => 'none', ...]
*/
public function getOptions()
{
return $this->options;
}
/**
* Change an option specifically.
*
* This method is probably rarely neeeded. We are using it to change the "encoding" option temporarily
* in the EncodingAutoTrait.
*
* @param string $id Id of option (ie "metadata")
* @param mixed $value The new value.
* @return void
*/
protected function setOption($id, $value)
{
$this->options[$id] = $value;
$this->options2->setOrCreateOption($id, $value);
}
/**
* Check options.
*
* @throws InvalidOptionTypeException if an option have wrong type
* @throws InvalidOptionValueException if an option value is out of range
* @throws ConversionSkippedException if 'skip' option is set to true
* @return void
*/
protected function checkOptions()
{
$this->options2->check();
if ($this->options['skip']) {
if (($this->getMimeTypeOfSource() == 'image/png') && isset($this->options['png']['skip'])) {
throw new ConversionSkippedException(
'skipped conversion (configured to do so for PNG)'
);
} else {
throw new ConversionSkippedException(
'skipped conversion (configured to do so)'
);
}
}
}
public function logOptions()
{
$this->logLn('');
$this->logLn('Options:');
$this->logLn('------------');
$unsupported = $this->getUnsupportedDefaultOptions();
$received = [];
$implicitlySet = [];
foreach ($this->options2->getOptionsMap() as $id => $option) {
if (in_array($id, [
'png', 'jpeg', '_skip_input_check', '_suppress_success_message', 'skip', 'log_call_arguments'
])) {
continue;
}
if ($option->isValueExplicitlySet()) {
$received[] = $option;
} else {
if (($option instanceof GhostOption) || in_array($id, $unsupported)) {
//$received[] = $option;
} else {
if (!$option->isDeprecated()) {
$implicitlySet[] = $option;
}
}
}
}
if (count($received) > 0) {
foreach ($received as $option) {
$this->log('- ' . $option->getId() . ': ');
if ($option instanceof GhostOption) {
$this->log(' (unknown to ' . $this->getConverterId() . ')', 'bold');
$this->logLn('');
continue;
}
$this->log($option->getValueForPrint());
if ($option->isDeprecated()) {
$this->log(' (deprecated)', 'bold');
}
if (in_array($option->getId(), $unsupported)) {
if ($this instanceof Stack) {
//$this->log(' *(passed on)*');
} else {
$this->log(' (unsupported by ' . $this->getConverterId() . ')', 'bold');
}
}
$this->logLn('');
}
$this->logLn('');
$this->logLn(
'Note that these are the resulting options after merging down the "jpeg" and "png" options and any ' .
'converter-prefixed options'
);
}
if (count($implicitlySet) > 0) {
$this->logLn('');
$this->logLn('Defaults:');
$this->logLn('------------');
$this->logLn(
'The following options was not set, so using the following defaults:'
);
foreach ($implicitlySet as $option) {
$this->log('- ' . $option->getId() . ': ');
$this->log($option->getValueForPrint());
/*if ($option instanceof GhostOption) {
$this->log(' **(ghost)**');
}*/
$this->logLn('');
}
}
}
// to be overridden by converters
protected function getUnsupportedDefaultOptions()
{
return [];
}
public function getUnsupportedGeneralOptions()
{
return $this->getUnsupportedDefaultOptions();
}
/**
* Get unique option definitions.
*
* Gets definitions of the converters "unique" options (that is, those options that
* are not general). It was added in order to give GUI's a way to automatically adjust
* their setting screens.
*
* @param bool $filterOutOptionsWithoutUI If options without UI defined should be filtered out
* @param string $imageType (png | jpeg) The image type - determines the defaults
*
* @return array Array of options definitions - ready to be json encoded, or whatever
*/
public function getUniqueOptionDefinitions($filterOutOptionsWithoutUI = true, $imageType = 'jpeg')
{
$uniqueOptions = new Options();
//$uniqueOptions->addOptions(... $this->getUniqueOptions($imageType));
foreach ($this->getUniqueOptions($imageType) as $uoption) {
$uoption->setId(self::getConverterId() . '-' . $uoption->getId());
$uniqueOptions->addOption($uoption);
}
$optionDefinitions = $uniqueOptions->getDefinitions();
if ($filterOutOptionsWithoutUI) {
$optionDefinitions = array_filter($optionDefinitions, function ($value) {
return !is_null($value['ui']);
});
$optionDefinitions = array_values($optionDefinitions); // re-index
}
return $optionDefinitions;
}
/**
* Get general option definitions.
*
* Gets definitions of all general options (not just the ones supported by current converter)
* For UI's, as a way to automatically adjust their setting screens.
*
* @param bool $filterOutOptionsWithoutUI If options without UI defined should be filtered out
* @param string $imageType (png | jpeg) The image type - determines the defaults
*
* @return array Array of options definitions - ready to be json encoded, or whatever
*/
public function getGeneralOptionDefinitions($filterOutOptionsWithoutUI = true, $imageType = 'jpeg')
{
$generalOptions = new Options();
$generalOptions->addOptions(... $this->getGeneralOptions($imageType));
//$generalOptions->setUI($this->getUIForGeneralOptions($imageType));
$optionDefinitions = $generalOptions->getDefinitions();
if ($filterOutOptionsWithoutUI) {
$optionDefinitions = array_filter($optionDefinitions, function ($value) {
return !is_null($value['ui']);
});
$optionDefinitions = array_values($optionDefinitions); // re-index
}
return $optionDefinitions;
}
public function getSupportedGeneralOptions($imageType = 'png')
{
$unsupportedGeneral = $this->getUnsupportedDefaultOptions();
$generalOptionsArr = $this->getGeneralOptions($imageType);
$supportedIds = [];
foreach ($generalOptionsArr as $i => $option) {
if (in_array($option->getId(), $unsupportedGeneral)) {
unset($generalOptionsArr[$i]);
}
}
return $generalOptionsArr;
}
/**
* Get general option definitions.
*
* Gets definitions of the converters "general" options. (that is, those options that
* It was added in order to give GUI's a way to automatically adjust their setting screens.
*
* @param string $imageType (png | jpeg) The image type - determines the defaults
*
* @return array Array of options definitions - ready to be json encoded, or whatever
*/
public function getSupportedGeneralOptionDefinitions($imageType = 'png')
{
$generalOptions = new Options();
$generalOptions->addOptions(... $this->getSupportedGeneralOptions($imageType));
return $generalOptions->getDefinitions();
}
public function getSupportedGeneralOptionIds()
{
$supportedGeneralOptions = $this->getSupportedGeneralOptions();
$supportedGeneralIds = [];
foreach ($supportedGeneralOptions as $option) {
$supportedGeneralIds[] = $option->getId();
}
return $supportedGeneralIds;
}
}