Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
78.95% covered (warning)
78.95%
60 / 76
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
Support
78.95% covered (warning)
78.95%
60 / 76
0.00% covered (danger)
0.00%
0 / 6
65.74
0.00% covered (danger)
0.00%
0 / 1
 getListBinary
25.00% covered (danger)
25.00%
3 / 12
0.00% covered (danger)
0.00%
0 / 1
21.19
 gravity
80.00% covered (warning)
80.00%
12 / 15
0.00% covered (danger)
0.00%
0 / 1
10.80
 imageTypes
91.67% covered (success)
91.67%
11 / 12
0.00% covered (danger)
0.00%
0 / 1
7.03
 colorSpace
91.67% covered (success)
91.67%
11 / 12
0.00% covered (danger)
0.00%
0 / 1
7.03
 layerMethod
90.91% covered (success)
90.91%
10 / 11
0.00% covered (danger)
0.00%
0 / 1
7.04
 supportedFormat
92.86% covered (success)
92.86%
13 / 14
0.00% covered (danger)
0.00%
0 / 1
9.03
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    2013-05-26
13 */
14
15declare(strict_types=1);
16
17namespace Karla;
18
19use Karla\Program;
20use Karla\Program\Identify;
21use Karla\Program\Convert;
22use Karla\Program\ImageMagick;
23use Karla\Program\Composite;
24
25/**
26 * Class for querying for supported features
27 *
28 * @category Utility
29 * @author   Johannes Skov Frandsen <jsf@greenoak.dk>
30 * @license  http://www.opensource.org/licenses/mit-license.php MIT
31 * @link     https://github.com/localgod/karla Karla
32 */
33class Support
34{
35    /**
36     * Get the appropriate binary for -list commands.
37     * For ImageMagick 7, use 'magick'.
38     * For ImageMagick 6, use 'convert' or 'identify' (Composite doesn't support -list).
39     *
40     * @param Program $program Program instance to extract binary path from
41     */
42    private static function getListBinary(Program $program): string
43    {
44        $binary = $program->getBinary();
45
46        // For Composite programs in IM6, we need to use 'convert' instead
47        // because 'composite' doesn't support -list commands
48        if ($program instanceof Composite) {
49            // If binary contains 'magick', it's IM7 - use as-is
50            if (strpos($binary, 'magick') !== false) {
51                return $binary;
52            }
53
54            // IM6 - replace composite with convert
55            // Get the directory and construct convert path
56            $dirPath = dirname($binary);
57            $isWindows = DIRECTORY_SEPARATOR === '\\';
58            $convertBin = $isWindows ? 'convert.exe' : 'convert';
59
60            $result = $dirPath . DIRECTORY_SEPARATOR . $convertBin;
61
62            // If convert doesn't exist, try using the original binary anyway
63            // (it might work in some configurations)
64            if (!file_exists($result) && !is_executable($result)) {
65                return $binary;
66            }
67
68            return $result;
69        }
70
71        // For Convert and Identify, use their binary as-is (they support -list)
72        return $binary;
73    }
74
75    /**
76     * Check if a gravity is supported by ImageMagick.
77     *
78     * @param Program $program Program to check
79     * @param string $gravity Gravity to check
80     *
81     * @throws \BadMethodCallException if called in a wrong context
82     */
83    public static function gravity(Program $program, string $gravity): bool
84    {
85        if (! ($program instanceof Convert) && ! ($program instanceof Composite)) {
86            $message = 'This method can not be used in this context. (' . get_class($program) . ')';
87            throw new \BadMethodCallException($message);
88        }
89
90        // Use the appropriate binary for -list commands
91        // Redirect stderr to stdout to capture all output
92        $command = self::getListBinary($program) . ' -list gravity 2>&1';
93
94        $gravities = shell_exec($command);
95
96        // If command fails, try without stderr redirect as fallback
97        if ($gravities === null || $gravities === false || trim($gravities) === '') {
98            $command = self::getListBinary($program) . ' -list gravity';
99            $gravities = shell_exec($command);
100        }
101
102        if ($gravities === null || $gravities === false || trim($gravities) === '') {
103            return false;
104        }
105
106        $gravities = explode("\n", $gravities);
107        $count = count($gravities);
108        for ($i = 0; $i < $count; $i++) {
109            $gravities[$i] = trim(strtolower($gravities[$i]));
110        }
111
112        return in_array(strtolower(trim($gravity)), $gravities);
113    }
114
115    /**
116     * Check if an image type is supported by the ImageMagick program.
117     *
118     * @param Program $program Program to check
119     * @param string $type Type to check
120     */
121    public static function imageTypes(Program $program, string $type): bool
122    {
123        if (! ($program instanceof Convert) && ! ($program instanceof Identify)) {
124            $message = 'This method can not be used in this context. (' . get_class($program) . ')';
125            throw new \BadMethodCallException($message);
126        }
127
128        // Use the appropriate binary for -list commands
129        // Redirect stderr to stdout to capture all output
130        $command = self::getListBinary($program) . ' -list type 2>&1';
131
132        $types = shell_exec($command);
133        if ($types === null || $types === false || trim($types) === '') {
134            return false;
135        }
136
137        $types = explode("\n", $types);
138        $count = count($types);
139        for ($i = 0; $i < $count; $i++) {
140            $types[$i] = trim(strtolower($types[$i]));
141        }
142
143        return in_array(strtolower(trim($type)), $types);
144    }
145
146    /**
147     * Check if a colorspace is supported by the ImageMagick program.
148     *
149     * @param Program $program Program to check
150     * @param string $colorSpace Colorspace to check
151     */
152    public static function colorSpace(Program $program, string $colorSpace): bool
153    {
154        if (! ($program instanceof Convert) && ! ($program instanceof Identify)) {
155            $message = 'This method can not be used in this context. (' . get_class($program) . ')';
156            throw new \BadMethodCallException($message);
157        }
158
159        // Use the appropriate binary for -list commands
160        // Redirect stderr to stdout to capture all output
161        $command = self::getListBinary($program) . ' -list colorspace 2>&1';
162
163        $colorspaces = shell_exec($command);
164        if ($colorspaces === null || $colorspaces === false || trim($colorspaces) === '') {
165            // Command failed, return false
166            return false;
167        }
168
169        $colorspaces = explode("\n", $colorspaces);
170        $count = count($colorspaces);
171        for ($i = 0; $i < $count; $i++) {
172            $colorspaces[$i] = trim(strtolower($colorspaces[$i]));
173        }
174
175        return in_array(strtolower(trim($colorSpace)), $colorspaces);
176    }
177
178    /**
179     * Check if a method is supported by ImageMagick.
180     *
181     * @param Program $program Program to check
182     * @param string $method Method to check
183     *
184     * @throws \BadMethodCallException if called in a wrong context
185     */
186    public static function layerMethod(Program $program, string $method): bool
187    {
188        if (! ($program instanceof Convert) && ! ($program instanceof Identify)) {
189            throw new \BadMethodCallException('This method can not be used in this context');
190        }
191
192        // Use the appropriate binary for -list commands
193        // Redirect stderr to stdout to capture all output
194        $command = self::getListBinary($program) . ' -list layers 2>&1';
195
196        $methods = shell_exec($command);
197        if ($methods === null || $methods === false || trim($methods) === '') {
198            return false;
199        }
200
201        $methods = explode("\n", $methods);
202        $count = count($methods);
203        for ($i = 0; $i < $count; $i++) {
204            $methods[$i] = trim(strtolower($methods[$i]));
205        }
206
207        return in_array(strtolower(trim($method)), $methods);
208    }
209
210    /**
211     * Check if a format is supported by ImageMagick.
212     *
213     * @param Program $program Program to check
214     * @param string $format Format to check
215     *
216     * @throws \BadMethodCallException if called in a wrong context
217     */
218    public static function supportedFormat(Program $program, string $format): bool
219    {
220        if (! ($program instanceof Convert) && ! ($program instanceof Identify)) {
221            throw new \BadMethodCallException('This method can not be used in this context');
222        }
223
224        // Use the appropriate binary for -list commands
225        // Redirect stderr to stdout to capture all output
226        $command = self::getListBinary($program) . ' -list format 2>&1';
227
228        $formats = shell_exec($command);
229        if ($formats === null || $formats === false || trim($formats) === '') {
230            return false;
231        }
232
233        $formats = explode("\n", $formats);
234        $count = count($formats);
235        for ($i = 0; $i < $count; $i++) {
236            $matches = [];
237            preg_match("/^[\s]*[A-Z0-9]+/", $formats[$i], $matches);
238            if (isset($matches[0]) && ! strpos($matches[0], 'Format')) {
239                $formats[$i] = strtolower(trim($matches[0]));
240            }
241        }
242
243        return in_array(strtolower(trim($format)), $formats);
244    }
245}