Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 75
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
Support
0.00% covered (danger)
0.00%
0 / 75
0.00% covered (danger)
0.00%
0 / 6
2070
0.00% covered (danger)
0.00%
0 / 1
 getListBinary
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
30
 gravity
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
110
 imageTypes
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
56
 colorSpace
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
56
 layerMethod
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
56
 supportedFormat
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
90
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\Platform;
20use Karla\Program;
21use Karla\Program\Identify;
22use Karla\Program\Convert;
23use Karla\Program\ImageMagick;
24use Karla\Program\Composite;
25
26/**
27 * Class for querying for supported features
28 *
29 * @category Utility
30 * @author   Johannes Skov Frandsen <jsf@greenoak.dk>
31 * @license  http://www.opensource.org/licenses/mit-license.php MIT
32 * @link     https://github.com/localgod/karla Karla
33 */
34class Support
35{
36    /**
37     * Get the appropriate binary for -list commands.
38     * For ImageMagick 7, use 'magick'.
39     * For ImageMagick 6, use 'convert' or 'identify' (Composite doesn't support -list).
40     *
41     * @param Program $program Program instance to extract binary path from
42     */
43    private static function getListBinary(Program $program): string
44    {
45        $binary = $program->getBinary();
46
47        // For Composite programs in IM6, we need to use 'convert' instead
48        // because 'composite' doesn't support -list commands
49        if ($program instanceof Composite) {
50            // If binary contains 'magick', it's IM7 - use as-is
51            if (strpos($binary, 'magick') !== false) {
52                return $binary;
53            }
54
55            // IM6 - replace composite with convert
56            // Get the directory and construct convert path
57            $dirPath = dirname($binary);
58            $convertBin = Platform::getBinary('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}