Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
67.50% covered (warning)
67.50%
27 / 40
44.44% covered (danger)
44.44%
4 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
ImageMagick
67.50% covered (warning)
67.50%
27 / 40
44.44% covered (danger)
44.44%
4 / 9
41.16
0.00% covered (danger)
0.00%
0 / 1
 __construct
80.00% covered (warning)
80.00%
8 / 10
0.00% covered (danger)
0.00%
0 / 1
3.07
 getQuery
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setQuery
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __clone
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getBinary
50.00% covered (danger)
50.00%
2 / 4
0.00% covered (danger)
0.00%
0 / 1
4.12
 getCommand
22.22% covered (danger)
22.22%
2 / 9
0.00% covered (danger)
0.00%
0 / 1
16.76
 execute
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
4.25
 raw
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
 validProgram
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3/**
4 * Karla ImageMagick wrapper library
5 *
6 * PHP Version 8.0<
7 *
8 * @category Utility
9 * @author   Johannes Skov Frandsen <jsf@greenoak.dk>
10 * @license  http://www.opensource.org/licenses/mit-license.php MIT
11 * @link     https://github.com/localgod/karla Karla
12 * @since    2012-04-05
13 */
14
15declare(strict_types=1);
16
17namespace Karla\Program;
18
19use Karla\Query;
20use Karla\Cache;
21
22/**
23 * Class for wrapping ImageMagick arguments used by all tools
24 *
25 * @category Utility
26 * @author   Johannes Skov Frandsen <jsf@greenoak.dk>
27 * @license  http://www.opensource.org/licenses/mit-license.php MIT
28 * @link     https://github.com/localgod/karla Karla
29 */
30abstract class ImageMagick implements \Karla\Program
31{
32    /**
33     * ImageMagick tool animate
34     *
35     * @var string
36     */
37    public const IMAGEMAGICK_ANIMATE = 'animate';
38
39    /**
40     * ImageMagick tool compare
41     *
42     * @var string
43     */
44    public const IMAGEMAGICK_COMPARE = 'compare';
45
46    /**
47     * ImageMagick tool composite
48     *
49     * @var string
50     */
51    public const IMAGEMAGICK_COMPOSITE = 'composite';
52
53    /**
54     * ImageMagick tool
55     *
56     * @var string
57     */
58    public const IMAGEMAGICK_CONJURE = 'conjure';
59
60    /**
61     * ImageMagick tool conjure
62     *
63     * @var string
64     */
65    public const IMAGEMAGICK_CONVERT = 'convert';
66
67    /**
68     * ImageMagick tool display
69     *
70     * @var string
71     */
72    public const IMAGEMAGICK_DISPLAY = 'display';
73
74    /**
75     * ImageMagick tool identify
76     *
77     * @var string
78     */
79    public const IMAGEMAGICK_IDENTIFY = 'identify';
80
81    /**
82     * ImageMagick tool import
83     *
84     * @var string
85     */
86    public const IMAGEMAGICK_IMPORT = 'import';
87
88    /**
89     * ImageMagick tool mogrify
90     *
91     * @var string
92     */
93    public const IMAGEMAGICK_MOGRIFY = 'mogrify';
94
95    /**
96     * ImageMagick tool montage
97     *
98     * @var string
99     */
100    public const IMAGEMAGICK_MONTAGE = 'montage';
101
102    /**
103     * ImageMagick tool stream
104     *
105     * @var string
106     */
107    public const IMAGEMAGICK_STREAM = 'stream';
108
109    /**
110     * ImageMagick unified command (v7+)
111     *
112     * @var string
113     */
114    public const IMAGEMAGICK_MAGICK = 'magick';
115
116    /**
117     * Path to binaries
118     *
119     * @var string
120     */
121    public string $binPath;
122
123    /**
124     * ImageMagick major version
125     *
126     * @var int|null
127     */
128    protected int|null $version = null;
129
130    /**
131     * Name of binary
132     *
133     * @var string
134     */
135    protected string $bin;
136
137    /**
138     * Cache controller
139     *
140     * @var Cache
141     */
142    protected Cache|null $cache;
143
144    /**
145     * The current query
146     *
147     * @var Query
148     */
149    private Query $query;
150
151    /**
152     * Contructs a new program
153     *
154     * @param string $binPath
155     *            Path to binaries
156     * @param string $bin
157     *            Binary
158     * @param \Karla\Cache|null $cache
159     *            Cache controller (default null = no cache)
160     * @param int|null $version
161     *            ImageMagick major version (6 or 7)
162     *
163     * @throws \InvalidArgumentException
164     */
165    final public function __construct(
166        string $binPath,
167        string $bin,
168        \Karla\Cache|null $cache = null,
169        int|null $version = null
170    ) {
171        if ($binPath == '') {
172            throw new \InvalidArgumentException('Invalid bin path');
173        }
174        if ($bin == '') {
175            throw new \InvalidArgumentException('Invalid bin');
176        }
177        $this->binPath = $binPath;
178        $this->bin = $bin;
179        $this->cache = $cache;
180        $this->version = $version;
181        $this->query = new Query();
182        $this->getQuery()->reset();
183    }
184
185    /**
186     * Get the current query
187     */
188    public function getQuery(): Query
189    {
190        return $this->query;
191    }
192
193    /**
194     * Set the current query
195     *
196     * @param Query $query Query to set
197     */
198    public function setQuery(Query $query): void
199    {
200        $this->query = $query;
201    }
202
203    /**
204     * It should not be possible to clon the ImageMagick object.
205     */
206    final public function __clone(): void
207    {
208        throw new \BadMethodCallException("Clone is not allowed");
209    }
210
211    /**
212     * Get the binary executable path (for use in -list commands, etc.)
213     * This returns just the base binary without full command setup
214     */
215    public function getBinary(): string
216    {
217        // For ImageMagick 7+, use 'magick' instead of separate tools
218        if ($this->version !== null && $this->version >= 7) {
219            $magickBin = \Karla\Platform::getBinary(self::IMAGEMAGICK_MAGICK);
220            return $this->binPath . $magickBin;
221        }
222
223        return $this->binPath . $this->bin;
224    }
225
226    /**
227     * Get the command to run
228     */
229    public function getCommand(): string
230    {
231        // For ImageMagick 7+, use 'magick' instead of separate tools
232        if ($this->version !== null && $this->version >= 7) {
233            // Get the base command name without .exe extension
234            $command = str_replace('.exe', '', $this->bin);
235
236            // For convert, just use 'magick' (ImageMagick 7 combines convert functionality into magick)
237            // For identify and composite, use 'magick <subcommand>'
238            if ($command === self::IMAGEMAGICK_CONVERT) {
239                $magickBin = \Karla\Platform::getBinary(self::IMAGEMAGICK_MAGICK);
240                return $this->binPath . $magickBin;
241            } elseif (in_array($command, [self::IMAGEMAGICK_IDENTIFY, self::IMAGEMAGICK_COMPOSITE])) {
242                $magickBin = \Karla\Platform::getBinary(self::IMAGEMAGICK_MAGICK);
243                return $this->binPath . $magickBin . ' ' . $command;
244            }
245        }
246
247        return $this->binPath . $this->bin;
248    }
249
250    /**
251     * Execute the command
252     *
253     * @param bool $reset Reset the query
254     */
255    public function execute(bool $reset = true): string|object
256    {
257        $result = shell_exec($this->getCommand());
258        if ($reset) {
259            $this->getQuery()->reset();
260        }
261
262        return $result !== null && $result !== false ? $result : '';
263    }
264
265    /**
266     * Raw arguments directly to ImageMagick
267     *
268     * @param string $arguments Arguments
269     * @param bool $input Defaults to an input option, use false to use it as an output option
270     */
271    public function raw(string $arguments, bool $input = true): self
272    {
273        if ($input) {
274            $this->getQuery()->setInputOption($arguments);
275        } else {
276            $this->getQuery()->setOutputOption($arguments);
277        }
278        return $this;
279    }
280
281    /**
282     * Check if the input is a valid ImageMagick program
283     *
284     * @param string $program Program name
285     */
286    final public static function validProgram(string $program): bool
287    {
288        $class = new \ReflectionClass(__CLASS__);
289        $constants = $class->getConstants();
290        foreach ($constants as $constant) {
291            if ($constant == $program) {
292                return true;
293            }
294        }
295
296        return false;
297    }
298}