Passed
Push — master ( fac0f4...8e4666 )
by Bjørn
07:13
created

FFMpeg::isWebPDelegateInstalled()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 5
c 1
b 0
f 0
nc 3
nop 0
dl 0
loc 9
rs 10
1
<?php
2
3
namespace WebPConvert\Convert\Converters;
4
5
use WebPConvert\Convert\Converters\AbstractConverter;
6
use WebPConvert\Convert\Converters\ConverterTraits\ExecTrait;
7
use WebPConvert\Convert\Converters\ConverterTraits\EncodingAutoTrait;
8
use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperational\SystemRequirementsNotMetException;
9
use WebPConvert\Convert\Exceptions\ConversionFailedException;
10
11
//use WebPConvert\Convert\Exceptions\ConversionFailed\InvalidInput\TargetNotFoundException;
12
13
/**
14
 * Convert images to webp by calling imagemagick binary.
15
 *
16
 * @package    WebPConvert
17
 * @author     Bjørn Rosell <[email protected]>
18
 * @since      Class available since Release 2.0.0
19
 */
20
class FFMpeg extends AbstractConverter
21
{
22
    use ExecTrait;
23
    use EncodingAutoTrait;
24
25
    protected function getUnsupportedDefaultOptions()
26
    {
27
        return [
28
            'alpha-quality',
29
            'auto-filter',
30
            'encoding',
31
            'low-memory',
32
            'near-lossless',
33
            'preset',
34
            'size-in-percentage',
35
            'use-nice'
36
        ];
37
    }
38
39
    private function getPath()
40
    {
41
        if (defined('WEBPCONVERT_FFMPEG_PATH')) {
42
            return constant('WEBPCONVERT_FFMPEG_PATH');
43
        }
44
        if (!empty(getenv('WEBPCONVERT_FFMPEG_PATH'))) {
45
            return getenv('WEBPCONVERT_FFMPEG_PATH');
46
        }
47
        return 'ffmpeg';
48
    }
49
50
    public function isInstalled()
51
    {
52
        exec($this->getPath() . ' -version 2>&1', $output, $returnCode);
53
        return ($returnCode == 0);
54
    }
55
56
    // Check if webp delegate is installed
57
    public function isWebPDelegateInstalled()
58
    {
59
        exec($this->getPath() . ' -version 2>&1', $output, $returnCode);
60
        foreach ($output as $line) {
61
            if (preg_match('# --enable-libwebp#i', $line)) {
62
                return true;
63
            }
64
        }
65
        return false;
66
    }
67
68
    /**
69
     * Check (general) operationality of imagack converter executable
70
     *
71
     * @throws SystemRequirementsNotMetException  if system requirements are not met
72
     */
73
    public function checkOperationality()
74
    {
75
        $this->checkOperationalityExecTrait();
76
77
        if (!$this->isInstalled()) {
78
            throw new SystemRequirementsNotMetException(
79
                'ffmpeg is not installed (cannot execute: "' . $this->getPath() . '")'
80
            );
81
        }
82
        if (!$this->isWebPDelegateInstalled()) {
83
            throw new SystemRequirementsNotMetException('ffmpeg was compiled without libwebp');
84
        }
85
    }
86
87
    /**
88
     * Build command line options
89
     *
90
     * @return string
91
     */
92
    private function createCommandLineOptions()
93
    {
94
        // PS: Available webp options for ffmpeg are documented here:
95
        // https://www.ffmpeg.org/ffmpeg-codecs.html#libwebp
96
97
        $commandArguments = [];
98
99
        $commandArguments[] = '-i';
100
        $commandArguments[] = escapeshellarg($this->source);
101
102
        // preset. Appears first in the list as recommended in the cwebp docs
103
        if (!is_null($this->options['preset'])) {
104
            if ($this->options['preset'] != 'none') {
105
                $cmdOptions[] = '-preset ' . $this->options['preset'];
0 ignored issues
show
Comprehensibility Best Practice introduced by
$cmdOptions was never initialized. Although not strictly required by PHP, it is generally a good practice to add $cmdOptions = array(); before regardless.
Loading history...
106
            }
107
        }
108
109
        // Overwrite existing files?, yes!
110
        $commandArguments[] = '-y';
111
112
        if ($this->isQualityDetectionRequiredButFailing()) {
113
            // quality:auto was specified, but could not be determined.
114
            // we cannot apply the max-quality logic, but we can provide auto quality
115
            // simply by not specifying the quality option.
116
        } else {
117
            $commandArguments[] = '-qscale ' . escapeshellarg($this->getCalculatedQuality());
118
        }
119
        if ($this->options['encoding'] == 'lossless') {
120
            $commandArguments[] = '-lossless 1';
121
        } else {
122
            $commandArguments[] = '-lossless 0';
123
        }
124
125
        if ($this->options['metadata'] == 'none') {
126
            // Unfortunately there seems to be no easy solution available for removing all metadata.
127
        }
128
129
        // compression_level maps to method, according to https://www.ffmpeg.org/ffmpeg-codecs.html#libwebp
130
        $commandArguments[] = '-compression_level ' . $this->options['method'];
131
132
        $commandArguments[] = escapeshellarg($this->destination);
133
134
135
        return implode(' ', $commandArguments);
136
    }
137
138
    protected function doActualConvert()
139
    {
140
        //$this->logLn($this->getVersion());
141
142
        $command = $this->getPath() . ' ' . $this->createCommandLineOptions() . ' 2>&1';
143
144
        $useNice = (($this->options['use-nice']) && self::hasNiceSupport()) ? true : false;
145
        if ($useNice) {
146
            $this->logLn('using nice');
147
            $command = 'nice ' . $command;
148
        }
149
        $this->logLn('Executing command: ' . $command);
150
        exec($command, $output, $returnCode);
151
152
        $this->logExecOutput($output);
153
        if ($returnCode == 0) {
154
            $this->logLn('success');
155
        } else {
156
            $this->logLn('return code: ' . $returnCode);
157
        }
158
159
        if ($returnCode == 127) {
160
            throw new SystemRequirementsNotMetException('ffmpeg is not installed');
161
        }
162
        if ($returnCode != 0) {
163
            throw new SystemRequirementsNotMetException('The exec call failed');
164
        }
165
    }
166
}
167