Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
59.46% |
22 / 37 |
|
25.00% |
1 / 4 |
CRAP | |
0.00% |
0 / 1 |
| JpegQualityDetector | |
59.46% |
22 / 37 |
|
25.00% |
1 / 4 |
71.04 | |
0.00% |
0 / 1 |
| detectQualityOfJpgUsingImagick | |
20.00% |
2 / 10 |
|
0.00% |
0 / 1 |
32.09 | |||
| detectQualityOfJpgUsingImageMagick | |
75.00% |
6 / 8 |
|
0.00% |
0 / 1 |
7.77 | |||
| detectQualityOfJpgUsingGraphicsMagick | |
54.55% |
6 / 11 |
|
0.00% |
0 / 1 |
14.01 | |||
| detectQualityOfJpg | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
4 | |||
| 1 | <?php |
| 2 | |
| 3 | namespace WebPConvert\Convert\Helpers; |
| 4 | |
| 5 | use ExecWithFallback\ExecWithFallback; |
| 6 | |
| 7 | /** |
| 8 | * Try to detect quality of a jpeg image using various tools. |
| 9 | * |
| 10 | * @package WebPConvert |
| 11 | * @author Bjørn Rosell <it@rosell.dk> |
| 12 | * @since Class available since Release 2.0.0 |
| 13 | */ |
| 14 | class JpegQualityDetector |
| 15 | { |
| 16 | |
| 17 | /** |
| 18 | * Try to detect quality of jpeg using imagick extension. |
| 19 | * |
| 20 | * Note that the detection might fail for two different reasons: |
| 21 | * 1) Imagick is not installed |
| 22 | * 2) Imagick for some reason fails to detect quality for some images |
| 23 | * |
| 24 | * In both cases, null is returned. |
| 25 | * |
| 26 | * @param string $filename A complete file path to file to be examined |
| 27 | * @return int|null Quality, or null if it was not possible to detect quality |
| 28 | */ |
| 29 | private static function detectQualityOfJpgUsingImagick($filename) |
| 30 | { |
| 31 | if (extension_loaded('imagick') && class_exists('\\Imagick')) { |
| 32 | try { |
| 33 | $img = new \Imagick($filename); |
| 34 | |
| 35 | // The required function is available as from PECL imagick v2.2.2 |
| 36 | if (method_exists($img, 'getImageCompressionQuality')) { |
| 37 | $quality = $img->getImageCompressionQuality(); |
| 38 | if ($quality === 0) { |
| 39 | // We have experienced that this Imagick method returns 0 for some images, |
| 40 | // (even though the imagemagick binary is able to detect the quality) |
| 41 | // ie "/test/images/quality-undetectable-with-imagick.jpg". See #208 |
| 42 | $quality = null; |
| 43 | } |
| 44 | return $quality; |
| 45 | } |
| 46 | } catch (\Exception $e) { |
| 47 | // Well well, it just didn't work out. |
| 48 | // - But perhaps next method will work... |
| 49 | } catch (\Throwable $e) { |
| 50 | } |
| 51 | } |
| 52 | return null; |
| 53 | } |
| 54 | |
| 55 | |
| 56 | /** |
| 57 | * Try to detect quality of jpeg using imagick binary. |
| 58 | * |
| 59 | * Note that the detection might fail for three different reasons: |
| 60 | * 1) exec function is not available |
| 61 | * 2) the 'identify' command is not available on the system |
| 62 | * 3) imagemagick for some reason fails to detect quality for some images |
| 63 | * |
| 64 | * In the first two cases, null is returned. |
| 65 | * In the third case, 92 is returned. This is what imagemagick returns when it cannot detect the quality. |
| 66 | * and unfortunately we cannot distinguish between the situation where the quality is undetectable |
| 67 | * and the situation where the quality is actually 92 (at least, I have not found a way to do so) |
| 68 | * |
| 69 | * @param string $filename A complete file path to file to be examined |
| 70 | * @return int|null Quality, or null if it was not possible to detect quality |
| 71 | */ |
| 72 | private static function detectQualityOfJpgUsingImageMagick($filename) |
| 73 | { |
| 74 | if (ExecWithFallback::anyAvailable()) { |
| 75 | // Try Imagick using exec, and routing stderr to stdout (the "2>$1" magic) |
| 76 | |
| 77 | try { |
| 78 | ExecWithFallback::exec( |
| 79 | "identify -format '%Q' " . escapeshellarg($filename) . " 2>&1", |
| 80 | $output, |
| 81 | $returnCode |
| 82 | ); |
| 83 | //echo 'out:' . print_r($output, true); |
| 84 | if ((intval($returnCode) == 0) && (is_array($output)) && (count($output) == 1)) { |
| 85 | return intval($output[0]); |
| 86 | } |
| 87 | } catch (\Exception $e) { |
| 88 | // its ok, there are other fish in the sea |
| 89 | } catch (\Throwable $e) { |
| 90 | } |
| 91 | } |
| 92 | return null; |
| 93 | } |
| 94 | |
| 95 | |
| 96 | /** |
| 97 | * Try to detect quality of jpeg using graphicsmagick binary. |
| 98 | * |
| 99 | * It seems that graphicsmagick is never able to detect the quality! - and always returns |
| 100 | * the default quality, which is 75. |
| 101 | * However, as this might be solved in future versions, the method might be useful one day. |
| 102 | * But we treat "75" as a failure to detect and shall return null in that case. |
| 103 | * |
| 104 | * @param string $filename A complete file path to file to be examined |
| 105 | * @return int|null Quality, or null if it was not possible to detect quality |
| 106 | */ |
| 107 | private static function detectQualityOfJpgUsingGraphicsMagick($filename) |
| 108 | { |
| 109 | if (ExecWithFallback::anyAvailable()) { |
| 110 | // Try GraphicsMagick |
| 111 | try { |
| 112 | ExecWithFallback::exec( |
| 113 | "gm identify -format '%Q' " . escapeshellarg($filename) . " 2>&1", |
| 114 | $output, |
| 115 | $returnCode |
| 116 | ); |
| 117 | if ((intval($returnCode) == 0) && (is_array($output)) && (count($output) == 1)) { |
| 118 | $quality = intval($output[0]); |
| 119 | |
| 120 | // It seems that graphicsmagick is (currently) never able to detect the quality! |
| 121 | // - and always returns 75 as a fallback |
| 122 | // We shall therefore treat 75 as a failure to detect. (#209) |
| 123 | if ($quality == 75) { |
| 124 | return null; |
| 125 | } |
| 126 | return $quality; |
| 127 | } |
| 128 | } catch (\Exception $e) { |
| 129 | } catch (\Throwable $e) { |
| 130 | } |
| 131 | } |
| 132 | return null; |
| 133 | } |
| 134 | |
| 135 | |
| 136 | /** |
| 137 | * Try to detect quality of jpeg. |
| 138 | * |
| 139 | * Note: This method does not throw errors, but might dispatch warnings. |
| 140 | * You can use the WarningsIntoExceptions class if it is critical to you that nothing gets "printed" |
| 141 | * |
| 142 | * @param string $filename A complete file path to file to be examined |
| 143 | * @return int|null Quality, or null if it was not possible to detect quality |
| 144 | */ |
| 145 | public static function detectQualityOfJpg($filename) |
| 146 | { |
| 147 | |
| 148 | //trigger_error('warning test', E_USER_WARNING); |
| 149 | |
| 150 | // Test that file exists in order not to break things. |
| 151 | if (!file_exists($filename)) { |
| 152 | // One could argue that it would be better to throw an Exception...? |
| 153 | return null; |
| 154 | } |
| 155 | |
| 156 | // Try Imagick extension, if available |
| 157 | $quality = self::detectQualityOfJpgUsingImagick($filename); |
| 158 | |
| 159 | if (is_null($quality)) { |
| 160 | $quality = self::detectQualityOfJpgUsingImageMagick($filename); |
| 161 | } |
| 162 | |
| 163 | if (is_null($quality)) { |
| 164 | $quality = self::detectQualityOfJpgUsingGraphicsMagick($filename); |
| 165 | } |
| 166 | |
| 167 | return $quality; |
| 168 | } |
| 169 | } |