Passed
Push — master ( dfd837...8a6cb8 )
by Bjørn
03:29
created

Imagick   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 140
Duplicated Lines 0 %

Test Coverage

Coverage 6.98%

Importance

Changes 0
Metric Value
eloc 42
dl 0
loc 140
ccs 3
cts 43
cp 0.0698
rs 10
c 0
b 0
f 0
wmc 16

3 Methods

Rating   Name   Duplication   Size   Complexity  
A checkConvertability() 0 19 5
A checkOperationality() 0 15 4
B doActualConvert() 0 70 7
1
<?php
2
3
namespace WebPConvert\Convert\Converters;
4
5
use WebPConvert\Convert\Converters\AbstractConverter;
6
use WebPConvert\Convert\Exceptions\ConversionFailedException;
7
use WebPConvert\Convert\Exceptions\ConversionFailed\FileSystemProblems\CreateDestinationFileException;
8
use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperational\SystemRequirementsNotMetException;
9
use WebPConvert\Convert\Converters\ConverterTraits\EncodingAutoTrait;
10
11
//use WebPConvert\Convert\Exceptions\ConversionFailed\InvalidInput\TargetNotFoundException;
12
13
/**
14
 * Convert images to webp using Imagick extension.
15
 *
16
 * @package    WebPConvert
17
 * @author     Bjørn Rosell <[email protected]>
18
 * @since      Class available since Release 2.0.0
19
 */
20
class Imagick extends AbstractConverter
21
{
22
    use EncodingAutoTrait;
23
24
    /*
25
    public function supportsLossless()
26
    {
27
        return false;
28
    }*/
29
30
    /**
31
     * Check operationality of Imagick converter.
32
     *
33
     * Note:
34
     * It may be that Gd has been compiled without jpeg support or png support.
35
     * We do not check for this here, as the converter could still be used for the other.
36
     *
37
     * @throws SystemRequirementsNotMetException  if system requirements are not met
38
     * @return void
39
     */
40 1
    public function checkOperationality()
41
    {
42 1
        if (!extension_loaded('imagick')) {
43 1
            throw new SystemRequirementsNotMetException('Required iMagick extension is not available.');
44
        }
45
46
        if (!class_exists('\\Imagick')) {
47
            throw new SystemRequirementsNotMetException(
48
                'iMagick is installed, but not correctly. The class Imagick is not available'
49
            );
50
        }
51
52
        $im = new \Imagick();
53
        if (!in_array('WEBP', $im->queryFormats('WEBP'))) {
54
            throw new SystemRequirementsNotMetException('iMagick was compiled without WebP support.');
55
        }
56
    }
57
58
    /**
59
     * Check if specific file is convertable with current converter / converter settings.
60
     *
61
     * @throws SystemRequirementsNotMetException  if Imagick does not support image type
62
     */
63
    public function checkConvertability()
64
    {
65
        $im = new \Imagick();
66
        $mimeType = $this->getMimeTypeOfSource();
67
        switch ($mimeType) {
68
            case 'image/png':
69
                if (!in_array('PNG', $im->queryFormats('PNG'))) {
70
                    throw new SystemRequirementsNotMetException(
71
                        'Imagick has been compiled without PNG support and can therefore not convert this PNG image.'
72
                    );
73
                }
74
                break;
75
            case 'image/jpeg':
76
                if (!in_array('JPEG', $im->queryFormats('JPEG'))) {
77
                    throw new SystemRequirementsNotMetException(
78
                        'Imagick has been compiled without Jpeg support and can therefore not convert this Jpeg image.'
79
                    );
80
                }
81
                break;
82
        }
83
    }
84
85
    /**
86
     *
87
     * It may also throw an ImagickException if imagick throws an exception
88
     * @throws CreateDestinationFileException if imageblob could not be saved to file
89
     */
90
    protected function doActualConvert()
91
    {
92
        /*
93
         * More about iMagick's WebP options:
94
         * - Inspect source code: https://github.com/ImageMagick/ImageMagick/blob/master/coders/webp.c#L559
95
         *      (search for "webp:")
96
         * - http://www.imagemagick.org/script/webp.php
97
         * - https://developers.google.com/speed/webp/docs/cwebp
98
         * - https://stackoverflow.com/questions/37711492/imagemagick-specific-webp-calls-in-php
99
         */
100
101
        $options = $this->options;
102
103
        // This might throw - we let it!
104
        $im = new \Imagick($this->source);
105
106
        //$im = new \Imagick();
107
        //$im->pingImage($this->source);
108
        //$im->readImage($this->source);
109
110
        $im->setImageFormat('WEBP');
111
112
        $im->setOption('webp:method', $options['method']);
113
        $im->setOption('webp:lossless', $options['encoding'] == 'lossless' ? 'true' : 'false');
114
        $im->setOption('webp:low-memory', $options['low-memory'] ? 'true' : 'false');
115
        $im->setOption('webp:alpha-quality', $options['alpha-quality']);
116
117
        if ($options['auto-filter'] === true) {
118
            $im->setOption('webp:auto-filter', 'true');
119
        }
120
121
        if ($options['metadata'] == 'none') {
122
            // Strip metadata and profiles
123
            $im->stripImage();
124
        }
125
126
        if ($this->isQualityDetectionRequiredButFailing()) {
127
            // Luckily imagick is a big boy, and automatically converts with same quality as
128
            // source, when the quality isn't set.
129
            // So we simply do not set quality.
130
            // This actually kills the max-quality functionality. But I deem that this is more important
131
            // because setting image quality to something higher than source generates bigger files,
132
            // but gets you no extra quality. When failing to limit quality, you at least get something
133
            // out of it
134
            $this->logLn('Converting without setting quality in order to achieve auto quality');
135
        } else {
136
            $im->setImageCompressionQuality($this->getCalculatedQuality());
137
        }
138
139
        // https://stackoverflow.com/questions/29171248/php-imagick-jpeg-optimization
140
        // setImageFormat
141
142
        // TODO: Read up on
143
        // https://www.smashingmagazine.com/2015/06/efficient-image-resizing-with-imagemagick/
144
        // https://github.com/nwtn/php-respimg
145
146
        // TODO:
147
        // Should we set alpha channel for PNG's like suggested here:
148
        // https://gauntface.com/blog/2014/09/02/webp-support-with-imagemagick-and-php ??
149
        // It seems that alpha channel works without... (at least I see completely transparerent pixels)
150
151
        // We used to use writeImageFile() method. But we now use getImageBlob(). See issue #43
152
153
        // This might throw - we let it!
154
        $imageBlob = $im->getImageBlob();
155
156
        $success = file_put_contents($this->destination, $imageBlob);
157
158
        if (!$success) {
159
            throw new CreateDestinationFileException('Failed writing file');
160
        }
161
162
        // Btw: check out processWebp() method here:
163
        // https://github.com/Intervention/image/blob/master/src/Intervention/Image/Imagick/Encoder.php
164
    }
165
}
166