1<?php
2
3
4namespace splitbrain\slika;
5
6/**
7 * Image Processing Adapter for ImageMagick's command line utility `convert`
8 */
9class ImageMagickAdapter extends Adapter
10{
11    /** @var array the CLI arguments to run imagemagick */
12    protected $args = [];
13
14    /** @inheritDoc */
15    public function __construct($imagepath, $options = [])
16    {
17        parent::__construct($imagepath, $options);
18
19        if (!is_executable($this->options['imconvert'])) {
20            throw new Exception('Can not find or run ' . $this->options['imconvert']);
21        }
22
23        $this->args[] = $this->options['imconvert'];
24        $this->args[] = $imagepath;
25    }
26
27    /** @inheritDoc */
28    public function autorotate()
29    {
30        $this->args[] = '-auto-orient';
31        return $this;
32    }
33
34    /** @inheritDoc */
35    public function rotate($orientation)
36    {
37        $orientation = (int)$orientation;
38        if ($orientation < 0 || $orientation > 8) {
39            throw new Exception('Unknown rotation given');
40        }
41
42        // rotate
43        $this->args[] = '-rotate';
44        if (in_array($orientation, [3, 4])) {
45            $this->args[] = '180';
46        } elseif (in_array($orientation, [5, 6])) {
47            $this->args[] = '90';
48        } elseif (in_array($orientation, [7, 8])) {
49            $this->args[] = '270';
50        }
51
52        // additionally flip
53        if (in_array($orientation, [2, 5, 7, 4])) {
54            $this->args[] = '-flop';
55        }
56        return $this;
57    }
58
59    /**
60     * @inheritDoc
61     * @throws Exception
62     */
63    public function resize($width, $height)
64    {
65        if ($width == 0 && $height == 0) {
66            throw new Exception('You can not resize to 0x0');
67        }
68        if ($width == 0) $width = '';
69        if ($height == 0) $height = '';
70
71        $size = $width . 'x' . $height;
72
73        $this->args[] = '-resize';
74        $this->args[] = $size;
75        return $this;
76    }
77
78    /**
79     * @inheritDoc
80     * @throws Exception
81     */
82    public function crop($width, $height)
83    {
84        if ($width == 0 && $height == 0) {
85            throw new Exception('You can not crop to 0x0');
86        }
87
88        if ($width == 0) $width = $height;
89        if ($height == 0) $height = $width;
90
91        $size = $width . 'x' . $height;
92
93        $this->args[] = '-resize';
94        $this->args[] = "$size^";
95        $this->args[] = '-gravity';
96        $this->args[] = 'center';
97        $this->args[] = '-crop';
98        $this->args[] = "$size+0+0";
99        $this->args[] = '+repage';
100        return $this;
101    }
102
103    /**
104     * @inheritDoc
105     * @throws Exception
106     */
107    public function save($path, $extension = '')
108    {
109        if ($extension === 'jpg') {
110            $extension = 'jpeg';
111        }
112
113        $this->args[] = '-quality';
114        $this->args[] = $this->options['quality'];
115
116        if ($extension !== '') $path = $extension . ':' . $path;
117        $this->args[] = $path;
118
119        $args = array_map('escapeshellarg', $this->args);
120
121        $cmd = join(' ', $args);
122        $output = [];
123        $return = 0;
124        exec($cmd, $output, $return);
125
126        if ($return !== 0) {
127            throw new Exception('ImageMagick returned non-zero exit code for ' . $cmd);
128        }
129    }
130}
131