Test Failed
Push — master ( fa98bc...fd4278 )
by Bjørn
02:17
created

Vips::webpsave()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 12
nc 3
nop 2
dl 0
loc 18
ccs 0
cts 3
cp 0
crap 12
rs 9.8666
c 0
b 0
f 0
1
<?php
2
3
namespace WebPConvert\Convert\Converters;
4
5
use WebPConvert\Convert\BaseConverters\AbstractConverter;
6
use WebPConvert\Convert\Exceptions\ConversionFailedException;
7
use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperational\SystemRequirementsNotMetException;
8
9
//require '/home/rosell/.composer/vendor/autoload.php';
10
11
class Vips extends AbstractConverter
12
{
13
    protected $supportsLossless = true;
14
15 1
    protected function getOptionDefinitionsExtra()
16
    {
17
        return [
18 1
            ['smart-subsample', 'boolean', false],
19
            ['alpha-quality', 'integer', 80],  // alpha quality in lossless mode
20
            ['near-lossless', 'integer', 60],
21
            ['preset', 'integer', 0],  // preset. 0:default, 1:picture, 2:photo, 3:drawing, 4:icon, 5:text, 6:last
22
        ];
23
    }
24
25
    /**
26
     * Check operationality of Vips converter.
27
     *
28
     * @throws SystemRequirementsNotMetException  if system requirements are not met
29
     */
30 1
    public function checkOperationality()
31
    {
32 1
        if (!extension_loaded('vips')) {
33 1
            throw new SystemRequirementsNotMetException('Required Vips extension is not available.');
34
        }
35
36
        if (!function_exists('vips_image_new_from_file')) {
37
            throw new SystemRequirementsNotMetException(
38
                'Vips extension seems to be installed, however something is not right: ' .
39
                'the function "vips_image_new_from_file" is not available.'
40
            );
41
        }
42
43
        // TODO: Should we also test if webp is available? (It seems not to be neccessary - it seems
44
        // that webp be well intergrated part of vips)
45
    }
46
47
    /**
48
     * Check if specific file is convertable with current converter / converter settings.
49
     *
50
     * @throws SystemRequirementsNotMetException  if Vips does not support image type
51
     */
52
    public function checkConvertability()
53
    {
54
        // It seems that png and jpeg are always supported by Vips
55
        // - so nothing needs to be done here
56
57
        if (function_exists('vips_version')) {
58
            $this->logLn('vipslib version: ' . vips_version());
59
        }
60
        $this->logLn('vips extension version: ' . phpversion('vips'));
61
    }
62
63
    /**
64
     * Create vips image resource from source file
65
     *
66
     * @throws  ConversionFailedException  if image resource cannot be created
67
     * @return  resource  vips image resource
68
     */
69
    private function createImageResource()
70
    {
71
        // We are currently using vips_image_new_from_file(), but we could consider
72
        // calling vips_jpegload / vips_pngload instead
73
        $result = /** @scrutinizer ignore-call */ vips_image_new_from_file($this->source, []);
74
        if ($result === -1) {
75
            /*throw new ConversionFailedException(
76
                'Failed creating new vips image from file: ' . $this->source
77
            );*/
78
            $message = /** @scrutinizer ignore-call */ vips_error_buffer();
79
            throw new ConversionFailedException($message);
80
        }
81
82
        if (!is_array($result)) {
83
            throw new ConversionFailedException(
84
                'vips_image_new_from_file did not return an array, which we expected'
85
            );
86
        }
87
88
        if (count($result) != 1) {
89
            throw new ConversionFailedException(
90
                'vips_image_new_from_file did not return an array of length 1 as we expected ' .
91
                '- length was: ' . count($result)
92
            );
93
        }
94
95
        $im = array_shift($result);
96
        return $im;
97
    }
98
99
    /**
100
     * Create parameters for webpsave
101
     *
102
     * @return  array  the parameters as an array
103
     */
104
    private function createParamsForVipsWebPSave()
105
    {
106
        // webpsave options are described here:
107
        // https://jcupitt.github.io/libvips/API/current/VipsForeignSave.html#vips-webpsave
108
109
        $options = [
110
            "Q" => $this->getCalculatedQuality(),
111
            'lossless' => $this->options['lossless'],
112
            'strip' => $this->options['metadata'] == 'none',
113
        ];
114
115
        // Only set the following options if they differ from the default of vipslib
116
        // This ensures we do not get warning if that property isn't supported
117
        if ($this->options['smart-subsample'] !== false) {
118
            $options['smart_subsample'] = $this->options['smart-subsample'];
119
        }
120
        if ($this->options['alpha-quality'] !== 100) {
121
            $options['alpha_q'] = $this->options['alpha-quality'];
122
        }
123
        if ($this->options['preset'] !== 0) {
124
            $options['preset'] = $this->options['preset'];
125
        }
126
        if ($this->options['near-lossless'] !== 100) {
127
            if ($options['lossless'] === true) {
128
                // We only let near_lossless have effect when lossless is set.
129
                // otherwise lossless auto would not work as expected
130
                $options['near_lossless'] = true;
131
132
                // In Vips, the near-lossless value is controlled by Q.
133
                // this differs from how it is done in cwebp, where it is an integer.
134
                // We have chosen same option syntax as cwebp
135
                $options['Q'] = $this->options['near-lossless'];
136
            }
137
        }
138
        return $options;
139
    }
140
141
    /**
142
     * Convert with vips extension.
143
     *
144
     * Tries to create image resource and save it as webp using the calculated options.
145
     * Vips fails when a parameter is not supported, but we detect this and unset that parameter and try again
146
     * (recursively call itself until there is no more of these kind of errors).
147
     *
148
     * @param  resource  $im  A vips image resource to save
149
     * @throws  ConversionFailedException  if conversion fails.
150
     */
151
    private function webpsave($im, $options)
152
    {
153
        $result = /** @scrutinizer ignore-call */ vips_call('webpsave', $im, $this->destination, $options);
154
155
        if ($result === -1) {
156
            $message = /** @scrutinizer ignore-call */ vips_error_buffer();
157
158
            // If the error
159
            if (preg_match("#no property named .(.*).#", $message, $matches)) {
160
                $nameOfPropertyNotFound = $matches[1];
161
                $this->logLn(
162
                    'Your version of vipslib does not support the "' . $nameOfPropertyNotFound . '" property. ' .
163
                    'The option is ignored.'
164
                );
165
                unset($options[$nameOfPropertyNotFound]);
166
                $this->webpsave($im, $options);
0 ignored issues
show
Bug introduced by
The method webpsave() does not exist on WebPConvert\Convert\Converters\Vips. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

166
                $this->/** @scrutinizer ignore-call */ 
167
                       webpsave($im, $options);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
167
            } else {
168
                throw new ConversionFailedException($message);
169
            }
170
        }
171
    }
172
173
    /**
174
     * Convert with vips extension.
175
     *
176
     * Tries to create image resource and save it as webp using the calculated options.
177
     * Vips fails when a parameter is not supported, but we detect this and unset that parameter and try again
178
     * (repeat until success).
179
     *
180
     * @throws  ConversionFailedException  if conversion fails.
181
     */
182
    protected function doActualConvert()
183
    {
184
/*
185
        $im = \Jcupitt\Vips\Image::newFromFile($this->source);
186
        //$im->writeToFile(__DIR__ . '/images/small-vips.webp', ["Q" => 10]);
187
188
        $im->webpsave($this->destination, [
189
            "Q" => 80,
190
            //'near_lossless' => true
191
        ]);
192
        return;*/
193
194
        $im = $this->createImageResource();
195
        $options = $this->createParamsForVipsWebPSave();
196
        $this->webpsave($im, $options);
197
    }
198
}
199