Passed
Branch master (145c86)
by Whallysson
01:22
created

ToWebP::toConvert()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 12
nc 5
nop 4
dl 0
loc 21
rs 9.2222
c 1
b 0
f 0
1
<?php
2
3
namespace CodeBlog\ToWebP;
4
5
use CodeBlog\ToWebP\Convert\Make;
6
use Exception;
7
8
/**
9
 * Class ToWebP
10
 *
11
 * Converts JPEG & PNG to WebP with PHP
12
 *
13
 * @author Whallysson Avelino <https://github.com/whallysson>
14
 * @package CodeBlog\ToWebP
15
 */
16
class ToWebP extends Make
17
{
18
19
    /** @var array */
20
    private $converters = ['imagick', 'cwebp', 'gd'];
21
22
    /** @var array */
23
    protected $preferredConverters = [];
24
25
    /** @var array */
26
    protected $allowedExtensions = ['jpg', 'jpeg', 'png'];
27
28
    /** @var string */
29
    public $image_webp;
30
31
    /** @var string */
32
    public $image_original;
33
34
35
    /**
36
     * ToWebP constructor.
37
     * @param string $uploadDir
38
     * @param string $fileTypeDir
39
     * @param array|string $converters
40
     * @throws Exception
41
     */
42
    public function __construct(string $uploadDir, string $fileTypeDir, $converters = [])
43
    {
44
        parent::__construct($uploadDir, $fileTypeDir);
45
46
        if ($converters != null) {
47
            $this->setConverters($converters);
48
        }
49
    }
50
51
    /**
52
     * Converts image to WebP
53
     *
54
     * @param string $source Path of input image
55
     * @param string $name Path of output image
56
     * @param integer $quality Image compression quality (ranging from 0 to 100)
57
     * @param boolean $stripMetadata Whether to strip metadata
58
     *
59
     * @return boolean
60
     */
61
    public function convert(string $source, string $name, int $quality = 85, bool $stripMetadata = true)
62
    {
63
        try {
64
            $this->image_original = $source;
65
66
            $this->isValidTarget($source);
67
            $this->isAllowedExtension($source);
68
69
            $success = false;
70
71
            // set local and name
72
            $this->name($name);
73
74
            if (!file_exists("{$this->path}/{$this->name}")) {
75
                $success = $this->toConvert($source, "{$this->path}/{$this->name}", $quality, $stripMetadata);
76
            }
77
78
            $this->image_webp = "{$this->path}/{$this->name}";
79
            return $success;
80
        } catch (Exception $e) {
81
            echo 'Error: ' . $e->getMessage();
82
        }
83
    }
84
85
86
    /**
87
     * Returns the picture picture formatted with the original image is the source with the type webp
88
     *
89
     * @param array|null $options
90
     * @return string
91
     */
92
    public function picture(array $options = null)
93
    {
94
        $picture = null;
95
        $img = null;
96
97
        if (!empty($options['picture'])) {
98
            foreach ($options['picture'] as $key => $val) {
99
                $picture .= " {$key}='{$val}'";
100
            }
101
        }
102
103
        if (!empty($options['img'])) {
104
            foreach ($options['img'] as $key => $val) {
105
                $img .= " {$key}='{$val}'";
106
            }
107
        }
108
109
        return "<picture{$picture}>
110
                    <source srcset='{$this->image_webp}' type='image/webp'>
111
                    <img src='{$this->image_original}'{$img} />
112
                </picture>";
113
    }
114
115
    /**
116
     * @param string $source
117
     * @param string $filename
118
     * @param int $quality
119
     * @param bool $stripMetadata
120
     * @return bool
121
     */
122
    private function toConvert(string $source, string $filename, int $quality, bool $stripMetadata)
123
    {
124
        $success = false;
125
        foreach ($this->setUpConverters() as $currentConverter) {
126
            $className = 'CodeBlog\\ToWebP\\Convert\\Converters\\' . ucfirst(strtolower($currentConverter));
127
128
            if (!class_exists($className)) { continue; }
129
130
            $converter = new $className( $source, $filename, $quality, $stripMetadata );
131
132
            if (!$converter instanceof AbstractConverter || !is_callable([$converter, 'convert'])) { continue; }
133
134
            $conversion = call_user_func([$converter, 'convert']);
135
136
            if ($conversion) {
137
                $success = true;
138
                $this->setConverters($currentConverter);
139
                break;
140
            }
141
        }
142
        return $success;
143
    }
144
145
    /**
146
     * Checks whether provided file exists
147
     *
148
     * @param $filePath
149
     * @return bool
150
     * @throws Exception
151
     */
152
    private function isValidTarget($filePath)
153
    {
154
        if (!file_exists($filePath)) {
155
            throw new Exception('File or directory not found: ' . $filePath);
156
        }
157
158
        return true;
159
    }
160
161
162
    /**
163
     * @param $filePath
164
     * @return bool
165
     * @throws Exception
166
     */
167
    private function isAllowedExtension($filePath)
168
    {
169
        $fileExtension = pathinfo($filePath, PATHINFO_EXTENSION);
170
        if (!in_array(strtolower($fileExtension), $this->allowedExtensions)) {
171
            throw new Exception('Unsupported file extension: ' . $fileExtension);
172
        }
173
174
        return true;
175
    }
176
177
    /**
178
     * Sets preferred converter(s)
179
     *
180
     * @param array|string $preferred
181
     */
182
    private function setConverters($preferred = [])
183
    {
184
        if (is_string($preferred)) {
185
            $this->preferredConverters = (array)$preferred;
186
            return;
187
        }
188
        $this->preferredConverters = $preferred;
189
    }
190
191
    /**
192
     * Gets preferred converter(s)
193
     *
194
     * @return array
195
     */
196
    public function getConverters()
197
    {
198
        return $this->preferredConverters;
199
    }
200
201
    /**
202
     * Sets up converters to be used during conversion
203
     *
204
     * @return array
205
     */
206
    private function setUpConverters()
207
    {
208
        // Returns available converters if no preferred converters are set
209
        if (empty($this->preferredConverters)) {
210
            return $this->converters;
211
        }
212
213
        // Returns preferred converters if set & remaining ones be skipped
214
        return $this->preferredConverters;
215
    }
216
217
}
218