PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.2.22
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.2.22
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / vendor / rosell-dk / webp-convert / src / Convert / Converters / Stack.php

Stack.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 3.2.22, at vendor/rosell-dk/webp-convert/src/Convert/Converters/Stack.php

284 lines 10.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WebPConvert\Convert\Converters;
4
5 use WebPConvert\Convert\ConverterFactory;
6 use WebPConvert\Convert\Converters\AbstractConverter;
7 use WebPConvert\Convert\Exceptions\ConversionFailedException;
8 use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperationalException;
9 use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperational\SystemRequirementsNotMetException;
10 use WebPConvert\Convert\Exceptions\ConversionFailed\ConversionSkippedException;
11 use WebPConvert\Options\OptionFactory;
12
13 //use WebPConvert\Convert\Exceptions\ConversionFailed\InvalidInput\TargetNotFoundException;
14
15 /**
16 * Convert images to webp by trying a stack of converters until success.
17 *
18 * @package WebPConvert
19 * @author Bjørn Rosell <[email protected]>
20 * @since Class available since Release 2.0.0
21 */
22 class Stack extends AbstractConverter
23 {
24
25 protected function getUnsupportedDefaultOptions()
26 {
27 return [
28 'alpha-quality',
29 'auto-filter',
30 'encoding',
31 'low-memory',
32 'metadata',
33 'method',
34 'near-lossless',
35 'preset',
36 'sharp-yuv',
37 'size-in-percentage',
38 'skip',
39 'default-quality',
40 'quality',
41 'max-quality',
42 ];
43 }
44
45 public function getUniqueOptions($imageType)
46 {
47 return OptionFactory::createOptions([
48 ['converters', 'array', [
49 'title' => 'Converters',
50 'description' => 'Converters to try, ordered by priority.',
51 'default' => self::getAvailableConverters(),
52 'sensitive' => true,
53 'ui' => [
54 'component' => 'multi-select',
55 'options' => self::getAvailableConverters(),
56 'advanced' => true
57 ]
58 ]],
59 ['converter-options', 'array', [
60 'title' => 'Converter options',
61 'description' =>
62 'Extra options for specific converters.',
63 'default' => [],
64 'sensitive' => true,
65 'ui' => null
66 ]],
67 ['preferred-converters', 'array', [
68 'title' => 'Preferred converters',
69 'description' =>
70 'With this option you can move specified converters to the top of the stack. ' .
71 'The converters are specified by id.',
72 'default' => [],
73 'ui' => null
74 ]],
75 ['extra-converters', 'array', [
76 'title' => 'Extra converters',
77 'description' =>
78 'Add extra converters to the bottom of the stack',
79 'default' => [],
80 'sensitive' => true,
81 'ui' => null
82 ]],
83 ['shuffle', 'boolean', [
84 'title' => 'Shuffle',
85 'description' =>
86 'Shuffles the converter order on each conversion. ' .
87 'Can for example be used to spread out requests on multiple cloud converters',
88 'default' => false,
89 'ui' => [
90 'component' => 'checkbox',
91 'advanced' => true
92 ]
93 ]],
94 ]);
95
96
97 /*
98 return [
99 new SensitiveArrayOption('converters', self::getAvailableConverters()),
100 new SensitiveArrayOption('converter-options', []),
101 new BooleanOption('shuffle', false),
102 new ArrayOption('preferred-converters', []),
103 new SensitiveArrayOption('extra-converters', [])
104 ];*/
105 }
106
107 /**
108 * Get available converters (ids) - ordered by awesomeness.
109 *
110 * @return array An array of ids of converters that comes with this library
111 */
112 public static function getAvailableConverters()
113 {
114 return [
115 'cwebp', 'vips', 'imagick', 'gmagick', 'imagemagick', 'graphicsmagick', 'wpc', 'ffmpeg', 'ewww', 'gd'
116 ];
117 }
118
119 /**
120 * Check (general) operationality of imagack converter executable
121 *
122 * @throws SystemRequirementsNotMetException if system requirements are not met
123 */
124 public function checkOperationality()
125 {
126 if (count($this->options['converters']) == 0) {
127 throw new ConverterNotOperationalException(
128 'Converter stack is empty! - no converters to try, no conversion can be made!'
129 );
130 }
131
132 // TODO: We should test if all converters are found in order to detect problems early
133
134 //$this->logLn('Stack converter ignited');
135 }
136
137 protected function doActualConvert()
138 {
139 $options = $this->options;
140
141 $beginTimeStack = microtime(true);
142
143 $anyRuntimeErrors = false;
144
145 $converters = $options['converters'];
146 if (count($options['extra-converters']) > 0) {
147 $converters = array_merge($converters, $options['extra-converters']);
148 /*foreach ($options['extra-converters'] as $extra) {
149 $converters[] = $extra;
150 }*/
151 }
152
153 // preferred-converters
154 if (count($options['preferred-converters']) > 0) {
155 foreach (array_reverse($options['preferred-converters']) as $prioritizedConverter) {
156 foreach ($converters as $i => $converter) {
157 if (is_array($converter)) {
158 $converterId = $converter['converter'];
159 } else {
160 $converterId = $converter;
161 }
162 if ($converterId == $prioritizedConverter) {
163 unset($converters[$i]);
164 array_unshift($converters, $converter);
165 break;
166 }
167 }
168 }
169 // perhaps write the order to the log? (without options) - but this requires some effort
170 }
171
172 // shuffle
173 if ($options['shuffle']) {
174 shuffle($converters);
175 }
176
177 //$this->logLn(print_r($converters));
178 //$options['converters'] = $converters;
179 //$defaultConverterOptions = $options;
180 $defaultConverterOptions = [];
181
182 foreach ($this->options2->getOptionsMap() as $id => $option) {
183 // Right here, there used to be a check that ensured that unknown options was not passed down to the
184 // converters (" && !($option instanceof GhostOption)"). But well, as the Stack doesn't know about
185 // converter specific options, such as "try-cwebp", these was not passed down (see #259)
186 // I'm not sure why the check was made in the first place, but it does not seem neccessary, as the
187 // converters simply ignore unknown options. So the check has now been removed.
188 if ($option->isValueExplicitlySet()) {
189 $defaultConverterOptions[$id] = $option->getValue();
190 }
191 }
192
193 //unset($defaultConverterOptions['converters']);
194 //unset($defaultConverterOptions['converter-options']);
195 $defaultConverterOptions['_skip_input_check'] = true;
196 $defaultConverterOptions['_suppress_success_message'] = true;
197 unset($defaultConverterOptions['converters']);
198 unset($defaultConverterOptions['extra-converters']);
199 unset($defaultConverterOptions['converter-options']);
200 unset($defaultConverterOptions['preferred-converters']);
201 unset($defaultConverterOptions['shuffle']);
202
203 // $this->logLn('converters: ' . print_r($converters, true));
204
205 //return;
206 foreach ($converters as $converter) {
207 if (is_array($converter)) {
208 $converterId = $converter['converter'];
209 $converterOptions = isset($converter['options']) ? $converter['options'] : [];
210 } else {
211 $converterId = $converter;
212 $converterOptions = [];
213 if (isset($options['converter-options'][$converterId])) {
214 // Note: right now, converter-options are not meant to be used,
215 // when you have several converters of the same type
216 $converterOptions = $options['converter-options'][$converterId];
217 }
218 }
219 $converterOptions = array_merge($defaultConverterOptions, $converterOptions);
220 /*
221 if ($converterId != 'stack') {
222 //unset($converterOptions['converters']);
223 //unset($converterOptions['converter-options']);
224 } else {
225 //$converterOptions['converter-options'] =
226 $this->logLn('STACK');
227 $this->logLn('converterOptions: ' . print_r($converterOptions, true));
228 }*/
229
230 $beginTime = microtime(true);
231
232 $this->ln();
233 $this->logLn($converterId . ' converter ignited', 'bold');
234
235 $converter = ConverterFactory::makeConverter(
236 $converterId,
237 $this->source,
238 $this->destination,
239 $converterOptions,
240 $this->logger
241 );
242
243 try {
244 $converter->doConvert();
245
246 //self::runConverterWithTiming($converterId, $source, $destination, $converterOptions, false, $logger);
247
248 $this->logLn($converterId . ' succeeded :)');
249 //throw new ConverterNotOperationalException('...');
250 return;
251 } catch (ConverterNotOperationalException $e) {
252 $this->logLn($e->getMessage());
253 } catch (ConversionSkippedException $e) {
254 $this->logLn($e->getMessage());
255 } catch (ConversionFailedException $e) {
256 $this->logLn($e->getMessage(), 'italic');
257 $prev = $e->getPrevious();
258 if (!is_null($prev)) {
259 $this->logLn($prev->getMessage(), 'italic');
260 $this->logLn(' in ' . $prev->getFile() . ', line ' . $prev->getLine(), 'italic');
261 $this->ln();
262 }
263 //$this->logLn($e->getTraceAsString());
264 $anyRuntimeErrors = true;
265 }
266 $this->logLn($converterId . ' failed in ' . round((microtime(true) - $beginTime) * 1000) . ' ms');
267 }
268
269 $this->ln();
270 $this->logLn('Stack failed in ' . round((microtime(true) - $beginTimeStack) * 1000) . ' ms');
271
272 // Hm, Scrutinizer complains that $anyRuntimeErrors is always false. But that is not true!
273 if ($anyRuntimeErrors) {
274 // At least one converter failed
275 throw new ConversionFailedException(
276 'None of the converters in the stack could convert the image.'
277 );
278 } else {
279 // All converters threw a SystemRequirementsNotMetException
280 throw new ConverterNotOperationalException('None of the converters in the stack are operational');
281 }
282 }
283 }
284