PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.2.3
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.2.3
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.3, at vendor/rosell-dk/webp-convert/src/Convert/Converters/Stack.php

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