diff --git a/src/Driver/Info.php b/src/Driver/Info.php new file mode 100644 index 000000000..32a56bf22 --- /dev/null +++ b/src/Driver/Info.php @@ -0,0 +1,186 @@ +.., if TRUE the result will be the raw version + */ + public function getDriverVersion($raw = false); + + /** + * Get the version of the library used by the driver. + * For example: + * - for GD: it's the version of libgd + * - for gmagick: it's the version of the GraphicsMagick + * - for imagick: it's the version of the ImageMagick. + * + * @param bool $raw if false the result will be in the format .., if TRUE the result will be the raw version + */ + public function getEngineVersion($raw = false); + + /** + * Check if the driver the features requested. + * + * @param int $features A combination of one or more of the FEATURE_... values + * + * @return bool returns TRUE if the driver supports all the specified features, FALSE otherwise + */ + public function hasFeature($features); + + /** + * Check if the driver has the features requested. + * + * @param int $features A combination of one or more of the FEATURE_... values + * + * @throws \Imagine\Exception\NotSupportedException if any of the requested features is not supported + */ + public function requireFeature($features); + + /** + * Get the list of supported file formats. + * + * @return \Imagine\Image\FormatList + */ + public function getSupportedFormats(); + + /** + * Check if a format is supported. + * + * @param \Imagine\Image\Format|string $format + * + * @return bool + */ + public function isFormatSupported($format); + + /** + * Check if a palette is supported. + * + * @param \Imagine\Image\Palette\PaletteInterface $palette + * + * @throws \Imagine\Exception\NotSupportedException if the palette is not supported + */ + public function checkPaletteSupport(PaletteInterface $palette); + + /** + * Check if a palette is supported. + * + * @param \Imagine\Image\Palette\PaletteInterface $palette + * + * @return bool + */ + public function isPaletteSupported(PaletteInterface $palette); +} diff --git a/src/Driver/InfoProvider.php b/src/Driver/InfoProvider.php new file mode 100644 index 000000000..479227e83 --- /dev/null +++ b/src/Driver/InfoProvider.php @@ -0,0 +1,20 @@ +loadGdInfo(); $this->resource = $resource; } + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + * @since 1.3.0 + */ + public static function getDriverInfo($required = true) + { + return DriverInfo::get($required); + } + /** * {@inheritdoc} * @@ -359,10 +365,7 @@ public function polygon(array $coordinates, ColorInterface $color, $fill = false */ public function text($string, AbstractFont $font, PointInterface $position, $angle = 0, $width = null) { - if (!$this->info['FreeType Support']) { - throw new RuntimeException('GD is not compiled with FreeType support'); - } - + static::getDriverInfo()->requireFeature(DriverInfo::FEATURE_TEXTFUNCTIONS); $angle = -1 * $angle; $fontsize = $font->getSize(); $fontfile = $font->getFile(); @@ -454,15 +457,6 @@ private function getColor(ColorInterface $color) return $gdColor; } - private function loadGdInfo() - { - if (!function_exists('gd_info')) { - throw new RuntimeException('Gd not installed'); - } - - $this->info = gd_info(); - } - /** * Apply the alpha blending value. * diff --git a/src/Gd/DriverInfo.php b/src/Gd/DriverInfo.php new file mode 100644 index 000000000..f8799e1f2 --- /dev/null +++ b/src/Gd/DriverInfo.php @@ -0,0 +1,226 @@ +driverRawVersion = PHP_VERSION; + $this->driverSemverVersion = defined('PHP_MAJOR_VERSION') ? implode('.', array(PHP_MAJOR_VERSION, PHP_MINOR_VERSION, PHP_RELEASE_VERSION)) : ''; + $this->engineRawVersion = is_string($gdVersion) ? $gdVersion : ''; + $this->engineSemverVersion = preg_match('/^.*?(\d+\.\d+\.\d+)/', $this->engineRawVersion, $m) ? $m[1] : ''; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::get() + */ + public static function get($required = true) + { + if (self::$instance === false) { + if (function_exists('gd_info') && defined('GD_VERSION')) { + self::$instance = new static(GD_VERSION); + } else { + return self::$instance = null; + } + } + if (self::$instance === null && $required) { + throw new NotSupportedException('Gd not installed'); + } + + return self::$instance; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::checkVersionIsSupported() + */ + public function checkVersionIsSupported() + { + if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 50300) { + throw new NotSupportedException('Imagine requires PHP 5.3 or later'); + } + if ($this->getEngineVersion() === '' || version_compare($this->getEngineVersion(), '2.0.1') < 0) { + throw new NotSupportedException(sprintf('GD2 version %s or higher is required, %s provided', '2.0.1', GD_VERSION)); + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::getDriverVersion() + */ + public function getDriverVersion($raw = false) + { + return $raw ? $this->driverRawVersion : $this->driverSemverVersion; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::getEngineVersion() + */ + public function getEngineVersion($raw = false) + { + return $raw ? $this->engineRawVersion : $this->engineSemverVersion; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::requireFeature() + */ + public function requireFeature($features) + { + $features = (int) $features; + if ($features & static::FEATURE_COLORPROFILES) { + throw new NotSupportedException('GD driver does not support color profiles'); + } + if ($features & static::FEATURE_TEXTFUNCTIONS) { + if (!function_exists('imageftbbox')) { + throw new NotSupportedException('GD is not compiled with FreeType support'); + } + } + if ($features & static::FEATURE_MULTIPLELAYERS) { + throw new NotSupportedException('GD does not support layer sets'); + } + if ($features & static::FEATURE_CUSTOMRESOLUTION) { + throw new NotSupportedException('GD does not support setting custom resolutions'); + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::hasFeature() + */ + public function hasFeature($features) + { + try { + $this->requireFeature($features); + } catch (NotSupportedException $x) { + return false; + } + + return true; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::getSupportedFormats() + */ + public function getSupportedFormats() + { + if ($this->supportedFormats !== null) { + return $this->supportedFormats; + } + $supportedFormats = array(); + foreach (array( + 'gif' => Format::ID_GIF, + 'jpeg' => Format::ID_JPEG, + 'png' => Format::ID_PNG, + 'wbmp' => Format::ID_WBMP, + 'xbm' => Format::ID_XBM, + 'bmp' => Format::ID_BMP, + 'webp' => Format::ID_WEBP, + 'avif' => Format::ID_AVIF, + ) as $suffix => $formatID) { + if (function_exists("image{$suffix}") && function_exists("imagecreatefrom{$suffix}")) { + $supportedFormats[] = Format::get($formatID); + } + } + $this->supportedFormats = new FormatList($supportedFormats); + + return $this->supportedFormats; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::isFormatSupported() + */ + public function isFormatSupported($format) + { + return $this->getSupportedFormats()->find($format) !== null; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::checkPaletteSupport() + */ + public function checkPaletteSupport(PaletteInterface $palette) + { + if (!($palette instanceof RGB)) { + throw new NotSupportedException('GD driver only supports RGB colors'); + } + + return true; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::isPaletteSupported() + */ + public function isPaletteSupported(PaletteInterface $palette) + { + try { + $this->checkPaletteSupport($palette); + } catch (NotSupportedException $x) { + return false; + } + + return true; + } +} diff --git a/src/Gd/Effects.php b/src/Gd/Effects.php index 408d16b95..716322d17 100644 --- a/src/Gd/Effects.php +++ b/src/Gd/Effects.php @@ -11,6 +11,7 @@ namespace Imagine\Gd; +use Imagine\Driver\InfoProvider; use Imagine\Effects\EffectsInterface; use Imagine\Exception\InvalidArgumentException; use Imagine\Exception\RuntimeException; @@ -21,7 +22,7 @@ /** * Effects implementation using the GD PHP extension. */ -class Effects implements EffectsInterface +class Effects implements EffectsInterface, InfoProvider { /** * @var resource|\GdImage @@ -38,6 +39,17 @@ public function __construct($resource) $this->resource = $resource; } + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + * @since 1.3.0 + */ + public static function getDriverInfo($required = true) + { + return DriverInfo::get($required); + } + /** * {@inheritdoc} * diff --git a/src/Gd/Font.php b/src/Gd/Font.php index d5e395f2d..840ba8bed 100644 --- a/src/Gd/Font.php +++ b/src/Gd/Font.php @@ -11,14 +11,25 @@ namespace Imagine\Gd; -use Imagine\Exception\RuntimeException; +use Imagine\Driver\InfoProvider; use Imagine\Image\AbstractFont; /** * Font implementation using the GD library. */ -final class Font extends AbstractFont +final class Font extends AbstractFont implements InfoProvider { + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + * @since 1.3.0 + */ + public static function getDriverInfo($required = true) + { + return DriverInfo::get($required); + } + /** * {@inheritdoc} * @@ -26,9 +37,7 @@ final class Font extends AbstractFont */ public function box($string, $angle = 0) { - if (!function_exists('imageftbbox')) { - throw new RuntimeException('GD must have been compiled with `--with-freetype-dir` option to use the Font feature.'); - } + static::getDriverInfo()->requireFeature(DriverInfo::FEATURE_TEXTFUNCTIONS); $fontfile = $this->file; if ($fontfile && DIRECTORY_SEPARATOR === '\\') { // On Windows imageftbbox() throws a "Could not find/open font" error if $fontfile is not an absolute path. diff --git a/src/Gd/Image.php b/src/Gd/Image.php index 80563cc5d..4fa360c14 100644 --- a/src/Gd/Image.php +++ b/src/Gd/Image.php @@ -11,6 +11,7 @@ namespace Imagine\Gd; +use Imagine\Driver\InfoProvider; use Imagine\Exception\InvalidArgumentException; use Imagine\Exception\OutOfBoundsException; use Imagine\Exception\RuntimeException; @@ -18,12 +19,12 @@ use Imagine\Image\AbstractImage; use Imagine\Image\BoxInterface; use Imagine\Image\Fill\FillInterface; +use Imagine\Image\Format; use Imagine\Image\ImageInterface; use Imagine\Image\Metadata\MetadataBag; use Imagine\Image\Palette\Color\ColorInterface; use Imagine\Image\Palette\Color\RGB as RGBColor; use Imagine\Image\Palette\PaletteInterface; -use Imagine\Image\Palette\RGB; use Imagine\Image\Point; use Imagine\Image\PointInterface; use Imagine\Image\ProfileInterface; @@ -32,7 +33,7 @@ /** * Image implementation using the GD library. */ -final class Image extends AbstractImage +final class Image extends AbstractImage implements InfoProvider { /** * @var resource|\GdImage @@ -68,8 +69,11 @@ public function __construct($resource, PaletteInterface $palette, MetadataBag $m */ public function __destruct() { - if (is_resource($this->resource) && get_resource_type($this->resource) === 'gd') { - imagedestroy($this->resource); + if ($this->resource) { + if (is_resource($this->resource) && get_resource_type($this->resource) === 'gd' || $this->resource instanceof \GdImage) { + imagedestroy($this->resource); + } + $this->resource = null; } } @@ -94,10 +98,21 @@ public function __clone() } } + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + * @since 1.3.0 + */ + public static function getDriverInfo($required = true) + { + return DriverInfo::get($required); + } + /** * Returns Gd resource. * - * @return resource + * @return resource|\GdImage */ public function getGdResource() { @@ -263,8 +278,15 @@ final public function save($path = null, array $options = array()) $originalPath = isset($this->metadata['filepath']) ? $this->metadata['filepath'] : null; $format = pathinfo($originalPath, \PATHINFO_EXTENSION); } - - $this->saveOrOutput($format, $options, $path); + $formatInfo = static::getDriverInfo()->getSupportedFormats()->find($format); + if ($formatInfo === null) { + throw new InvalidArgumentException(sprintf( + 'Saving image in "%s" format is not supported, please use one of the following extensions: "%s"', + $format, + implode('", "', static::getDriverInfo()->getSupportedFormats()->getAllIDs()) + )); + } + $this->saveOrOutput($formatInfo, $options, $path); return $this; } @@ -276,9 +298,16 @@ final public function save($path = null, array $options = array()) */ public function show($format, array $options = array()) { - header('Content-type: ' . $this->getMimeType($format)); - - $this->saveOrOutput($format, $options); + $formatInfo = static::getDriverInfo()->getSupportedFormats()->find($format); + if ($formatInfo === null) { + throw new InvalidArgumentException(sprintf( + 'Displaying an image in "%s" format is not supported, please use one of the following formats: "%s"', + $format, + implode('", "', static::getDriverInfo()->getSupportedFormats()->getAllIDs()) + )); + } + header('Content-type: ' . $formatInfo->getMimeType()); + $this->saveOrOutput($formatInfo, $options); return $this; } @@ -290,8 +319,16 @@ public function show($format, array $options = array()) */ public function get($format, array $options = array()) { + $formatInfo = static::getDriverInfo()->getSupportedFormats()->find($format); + if ($formatInfo === null) { + throw new InvalidArgumentException(sprintf( + 'Creating an image in "%s" format is not supported, please use one of the following formats: "%s"', + $format, + implode('", "', static::getDriverInfo()->getSupportedFormats()->getAllIDs()) + )); + } ob_start(); - $this->saveOrOutput($format, $options); + $this->saveOrOutput($formatInfo, $options); return ob_get_clean(); } @@ -303,7 +340,7 @@ public function get($format, array $options = array()) */ public function __toString() { - return $this->get('png'); + return $this->get(Format::ID_PNG); } /** @@ -567,7 +604,7 @@ public function palette() */ public function profile(ProfileInterface $profile) { - throw new RuntimeException('GD driver does not support color profiles'); + static::getDriverInfo()->requireFeature(DriverInfo::FEATURE_COLORPROFILES); } /** @@ -577,10 +614,12 @@ public function profile(ProfileInterface $profile) */ public function usePalette(PaletteInterface $palette) { - if (!$palette instanceof RGB) { - throw new RuntimeException('GD driver only supports RGB palette'); + if ($this->palette->name() === $palette->name()) { + return $this; } + static::getDriverInfo()->checkPaletteSupport($palette); + $this->palette = $palette; return $this; @@ -589,51 +628,49 @@ public function usePalette(PaletteInterface $palette) /** * Performs save or show operation using one of GD's image... functions. * - * @param string $format + * @param \Imagine\Image\Format $format * @param array $options * @param string $filename * * @throws \Imagine\Exception\InvalidArgumentException * @throws \Imagine\Exception\RuntimeException */ - private function saveOrOutput($format, array $options, $filename = null) + private function saveOrOutput(Format $format, array $options, $filename = null) { - $format = $this->normalizeFormat($format); - - if (!$this->supported($format)) { - throw new InvalidArgumentException(sprintf('Saving image in "%s" format is not supported, please use one of the following extensions: "%s"', $format, implode('", "', $this->supported()))); + switch ($format->getID()) { + default: + $saveFunction = 'image' . $format->getID(); + break; } - - $save = 'image' . $format; $args = array(&$this->resource, $filename); - switch ($format) { - case 'avif': + switch ($format->getID()) { + case Format::ID_AVIF: // ranges from 0 (worst quality, smaller file) to 100 (best quality, larger file). If -1 is provided, the default value is used $quality = -1; // ranges from 0 (slow, smaller file) to 10 (fast, larger file). If -1 is provided, the default value is used $speed = -1; - if (!empty($options[$format . '_lossless'])) { + if (!empty($options['avif_lossless'])) { $quality = 100; } else { - if (!isset($options[$format . '_quality'])) { + if (!isset($options['avif_quality'])) { if (isset($options['quality'])) { - $options[$format . '_quality'] = $options['quality']; + $options['avif_quality'] = $options['quality']; } } - if (isset($options[$format . '_quality'])) { - $quality = max(0, min(100, $options[$format . '_quality'])); + if (isset($options['avif_quality'])) { + $quality = max(0, min(100, $options['avif_quality'])); } } $args[] = $quality; $args[] = $speed; break; - case 'bmp': + case Format::ID_BMP: if (isset($options['compressed'])) { $args[] = (bool) $options['compressed']; } break; - case 'jpeg': + case Format::ID_JPEG: if (!isset($options['jpeg_quality'])) { if (isset($options['quality'])) { $options['jpeg_quality'] = $options['quality']; @@ -643,7 +680,7 @@ private function saveOrOutput($format, array $options, $filename = null) $args[] = $options['jpeg_quality']; } break; - case 'png': + case Format::ID_PNG: if (!isset($options['png_compression_level'])) { if (isset($options['quality'])) { $options['png_compression_level'] = round((100 - $options['quality']) * 9 / 100); @@ -669,13 +706,13 @@ private function saveOrOutput($format, array $options, $filename = null) $args[] = $options['png_compression_filter']; } break; - case 'wbmp': - case 'xbm': + case Format::ID_WBMP: + case Format::ID_XBM: if (isset($options['foreground'])) { $args[] = $options['foreground']; } break; - case 'webp': + case Format::ID_WEBP: if (!isset($options['webp_quality'])) { if (isset($options['quality'])) { $options['webp_quality'] = $options['quality']; @@ -690,8 +727,8 @@ private function saveOrOutput($format, array $options, $filename = null) break; } - ErrorHandling::throwingRuntimeException(E_WARNING | E_NOTICE, function () use ($save, $args) { - if (call_user_func_array($save, $args) === false) { + ErrorHandling::throwingRuntimeException(E_WARNING | E_NOTICE, function () use ($saveFunction, $args) { + if (call_user_func_array($saveFunction, $args) === false) { throw new RuntimeException('Save operation failed'); } }); @@ -705,7 +742,7 @@ private function saveOrOutput($format, array $options, $filename = null) * * @throws \Imagine\Exception\RuntimeException * - * @return resource + * @return resource|\GdImage */ private function createImage(BoxInterface $size, $operation) { @@ -754,90 +791,4 @@ private function getColor(ColorInterface $color) return $index; } - - /** - * Normalizes a given format name. - * - * @param string $format - * - * @return string - */ - private function normalizeFormat($format) - { - $format = strtolower($format); - - if ($format === 'jpg' || $format === 'pjpeg' || $format === 'jfif') { - $format = 'jpeg'; - } - - return $format; - } - - /** - * Checks whether a given format is supported by GD library. - * - * @param string $format - * - * @return bool - */ - private function supported($format = null) - { - $formats = self::getSupportedFormats(); - - if ($format === null) { - return array_keys($formats); - } - - return is_string($format) && isset($formats[$format]); - } - - /** - * Get the mime type based on format. - * - * @param string $format - * - * @throws \Imagine\Exception\RuntimeException - * - * @return string mime-type - */ - private function getMimeType($format) - { - $format = $this->normalizeFormat($format); - $formats = self::getSupportedFormats(); - - if (!isset($formats[$format])) { - throw new RuntimeException('Invalid format'); - } - - return $formats[$format]['mimeType']; - } - - /** - * @return array - */ - private static function getSupportedFormats() - { - static $supportedFormats; - if (!isset($supportedFormats)) { - $supportedFormats = array( - 'gif' => array('mimeType' => 'image/gif'), - 'jpeg' => array('mimeType' => 'image/jpeg'), - 'png' => array('mimeType' => 'image/png'), - 'wbmp' => array('mimeType' => 'image/vnd.wap.wbmp'), - 'xbm' => array('mimeType' => 'image/xbm'), - ); - if (function_exists('imagebmp')) { - $supportedFormats['bmp'] = array('mimeType' => 'image/bmp'); - } - if (function_exists('imagewebp')) { - $supportedFormats['webp'] = array('mimeType' => 'image/webp'); - } - if (function_exists('imageavif') && function_exists('imagecreatefromavif')) { - $supportedFormats['avif'] = array('mimeType' => 'image/avif'); - } - ksort($supportedFormats); - } - - return $supportedFormats; - } } diff --git a/src/Gd/Imagine.php b/src/Gd/Imagine.php index 91273fa91..7736569f5 100644 --- a/src/Gd/Imagine.php +++ b/src/Gd/Imagine.php @@ -11,6 +11,7 @@ namespace Imagine\Gd; +use Imagine\Driver\InfoProvider; use Imagine\Exception\InvalidArgumentException; use Imagine\Exception\RuntimeException; use Imagine\Factory\ClassFactoryInterface; @@ -19,7 +20,6 @@ use Imagine\Image\BoxInterface; use Imagine\Image\Metadata\MetadataBag; use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Image\Palette\Color\RGB as RGBColor; use Imagine\Image\Palette\PaletteInterface; use Imagine\Image\Palette\RGB; use Imagine\Utils\ErrorHandling; @@ -29,14 +29,25 @@ * * @final */ -class Imagine extends AbstractImagine +class Imagine extends AbstractImagine implements InfoProvider { /** * Initialize the class. */ public function __construct() { - $this->requireGdVersion('2.0.1'); + static::getDriverInfo()->checkVersionIsSupported(); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + * @since 1.3.0 + */ + public static function getDriverInfo($required = true) + { + return DriverInfo::get($required); } /** @@ -55,11 +66,12 @@ public function create(BoxInterface $size, ColorInterface $color = null) throw new RuntimeException('Create operation failed'); } - $palette = $color !== null ? $color->getPalette() : new RGB(); - $color = $color ? $color : $palette->color('fff'); - - if (!$color instanceof RGBColor) { - throw new InvalidArgumentException('GD driver only supports RGB colors'); + if ($color === null) { + $palette = new RGB(); + $color = $palette->color('fff'); + } else { + $palette = $color->getPalette(); + static::getDriverInfo()->checkPaletteSupport($palette); } $index = imagecolorallocatealpha($resource, $color->getRed(), $color->getGreen(), $color->getBlue(), round(127 * (100 - $color->getAlpha()) / 100)); @@ -93,7 +105,7 @@ public function open($path) $resource = $this->createImageFromString($data); - if (!$resource instanceof \GdImage && !\is_resource($resource)) { + if (!($resource instanceof \GdImage) && !\is_resource($resource)) { throw new RuntimeException(sprintf('Unable to open image %s', $path)); } @@ -185,21 +197,6 @@ private function wrap($resource, PaletteInterface $palette, MetadataBag $metadat return $this->getClassFactory()->createImage(ClassFactoryInterface::HANDLE_GD, $resource, $palette, $metadata); } - /** - * @param string $version - * - * @throws \Imagine\Exception\RuntimeException - */ - private function requireGdVersion($version) - { - if (!\function_exists('gd_info')) { - throw new RuntimeException('Gd not installed'); - } - if (version_compare(GD_VERSION, $version, '<')) { - throw new RuntimeException(sprintf('GD2 version %s or higher is required, %s provided', $version, GD_VERSION)); - } - } - /** * @param string $string * @param \Imagine\Image\Metadata\MetadataBag $metadata @@ -243,10 +240,10 @@ private function createImageFromString(&$string) return ErrorHandling::ignoring(-1, function () use (&$string) { // imagecreatefromstring() does not support webp images before PHP 7.3.0 if (PHP_VERSION_ID < 70300 && function_exists('imagecreatefromwebp') && $this->isWebP($string)) { - return @imagecreatefromwebp('data:image/webp;base64,' . base64_encode($string)); + return imagecreatefromwebp('data:image/webp;base64,' . base64_encode($string)); } - return @imagecreatefromstring($string); + return imagecreatefromstring($string); }); } } diff --git a/src/Gd/Layers.php b/src/Gd/Layers.php index 8bf28ccc7..79664c1c9 100644 --- a/src/Gd/Layers.php +++ b/src/Gd/Layers.php @@ -11,6 +11,7 @@ namespace Imagine\Gd; +use Imagine\Driver\InfoProvider; use Imagine\Exception\NotSupportedException; use Imagine\Exception\RuntimeException; use Imagine\Factory\ClassFactoryInterface; @@ -18,7 +19,7 @@ use Imagine\Image\Metadata\MetadataBag; use Imagine\Image\Palette\PaletteInterface; -class Layers extends AbstractLayers +class Layers extends AbstractLayers implements InfoProvider { /** * @var \Imagine\Gd\Image @@ -60,6 +61,17 @@ public function __construct(Image $image, PaletteInterface $palette, $resource, $this->palette = $palette; } + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + * @since 1.3.0 + */ + public static function getDriverInfo($required = true) + { + return DriverInfo::get($required); + } + /** * {@inheritdoc} * diff --git a/src/Gmagick/Drawer.php b/src/Gmagick/Drawer.php index d645aac2c..72423f8a6 100644 --- a/src/Gmagick/Drawer.php +++ b/src/Gmagick/Drawer.php @@ -12,6 +12,7 @@ namespace Imagine\Gmagick; use Imagine\Draw\DrawerInterface; +use Imagine\Driver\InfoProvider; use Imagine\Exception\InvalidArgumentException; use Imagine\Exception\RuntimeException; use Imagine\Image\AbstractFont; @@ -24,7 +25,7 @@ /** * Drawer implementation using the Gmagick PHP extension. */ -final class Drawer implements DrawerInterface +final class Drawer implements DrawerInterface, InfoProvider { /** * @var \Gmagick @@ -39,6 +40,17 @@ public function __construct(\Gmagick $gmagick) $this->gmagick = $gmagick; } + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + * @since 1.3.0 + */ + public static function getDriverInfo($required = true) + { + return DriverInfo::get($required); + } + /** * {@inheritdoc} * diff --git a/src/Gmagick/DriverInfo.php b/src/Gmagick/DriverInfo.php new file mode 100644 index 000000000..1db6b4217 --- /dev/null +++ b/src/Gmagick/DriverInfo.php @@ -0,0 +1,246 @@ +driverRawVersion = (string) $driverRawVersion; + $this->driverSemverVersion = preg_match('/^.*?(\d+\.\d+\.\d+)/', $this->driverRawVersion, $m) ? $m[1] : ''; + $this->engineRawVersion = ''; + if (isset($engineRawVersion['versionString']) && is_string($engineRawVersion['versionString'])) { + if (preg_match('/^.*?(\d+\.\d+\.\d+(-\d+)?(\s+Q\d+)?)/i', $engineRawVersion['versionString'], $m)) { + $this->engineRawVersion = $m[1]; + } else { + $this->engineRawVersion = $engineRawVersion['versionString']; + } + } + $this->engineSemverVersion = preg_match('/^.*?(\d+\.\d+\.\d+)/', $this->engineRawVersion, $m) ? $m[1] : ''; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::get() + */ + public static function get($required = true) + { + if (self::$instance === false) { + if (class_exists('Gmagick') && extension_loaded('gmagick')) { + $extensionVersion = phpversion('gmagick'); + $gmagick = new \Gmagick(); + $engineVersion = $gmagick->getversion(); + self::$instance = new static(is_string($extensionVersion) ? $extensionVersion : '', is_array($engineVersion) ? $engineVersion : array()); + } else { + self::$instance = null; + } + } + if (self::$instance === null && $required) { + throw new NotSupportedException('Gmagick not installed'); + } + + return self::$instance; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::checkVersionIsSupported() + */ + public function checkVersionIsSupported() + { + if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 50300) { + throw new NotSupportedException('Imagine requires PHP 5.3 or later'); + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::getDriverVersion() + */ + public function getDriverVersion($raw = false) + { + return $raw ? $this->driverRawVersion : $this->driverSemverVersion; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::getEngineVersion() + */ + public function getEngineVersion($raw = false) + { + return $raw ? $this->engineRawVersion : $this->engineSemverVersion; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::requireFeature() + */ + public function requireFeature($features) + { + $features = (int) $features; + if ($features & static::FEATURE_COALESCELAYERS) { + throw new NotSupportedException('Gmagick does not support coalescing'); + } + if ($features & static::FEATURE_NEGATEIMAGE) { + if (!$this->isMethodAvailale('negateimage')) { + throw new NotSupportedException('Gmagick version 1.1.0 RC3 is required for negative effect'); + } + } + if ($features & static::FEATURE_COLORIZEIMAGE) { + throw new NotSupportedException('Gmagick does not support colorize'); + } + if ($features & static::FEATURE_SHARPENIMAGE) { + throw new NotSupportedException('Gmagick does not support sharpen yet'); + } + if ($features & static::FEATURE_CONVOLVEIMAGE) { + if (!$this->isMethodAvailale('convolveimage')) { + throw new NotSupportedException('The version of Gmagick extension is too old: it does not support convolve (you need gmagick 2.0.1RC2 or later.'); + } + } + if ($features & static::FEATURE_CUSTOMRESOLUTION) { + throw new NotSupportedException('Gmagick does not support setting custom resolutions'); + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::hasFeature() + */ + public function hasFeature($features) + { + try { + $this->requireFeature($features); + } catch (NotSupportedException $x) { + return false; + } + + return true; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::getSupportedFormats() + */ + public function getSupportedFormats() + { + if ($this->supportedFormats !== null) { + return $this->supportedFormats; + } + $supportedFormats = array(); + $gmagick = new \Gmagick(); + $magickFormats = array_map('strtolower', $gmagick->queryFormats()); + foreach (Format::getAll() as $format) { + if (in_array($format->getID(), $magickFormats, true) || array_intersect($magickFormats, $format->getAlternativeIDs()) !== array()) { + $supportedFormats[] = $format; + } + } + $this->supportedFormats = new FormatList($supportedFormats); + + return $this->supportedFormats; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::isFormatSupported() + */ + public function isFormatSupported($format) + { + return $this->getSupportedFormats()->find($format) !== null; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::checkPaletteSupport() + */ + public function checkPaletteSupport(PaletteInterface $palette) + { + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::isPaletteSupported() + */ + public function isPaletteSupported(PaletteInterface $palette) + { + try { + $this->checkPaletteSupport($palette); + } catch (NotSupportedException $x) { + return false; + } + + return true; + } + + /** + * @param string $methodName + * + * @return bool + */ + private function isMethodAvailale($methodName) + { + if (!isset($this->availableMethods[$methodName])) { + $gmagick = new \Gmagick(); + $this->availableMethods[$methodName] = method_exists($gmagick, $methodName); + } + + return $this->availableMethods[$methodName]; + } +} diff --git a/src/Gmagick/Effects.php b/src/Gmagick/Effects.php index d918c5779..e78ce3e9e 100644 --- a/src/Gmagick/Effects.php +++ b/src/Gmagick/Effects.php @@ -11,9 +11,9 @@ namespace Imagine\Gmagick; +use Imagine\Driver\InfoProvider; use Imagine\Effects\EffectsInterface; use Imagine\Exception\InvalidArgumentException; -use Imagine\Exception\NotSupportedException; use Imagine\Exception\RuntimeException; use Imagine\Image\Palette\Color\ColorInterface; use Imagine\Utils\Matrix; @@ -21,7 +21,7 @@ /** * Effects implementation using the Gmagick PHP extension. */ -class Effects implements EffectsInterface +class Effects implements EffectsInterface, InfoProvider { /** * @var \Gmagick @@ -38,6 +38,17 @@ public function __construct(\Gmagick $gmagick) $this->gmagick = $gmagick; } + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + * @since 1.3.0 + */ + public static function getDriverInfo($required = true) + { + return DriverInfo::get($required); + } + /** * {@inheritdoc} * @@ -61,10 +72,7 @@ public function gamma($correction) */ public function negative() { - if (!method_exists($this->gmagick, 'negateimage')) { - throw new NotSupportedException('Gmagick version 1.1.0 RC3 is required for negative effect'); - } - + static::getDriverInfo()->requireFeature(DriverInfo::FEATURE_NEGATEIMAGE); try { $this->gmagick->negateimage(false, \Gmagick::CHANNEL_ALL); } catch (\GmagickException $e) { @@ -82,7 +90,7 @@ public function negative() public function grayscale() { try { - $this->gmagick->setimagetype(2); + $this->gmagick->setimagetype(defined('Gmagick::IMGTYPE_GRAYSCALE') ? \Gmagick::IMGTYPE_GRAYSCALE : 2); } catch (\GmagickException $e) { throw new RuntimeException('Failed to grayscale the image', $e->getCode(), $e); } @@ -97,7 +105,7 @@ public function grayscale() */ public function colorize(ColorInterface $color) { - throw new NotSupportedException('Gmagick does not support colorize'); + static::getDriverInfo()->requireFeature(DriverInfo::FEATURE_COLORIZEIMAGE); } /** @@ -107,7 +115,7 @@ public function colorize(ColorInterface $color) */ public function sharpen() { - throw new NotSupportedException('Gmagick does not support sharpen yet'); + static::getDriverInfo()->requireFeature(DriverInfo::FEATURE_SHARPENIMAGE); } /** @@ -159,10 +167,7 @@ public function brightness($brightness) */ public function convolve(Matrix $matrix) { - if (!method_exists($this->gmagick, 'convolveimage')) { - // convolveimage has been added in gmagick 2.0.1RC2 - throw new NotSupportedException('The version of Gmagick extension is too old: it does not support convolve.'); - } + static::getDriverInfo()->requireFeature(DriverInfo::FEATURE_CONVOLVEIMAGE); if ($matrix->getWidth() !== 3 || $matrix->getHeight() !== 3) { throw new InvalidArgumentException(sprintf('A convolution matrix must be 3x3 (%dx%d provided).', $matrix->getWidth(), $matrix->getHeight())); } diff --git a/src/Gmagick/Font.php b/src/Gmagick/Font.php index d1b121515..4e2a8832d 100644 --- a/src/Gmagick/Font.php +++ b/src/Gmagick/Font.php @@ -11,13 +11,14 @@ namespace Imagine\Gmagick; +use Imagine\Driver\InfoProvider; use Imagine\Image\AbstractFont; use Imagine\Image\Palette\Color\ColorInterface; /** * Font implementation using the Gmagick PHP extension. */ -final class Font extends AbstractFont +final class Font extends AbstractFont implements InfoProvider { /** * @var \Gmagick @@ -37,6 +38,17 @@ public function __construct(\Gmagick $gmagick, $file, $size, ColorInterface $col parent::__construct($file, $size, $color); } + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + * @since 1.3.0 + */ + public static function getDriverInfo($required = true) + { + return DriverInfo::get($required); + } + /** * {@inheritdoc} * diff --git a/src/Gmagick/Image.php b/src/Gmagick/Image.php index 3bbac1a08..b73d9b731 100644 --- a/src/Gmagick/Image.php +++ b/src/Gmagick/Image.php @@ -11,6 +11,7 @@ namespace Imagine\Gmagick; +use Imagine\Driver\InfoProvider; use Imagine\Exception\InvalidArgumentException; use Imagine\Exception\NotSupportedException; use Imagine\Exception\OutOfBoundsException; @@ -30,7 +31,7 @@ /** * Image implementation using the Gmagick PHP extension. */ -final class Image extends AbstractImage +final class Image extends AbstractImage implements InfoProvider { /** * @var \Gmagick @@ -92,6 +93,17 @@ public function __clone() } } + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + * @since 1.3.0 + */ + public static function getDriverInfo($required = true) + { + return DriverInfo::get($required); + } + /** * Returns gmagick instance. * @@ -729,15 +741,15 @@ public function interlace($scheme) */ public function usePalette(PaletteInterface $palette) { + if ($this->palette->name() === $palette->name()) { + return $this; + } + $colorspaceMapping = self::getColorspaceMapping(); if (!isset($colorspaceMapping[$palette->name()])) { throw new InvalidArgumentException(sprintf('The palette %s is not supported by Gmagick driver', $palette->name())); } - if ($this->palette->name() === $palette->name()) { - return $this; - } - try { try { $hasICCProfile = (bool) $this->gmagick->getimageprofile('ICM'); diff --git a/src/Gmagick/Imagine.php b/src/Gmagick/Imagine.php index 2d3aecf93..d1159b13f 100644 --- a/src/Gmagick/Imagine.php +++ b/src/Gmagick/Imagine.php @@ -11,6 +11,7 @@ namespace Imagine\Gmagick; +use Imagine\Driver\InfoProvider; use Imagine\Exception\InvalidArgumentException; use Imagine\Exception\NotSupportedException; use Imagine\Exception\RuntimeException; @@ -30,16 +31,25 @@ * * @final */ -class Imagine extends AbstractImagine +class Imagine extends AbstractImagine implements InfoProvider { /** * @throws \Imagine\Exception\RuntimeException */ public function __construct() { - if (!class_exists('Gmagick')) { - throw new RuntimeException('Gmagick not installed'); - } + static::getDriverInfo()->checkVersionIsSupported(); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + * @since 1.3.0 + */ + public static function getDriverInfo($required = true) + { + return DriverInfo::get($required); } /** diff --git a/src/Gmagick/Layers.php b/src/Gmagick/Layers.php index dda07a743..a651c6ce9 100644 --- a/src/Gmagick/Layers.php +++ b/src/Gmagick/Layers.php @@ -11,16 +11,17 @@ namespace Imagine\Gmagick; +use Imagine\Driver\InfoProvider; use Imagine\Exception\InvalidArgumentException; -use Imagine\Exception\NotSupportedException; use Imagine\Exception\OutOfBoundsException; use Imagine\Exception\RuntimeException; use Imagine\Factory\ClassFactoryInterface; use Imagine\Image\AbstractLayers; +use Imagine\Image\Format; use Imagine\Image\Metadata\MetadataBag; use Imagine\Image\Palette\PaletteInterface; -class Layers extends AbstractLayers +class Layers extends AbstractLayers implements InfoProvider { /** * @var \Imagine\Gmagick\Image @@ -61,6 +62,17 @@ public function __construct(Image $image, PaletteInterface $palette, \Gmagick $r $this->offset = (int) $initialOffset; } + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + * @since 1.3.0 + */ + public static function getDriverInfo($required = true) + { + return DriverInfo::get($required); + } + /** * {@inheritdoc} * @@ -85,7 +97,7 @@ public function merge() */ public function coalesce() { - throw new NotSupportedException('Gmagick does not support coalescing'); + static::getDriverInfo()->requireFeature(DriverInfo::FEATURE_COALESCELAYERS); } /** @@ -95,8 +107,9 @@ public function coalesce() */ public function animate($format, $delay, $loops) { - if (strtolower($format) !== 'gif') { - throw new NotSupportedException('Animated picture is currently only supported on gif'); + $formatInfo = Format::get($format); + if ($formatInfo === null || $formatInfo->getID() !== Format::ID_GIF) { + throw new InvalidArgumentException('Animated picture is currently only supported on gif'); } if (!is_int($loops) || $loops < 0) { diff --git a/src/Image/Format.php b/src/Image/Format.php new file mode 100644 index 000000000..67ec66cc7 --- /dev/null +++ b/src/Image/Format.php @@ -0,0 +1,162 @@ +id = $id; + $this->mimeType = $mimeType; + $this->canonicalFileExtension = $canonicalFileExtension; + $this->alternativeIDs = $alternativeIDs; + } + + /** + * @return string + */ + public function getID() + { + return $this->id; + } + + /** + * @return string + */ + public function getMimeType() + { + return $this->mimeType; + } + + /** + * @return string + */ + public function getCanonicalFileExtension() + { + return $this->canonicalFileExtension; + } + + /** + * @return string[] + */ + public function getAlternativeIDs() + { + return $this->alternativeIDs; + } + + /** + * Get a format given its ID. + * + * @param static|string $format the format (a Format instance of a format ID) + * + * @return static|null + */ + public static function get($format) + { + return static::getList()->find($format); + } + + /** + * @return static[] + */ + public static function getAll() + { + return static::getList()->getAll(); + } + + /** + * @return \Imagine\Image\FormatList + */ + protected static function getList() + { + if (self::$all !== null) { + return self::$all; + } + $class = new ReflectionClass(get_called_class()); + $formats = array(); + foreach ($class->getConstants() as $constantName => $constantValue) { + if (strpos($constantName, 'ID_') === 0) { + $formats[] = static::create($constantValue); + } + } + self::$all = new FormatList($formats); + + return self::$all; + } + + /** + * @param string $formatID + * + * @return static + */ + protected static function create($formatID) + { + switch ($formatID) { + case static::ID_JPEG: + return new static($formatID, 'jpg', 'image/jpeg', array('jpg', 'pjpeg', 'jfif')); + case static::ID_WBMP: + return new static($formatID, 'jpg', 'vnd.wap.wbmp'); + default: + return new static($formatID, $formatID, "image/{$formatID}"); + } + } +} diff --git a/src/Image/FormatList.php b/src/Image/FormatList.php new file mode 100644 index 000000000..d119e7216 --- /dev/null +++ b/src/Image/FormatList.php @@ -0,0 +1,68 @@ +formats = $formats; + } + + /** + * @return \Imagine\Image\Format[] + */ + public function getAll() + { + return $this->formats; + } + + /** + * @return string[] + */ + public function getAllIDs() + { + $result = array(); + foreach ($this->getAll() as $format) { + $result[] = $format->getID(); + } + + return $result; + } + + /** + * Get a format given its ID. + * + * @param \Imagine\Image\Format|string $format the format (a Format instance of a format ID) + * + * @return \Imagine\Image\Format|null + */ + public function find($format) + { + if (is_string($format)) { + $format = strtolower(trim($format)); + if ($format === '') { + return null; + } + foreach ($this->getAll() as $f) { + if ($f->getID() === $format || in_array($format, $f->getAlternativeIDs(), true)) { + return $f; + } + } + + return null; + } + + return in_array($format, $this->getAll(), true) ? $format : null; + } +} diff --git a/src/Imagick/Drawer.php b/src/Imagick/Drawer.php index 5b3356399..e9684b8d1 100644 --- a/src/Imagick/Drawer.php +++ b/src/Imagick/Drawer.php @@ -12,6 +12,7 @@ namespace Imagine\Imagick; use Imagine\Draw\DrawerInterface; +use Imagine\Driver\InfoProvider; use Imagine\Exception\InvalidArgumentException; use Imagine\Exception\RuntimeException; use Imagine\Image\AbstractFont; @@ -24,7 +25,7 @@ /** * Drawer implementation using the Imagick PHP extension. */ -final class Drawer implements DrawerInterface +final class Drawer implements DrawerInterface, InfoProvider { /** * @var \Imagick @@ -39,6 +40,17 @@ public function __construct(\Imagick $imagick) $this->imagick = $imagick; } + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + * @since 1.3.0 + */ + public static function getDriverInfo($required = true) + { + return DriverInfo::get($required); + } + /** * {@inheritdoc} * @@ -408,12 +420,8 @@ public function text($string, AbstractFont $font, PointInterface $position, $ang $text = new \ImagickDraw(); $text->setFont($font->getFile()); - /* - * @see http://www.php.net/manual/en/imagick.queryfontmetrics.php#101027 - * - * ensure font resolution is the same as GD's hard-coded 96 - */ - if (version_compare(phpversion('imagick'), '3.0.2', '>=')) { + // Ensure font resolution is the same as GD's hard-coded 96 + if (static::getDriverInfo()->hasFeature(DriverInfo::FEATURE_CUSTOMRESOLUTION)) { $text->setResolution(96, 96); $text->setFontSize($font->getSize()); } else { diff --git a/src/Imagick/DriverInfo.php b/src/Imagick/DriverInfo.php new file mode 100644 index 000000000..86f63952e --- /dev/null +++ b/src/Imagick/DriverInfo.php @@ -0,0 +1,285 @@ +driverRawVersion = (string) $driverRawVersion; + $this->driverSemverVersion = preg_match('/^.*?(\d+\.\d+\.\d+)/', $this->driverRawVersion, $m) ? $m[1] : ''; + $this->engineRawVersion = ''; + if (isset($engineRawVersion['versionString']) && is_string($engineRawVersion['versionString'])) { + if (preg_match('/^.*?(\d+\.\d+\.\d+(-\d+)?(\s+Q\d+)?)/i', $engineRawVersion['versionString'], $m)) { + $this->engineRawVersion = $m[1]; + } else { + $this->engineRawVersion = $engineRawVersion['versionString']; + } + } + $this->engineSemverVersion = preg_match('/^.*?(\d+\.\d+\.\d+)/', $this->engineRawVersion, $m) ? $m[1] : ''; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::get() + */ + public static function get($required = true) + { + if (self::$instance === false) { + if (class_exists('Imagick') && extension_loaded('imagick')) { + $extensionVersion = phpversion('imagick'); + $imagick = new \Imagick(); + $engineVersion = $imagick->getversion(); + self::$instance = new static(is_string($extensionVersion) ? $extensionVersion : '', is_array($engineVersion) ? $engineVersion : array()); + } else { + self::$instance = null; + } + } + if (self::$instance === null && $required) { + throw new NotSupportedException('Imagick not installed'); + } + + return self::$instance; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::checkVersionIsSupported() + */ + public function checkVersionIsSupported() + { + if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 50300) { + throw new NotSupportedException('Imagine requires PHP 5.3 or later'); + } + if (version_compare($this->getEngineVersion(), '6.2.9') < 0) { + throw new NotSupportedException(sprintf('ImageMagick version 6.2.9 or higher is required, %s provided', $this->getEngineVersion())); + } + if ($this->getEngineVersion(true) === '7.0.7-32') { + // https://github.com/php-imagine/Imagine/issues/689 + throw new NotSupportedException(sprintf('ImageMagick version %s has known bugs that prevent it from working', $this->getEngineVersion())); + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::getDriverVersion() + */ + public function getDriverVersion($raw = false) + { + return $raw ? $this->driverRawVersion : $this->driverSemverVersion; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::getEngineVersion() + */ + public function getEngineVersion($raw = false) + { + return $raw ? $this->engineRawVersion : $this->engineSemverVersion; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::requireFeature() + */ + public function requireFeature($features) + { + $features = (int) $features; + if ($features & static::FEATURE_COLORPROFILES) { + if (!$this->areColorProfilesSupported()) { + throw new NotSupportedException('Unable to manage color profiles: be sure to compile ImageMagick with the `--with-lcms2` option'); + } + } + if ($features & static::FEATURE_COLORSPACECONVERSION) { + if (!$this->isColorspaceConversionAvailable()) { + throw new NotSupportedException('Your version of Imagick does not support colorspace conversions.'); + } + } + if ($features & static::FEATURE_GRAYSCALEEFFECT) { + if (version_compare($this->getEngineVersion(), '6.8.5') <= 0) { + throw new NotSupportedException(sprintf('Converting an image to grayscale requires ImageMagick version 6.8.5 or higher is required, %s provided', $this->getEngineVersion())); + } + } + if ($features & static::FEATURE_CUSTOMRESOLUTION) { + // We can't do version_compare($this->getDriverVersion(), '3.1.0') < 0 because phpversion('imagick') may return @PACKAGE_VERSION@ + // @see https://www.php.net/manual/en/imagick.queryfontmetrics.php#101027 + // So, let's check ImagickDraw::setResolution (which has been introduced in 3.1.0b1 + if (!method_exists('ImagickDraw', 'setResolution')) { + throw new NotSupportedException(sprintf('Setting image resolution requires imagick version 3.1.0 or higher is required, %s provided', $this->getDriverVersion(true))); + } + } + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::hasFeature() + */ + public function hasFeature($features) + { + try { + $this->requireFeature($features); + } catch (NotSupportedException $x) { + return false; + } + + return true; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::getSupportedFormats() + */ + public function getSupportedFormats() + { + if ($this->supportedFormats !== null) { + return $this->supportedFormats; + } + $supportedFormats = array(); + $magickFormats = array_map('strtolower', \Imagick::queryFormats()); + foreach (Format::getAll() as $format) { + if (in_array($format->getID(), $magickFormats, true) || array_intersect($magickFormats, $format->getAlternativeIDs()) !== array()) { + $supportedFormats[] = $format; + } + } + $this->supportedFormats = new FormatList($supportedFormats); + + return $this->supportedFormats; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::isFormatSupported() + */ + public function isFormatSupported($format) + { + return $this->getSupportedFormats()->find($format) !== null; + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::checkPaletteSupport() + */ + public function checkPaletteSupport(PaletteInterface $palette) + { + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\Info::isPaletteSupported() + */ + public function isPaletteSupported(PaletteInterface $palette) + { + try { + $this->checkPaletteSupport($palette); + } catch (NotSupportedException $x) { + return false; + } + + return true; + } + + /** + * ImageMagick without the lcms delegate cannot handle profiles well. + * This detection is needed because there is no way to directly check for lcms. + * + * @return bool + */ + private function areColorProfilesSupported() + { + if ($this->colorProfilesSupported === null) { + $imagick = new \Imagick(); + if (method_exists($imagick, 'profileImage')) { + try { + $imagick->newImage(1, 1, new \ImagickPixel('#fff')); + $imagick->profileImage('icc', 'x'); + $this->colorProfilesSupported = false; + } catch (\ImagickException $exception) { + // If ImageMagick has support for profiles, it detects the invalid profile data 'x' and throws an exception. + $this->colorProfilesSupported = true; + } + } else { + $this->colorProfilesSupported = false; + } + } + + return $this->colorProfilesSupported; + } + + /** + * @return bool + */ + private function isColorspaceConversionAvailable() + { + if ($this->colorspaceConversionAvailable === null) { + $this->colorspaceConversionAvailable = method_exists('Imagick', 'setColorspace'); + } + + return $this->colorspaceConversionAvailable; + } +} diff --git a/src/Imagick/Effects.php b/src/Imagick/Effects.php index ef67cefce..a4d1e3ce5 100644 --- a/src/Imagick/Effects.php +++ b/src/Imagick/Effects.php @@ -11,6 +11,7 @@ namespace Imagine\Imagick; +use Imagine\Driver\InfoProvider; use Imagine\Effects\EffectsInterface; use Imagine\Exception\InvalidArgumentException; use Imagine\Exception\NotSupportedException; @@ -22,7 +23,7 @@ /** * Effects implementation using the Imagick PHP extension. */ -class Effects implements EffectsInterface +class Effects implements EffectsInterface, InfoProvider { /** * @var \Imagick @@ -39,6 +40,17 @@ public function __construct(\Imagick $imagick) $this->imagick = $imagick; } + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + * @since 1.3.0 + */ + public static function getDriverInfo($required = true) + { + return DriverInfo::get($required); + } + /** * {@inheritdoc} * @@ -78,9 +90,7 @@ public function negative() */ public function grayscale() { - if (version_compare(Imagine::getExtensionInfo()->getImageMagickSemVerVersion(), '6.8.5') < 0) { - throw new NotSupportedException('Your imagick extension has been compiled with ImageMagick ' . Imagine::getExtensionInfo()->getImageMagickFullVersion() . ' which is too old (you need at least ImageMagick 6.8.5-10)'); - } + static::getDriverInfo()->requireFeature(DriverInfo::FEATURE_GRAYSCALEEFFECT); try { $this->imagick->setImageType(\Imagick::IMGTYPE_GRAYSCALE); } catch (\ImagickException $e) { @@ -182,7 +192,7 @@ public function convolve(Matrix $matrix) throw new InvalidArgumentException(sprintf('A convolution matrix must be 3x3 (%dx%d provided).', $matrix->getWidth(), $matrix->getHeight())); } try { - if (class_exists('ImagickKernel', false) && version_compare(Imagine::getExtensionInfo()->getImageMagickSemVerVersion(), '7') >= 0) { + if (class_exists('ImagickKernel', false) && version_compare(static::getDriverInfo()->getEngineVersion(), '7.0.0') >= 0) { $kernel = \ImagickKernel::fromMatrix($matrix->getMatrix()); } else { $kernel = $matrix->getValueList(); diff --git a/src/Imagick/ExtensionInfo.php b/src/Imagick/ExtensionInfo.php deleted file mode 100644 index 077c99ac7..000000000 --- a/src/Imagick/ExtensionInfo.php +++ /dev/null @@ -1,79 +0,0 @@ -getVersion(); - if (preg_match('/(\d+\.\d+\.\d+)/', $imagickVersion, $m)) { - $this->imagickSemVerVersion = $m[0]; - } else { - $this->imagickSemVerVersion = ''; - } - $imageMagickVersionInfo = $imagick->getversion(); - if (preg_match('/(\d+\.\d+\.\d+)(-\d+)?/', $imageMagickVersionInfo['versionString'], $m)) { - $this->imageMagickFullVersion = $m[1] . (isset($m[2]) ? $m[2] : ''); - $this->imageMagickSemVerVersion = $m[1]; - } else { - $this->imageMagickFullVersion = ''; - $this->imageMagickSemVerVersion = ''; - } - - return $m[1]; - } - - /** - * Get the major.minor.patch version of imagick. - * - * @example 3.4.4 - * - * @return string - */ - public function getImagickSemVerVersion() - { - return $this->imagickSemVerVersion; - } - - /** - * Get the full version of ImageMagick. - * - * @example 7.0.7-11 - * - * @return string - */ - public function getImageMagickFullVersion() - { - return $this->imageMagickFullVersion; - } - - /** - * Get the major.minor.patch version of ImageMagick. - * - * @example 7.0.7 - * - * @return string - */ - public function getImageMagickSemVerVersion() - { - return $this->imageMagickSemVerVersion; - } -} diff --git a/src/Imagick/Font.php b/src/Imagick/Font.php index 3edd261fb..434e405b6 100644 --- a/src/Imagick/Font.php +++ b/src/Imagick/Font.php @@ -11,13 +11,14 @@ namespace Imagine\Imagick; +use Imagine\Driver\InfoProvider; use Imagine\Image\AbstractFont; use Imagine\Image\Palette\Color\ColorInterface; /** * Font implementation using the Imagick PHP extension. */ -final class Font extends AbstractFont +final class Font extends AbstractFont implements InfoProvider { /** * @var \Imagick @@ -37,6 +38,17 @@ public function __construct(\Imagick $imagick, $file, $size, ColorInterface $col parent::__construct($file, $size, $color); } + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + * @since 1.3.0 + */ + public static function getDriverInfo($required = true) + { + return DriverInfo::get($required); + } + /** * {@inheritdoc} * @@ -48,12 +60,8 @@ public function box($string, $angle = 0) $text->setFont($this->file); - /* - * @see http://www.php.net/manual/en/imagick.queryfontmetrics.php#101027 - * - * ensure font resolution is the same as GD's hard-coded 96 - */ - if (version_compare(phpversion('imagick'), '3.0.2', '>=')) { + // ensure font resolution is the same as GD's hard-coded 96 + if (static::getDriverInfo()->hasFeature(DriverInfo::FEATURE_CUSTOMRESOLUTION)) { $text->setResolution(96, 96); $text->setFontSize($this->size); } else { diff --git a/src/Imagick/Image.php b/src/Imagick/Image.php index 947b3be96..6ad806074 100644 --- a/src/Imagick/Image.php +++ b/src/Imagick/Image.php @@ -11,6 +11,7 @@ namespace Imagine\Imagick; +use Imagine\Driver\InfoProvider; use Imagine\Exception\InvalidArgumentException; use Imagine\Exception\OutOfBoundsException; use Imagine\Exception\RuntimeException; @@ -20,6 +21,7 @@ use Imagine\Image\Fill\FillInterface; use Imagine\Image\Fill\Gradient\Horizontal; use Imagine\Image\Fill\Gradient\Linear; +use Imagine\Image\Format; use Imagine\Image\ImageInterface; use Imagine\Image\Metadata\MetadataBag; use Imagine\Image\Palette\Color\ColorInterface; @@ -32,7 +34,7 @@ /** * Image implementation using the Imagick PHP extension. */ -final class Image extends AbstractImage +final class Image extends AbstractImage implements InfoProvider { /** * @var \Imagick @@ -49,16 +51,6 @@ final class Image extends AbstractImage */ private $palette; - /** - * @var bool - */ - private static $supportsColorspaceConversion; - - /** - * @var bool - */ - private static $supportsProfiles; - /** * @var array */ @@ -78,9 +70,8 @@ final class Image extends AbstractImage public function __construct(\Imagick $imagick, PaletteInterface $palette, MetadataBag $metadata) { $this->metadata = $metadata; - $this->detectColorspaceConversionSupport(); $this->imagick = $imagick; - if (static::$supportsColorspaceConversion) { + if (static::getDriverInfo()->hasFeature(DriverInfo::FEATURE_COLORSPACECONVERSION)) { $this->setColorspace($palette); } $this->palette = $palette; @@ -114,6 +105,17 @@ public function __destruct() } } + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + * @since 1.3.0 + */ + public static function getDriverInfo($required = true) + { + return DriverInfo::get($required); + } + /** * Returns the underlying \Imagick instance. * @@ -353,7 +355,15 @@ public function save($path = null, array $options = array()) */ public function show($format, array $options = array()) { - header('Content-type: ' . $this->getMimeType($format)); + $formatInfo = static::getDriverInfo()->getSupportedFormats()->find($format); + if ($formatInfo === null) { + throw new InvalidArgumentException(sprintf( + 'Displaying an image in "%s" format is not supported, please use one of the following formats: "%s"', + $format, + implode('", "', static::getDriverInfo()->getSupportedFormats()->getAllIDs()) + )); + } + header('Content-type: ' . $formatInfo->getMimeType()); echo $this->get($format, $options); return $this; @@ -406,7 +416,7 @@ public function interlace($scheme) private function prepareOutput(array $options, $path = null) { if (isset($options['animated']) && $options['animated'] === true) { - $format = isset($options['format']) ? $options['format'] : 'gif'; + $format = isset($options['format']) ? $options['format'] : Format::ID_GIF; $delay = isset($options['animated.delay']) ? $options['animated.delay'] : null; $loops = isset($options['animated.loops']) ? $options['animated.loops'] : 0; @@ -435,7 +445,7 @@ private function prepareOutput(array $options, $path = null) */ public function __toString() { - return $this->get('png'); + return $this->get(Format::ID_PNG); } /** @@ -665,18 +675,16 @@ public function layers() */ public function usePalette(PaletteInterface $palette) { - if (!isset(static::$colorspaceMapping[$palette->name()])) { - throw new InvalidArgumentException(sprintf('The palette %s is not supported by Imagick driver', $palette->name())); - } - if ($this->palette->name() === $palette->name()) { return $this; } - if (!static::$supportsColorspaceConversion) { - throw new RuntimeException('Your version of Imagick does not support colorspace conversions.'); + if (!isset(static::$colorspaceMapping[$palette->name()])) { + throw new InvalidArgumentException(sprintf('The palette %s is not supported by Imagick driver', $palette->name())); } + static::getDriverInfo()->requireFeature(DriverInfo::FEATURE_COLORSPACECONVERSION); + try { try { $hasICCProfile = (bool) $this->imagick->getImageProfile('icc'); @@ -714,10 +722,7 @@ public function palette() */ public function profile(ProfileInterface $profile) { - if (!$this->detectProfilesSupport()) { - throw new RuntimeException(sprintf('Unable to add profile %s to image, be sure to compile imagemagick with `--with-lcms2` option', $profile->name())); - } - + static::getDriverInfo()->requireFeature(DriverInfo::FEATURE_COLORPROFILES); try { $this->imagick->profileImage('icc', $profile->data()); } catch (\ImagickException $e) { @@ -766,12 +771,9 @@ private function applyImageOptions(\Imagick $image, array $options, $path) $format = pathinfo($image->getImageFilename(), \PATHINFO_EXTENSION); } - $format = strtolower($format); - - switch ($format) { - case 'jpeg': - case 'jpg': - case 'pjpeg': + $formatInfo = Format::get($format); + switch ($formatInfo === null ? '' : $formatInfo->getID()) { + case Format::ID_JPEG: if (!isset($options['jpeg_quality'])) { if (isset($options['quality'])) { $options['jpeg_quality'] = $options['quality']; @@ -790,7 +792,7 @@ private function applyImageOptions(\Imagick $image, array $options, $path) }, $options['jpeg_sampling_factors'])); } break; - case 'png': + case Format::ID_PNG: if (!isset($options['png_compression_level'])) { if (isset($options['quality'])) { $options['png_compression_level'] = round((100 - $options['quality']) * 9 / 100); @@ -815,7 +817,7 @@ private function applyImageOptions(\Imagick $image, array $options, $path) $image->setcompressionquality($compression); } break; - case 'webp': + case Format::ID_WEBP: if (!isset($options['webp_quality'])) { if (isset($options['quality'])) { $options['webp_quality'] = $options['quality']; @@ -828,38 +830,38 @@ private function applyImageOptions(\Imagick $image, array $options, $path) $image->setOption('webp:lossless', $options['webp_lossless']); } break; - case 'avif': - case 'heic': - if (!empty($options[$format . '_lossless'])) { + case Format::ID_AVIF: + case Format::ID_HEIC: + if (!empty($options[$formatInfo->getID() . '_lossless'])) { $image->setimagecompressionquality(100); $image->setcompressionquality(100); } else { - if (!isset($options[$format . '_quality'])) { + if (!isset($options[$formatInfo->getID() . '_quality'])) { if (isset($options['quality'])) { - $options[$format . '_quality'] = $options['quality']; + $options[$formatInfo->getID() . '_quality'] = $options['quality']; } } - if (isset($options[$format . '_quality'])) { - $options[$format . '_quality'] = max(1, min(99, $options[$format . '_quality'])); - $image->setimagecompressionquality($options[$format . '_quality']); - $image->setcompressionquality($options[$format . '_quality']); + if (isset($options[$formatInfo->getID() . '_quality'])) { + $options[$formatInfo->getID() . '_quality'] = max(1, min(99, $options[$formatInfo->getID() . '_quality'])); + $image->setimagecompressionquality($options[$formatInfo->getID() . '_quality']); + $image->setcompressionquality($options[$formatInfo->getID() . '_quality']); } } break; - case 'jxl': - if (!empty($options[$format . '_lossless'])) { + case Format::ID_JXL: + if (!empty($options['jxl_lossless'])) { $image->setimagecompressionquality(100); $image->setcompressionquality(100); } else { - if (!isset($options[$format . '_quality'])) { + if (!isset($options['jxl_quality'])) { if (isset($options['quality'])) { - $options[$format . '_quality'] = $options['quality']; + $options['jxl_quality'] = $options['quality']; } } - if (isset($options[$format . '_quality'])) { - $options[$format . '_quality'] = max(9, min(99, $options[$format . '_quality'])); - $image->setimagecompressionquality($options[$format . '_quality']); - $image->setcompressionquality($options[$format . '_quality']); + if (isset($options['jxl_quality'])) { + $options['jxl_quality'] = max(9, min(99, $options['jxl_quality'])); + $image->setimagecompressionquality($options['jxl_quality']); + $image->setcompressionquality($options['jxl_quality']); } } break; @@ -952,40 +954,6 @@ private function applyFastLinear(Linear $fill) $gradient->destroy(); } - /** - * Internal. - * - * Get the mime type based on format. - * - * @param string $format - * - * @throws \Imagine\Exception\RuntimeException - * - * @return string mime-type - */ - private function getMimeType($format) - { - static $mimeTypes = array( - 'jpeg' => 'image/jpeg', - 'jpg' => 'image/jpeg', - 'jxl' => 'image/jxl', - 'gif' => 'image/gif', - 'png' => 'image/png', - 'wbmp' => 'image/vnd.wap.wbmp', - 'xbm' => 'image/xbm', - 'webp' => 'image/webp', - 'avif' => 'image/avif', - 'heic' => 'image/heic', - 'bmp' => 'image/bmp', - ); - - if (!isset($mimeTypes[$format])) { - throw new RuntimeException(sprintf('Unsupported format given. Only %s are supported, %s given', implode(', ', array_keys($mimeTypes)), $format)); - } - - return $mimeTypes[$format]; - } - /** * Sets colorspace and image type, assigns the palette. * @@ -1026,48 +994,6 @@ private function setColorspace(PaletteInterface $palette) $this->palette = $palette; } - /** - * Older imagemagick versions does not support colorspace conversions. - * Let's detect if it is supported. - * - * @return bool - */ - private function detectColorspaceConversionSupport() - { - if (static::$supportsColorspaceConversion !== null) { - return static::$supportsColorspaceConversion; - } - - return static::$supportsColorspaceConversion = method_exists('Imagick', 'setColorspace'); - } - - /** - * ImageMagick without the lcms delegate cannot handle profiles well. - * This detection is needed because there is no way to directly check for lcms. - * - * @return bool - */ - private function detectProfilesSupport() - { - if (self::$supportsProfiles !== null) { - return self::$supportsProfiles; - } - - self::$supportsProfiles = false; - - try { - $image = new \Imagick(); - $image->newImage(1, 1, new \ImagickPixel('#fff')); - $image->profileImage('icc', 'x'); - } catch (\ImagickException $exception) { - // If ImageMagick has support for profiles, - // it detects the invalid profile data 'x' and throws an exception. - self::$supportsProfiles = true; - } - - return self::$supportsProfiles; - } - /** * Returns the filter if it's supported. * diff --git a/src/Imagick/Imagine.php b/src/Imagick/Imagine.php index 88f6fcae8..b216a785c 100644 --- a/src/Imagick/Imagine.php +++ b/src/Imagick/Imagine.php @@ -11,6 +11,7 @@ namespace Imagine\Imagick; +use Imagine\Driver\InfoProvider; use Imagine\Exception\InvalidArgumentException; use Imagine\Exception\NotSupportedException; use Imagine\Exception\RuntimeException; @@ -30,29 +31,25 @@ * * @final */ -class Imagine extends AbstractImagine +class Imagine extends AbstractImagine implements InfoProvider { - /** - * @var \Imagine\Imagick\ExtensionInfo|false|null - */ - private static $extensionInfo = false; - /** * @throws \Imagine\Exception\RuntimeException */ public function __construct() { - $extensionInfo = static::getExtensionInfo(); - if ($extensionInfo === null) { - throw new RuntimeException('Imagick not installed'); - } + static::getDriverInfo()->checkVersionIsSupported(); + } - if (version_compare($extensionInfo->getImageMagickSemVerVersion(), '6.2.9') < 0) { - throw new RuntimeException(sprintf('ImageMagick version 6.2.9 or higher is required, %s provided', $extensionInfo->getImageMagickSemVerVersion())); - } - if ($extensionInfo->getImageMagickFullVersion() === '7.0.7-32') { // https://github.com/avalanche123/Imagine/issues/689 - throw new RuntimeException(sprintf('ImageMagick version %s has known bugs that prevent it from working', $extensionInfo->getImageMagickFullVersion())); - } + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + * @since 1.3.0 + */ + public static function getDriverInfo($required = true) + { + return DriverInfo::get($required); } /** @@ -67,12 +64,12 @@ public function open($path) try { if ($loader->isLocalFile()) { - if (DIRECTORY_SEPARATOR === '\\' && PHP_INT_SIZE === 8 && PHP_VERSION_ID >= 70100 && PHP_VERSION_ID < 70200) { + if (DIRECTORY_SEPARATOR === '\\' && PHP_INT_SIZE === 8 && defined('PHP_VERSION_ID') && PHP_VERSION_ID >= 70100 && PHP_VERSION_ID < 70200) { + // Passing the file name to the Imagick constructor may break PHP 7.1 64 bit on Windows - see https://github.com/mkoppanen/imagick/issues/252 + $imagick = new \Imagick($loader->getPath()); + } else { $imagick = new \Imagick(); - // PHP 7.1 64 bit on Windows: don't pass the file name to the constructor: it may break PHP - see https://github.com/mkoppanen/imagick/issues/252 $imagick->readImageBlob($loader->getData(), $path); - } else { - $imagick = new \Imagick($loader->getPath()); } } else { $imagick = new \Imagick(); @@ -108,7 +105,8 @@ public function create(BoxInterface $size, ColorInterface $color = null) $imagick->setImageMatte(true); $imagick->setImageBackgroundColor($pixel); - if (version_compare('6.3.1', static::getExtensionInfo()->getImageMagickSemVerVersion()) < 0) { + // Setting image alpha requires ImageMagick version 6.3.1 or higher is required + if (version_compare(static::getDriverInfo()->getEngineVersion(), '6.3.1') >= 0) { // setImageOpacity was replaced with setImageAlpha in php-imagick v3.4.3 if (method_exists($imagick, 'setImageAlpha')) { $imagick->setImageAlpha($pixel->getColorValue(\Imagick::COLOR_ALPHA)); @@ -180,27 +178,6 @@ public function font($file, $size, ColorInterface $color) return $this->getClassFactory()->createFont(ClassFactoryInterface::HANDLE_IMAGICK, $file, $size, $color); } - /** - * Get the info about the Imagick extension. - * - * @return \Imagine\Imagick\ExtensionInfo|null return NULL if Imagick is not installed - */ - public static function getExtensionInfo() - { - if (self::$extensionInfo === false) { - if (!class_exists('Imagick')) { - self::$extensionInfo = null; - } else { - $imagick = new \Imagick(); - self::$extensionInfo = new ExtensionInfo($imagick); - $imagick->clear(); - $imagick->destroy(); - } - } - - return self::$extensionInfo; - } - /** * Returns the palette corresponding to an \Imagick resource colorspace. * @@ -221,6 +198,7 @@ private function createPalette(\Imagick $imagick) case \Imagick::COLORSPACE_GRAY: return new Grayscale(); case \Imagick::COLORSPACE_YCBCR: + static::getDriverInfo()->requireFeature(DriverInfo::FEATURE_COLORSPACECONVERSION); try { $profile = $imagick->getImageProfile('icc'); } catch (\ImagickException $e) { @@ -229,6 +207,7 @@ private function createPalette(\Imagick $imagick) $imagick->transformImageColorspace(\Imagick::COLORSPACE_SRGB); if ($profile) { + static::getDriverInfo()->requireFeature(DriverInfo::FEATURE_COLORPROFILES); $imagick->setImageProfile('icc', $profile); } diff --git a/src/Imagick/Layers.php b/src/Imagick/Layers.php index f1fe30ed8..c90146851 100644 --- a/src/Imagick/Layers.php +++ b/src/Imagick/Layers.php @@ -11,15 +11,17 @@ namespace Imagine\Imagick; +use Imagine\Driver\InfoProvider; use Imagine\Exception\InvalidArgumentException; use Imagine\Exception\OutOfBoundsException; use Imagine\Exception\RuntimeException; use Imagine\Factory\ClassFactoryInterface; use Imagine\Image\AbstractLayers; +use Imagine\Image\Format; use Imagine\Image\Metadata\MetadataBag; use Imagine\Image\Palette\PaletteInterface; -class Layers extends AbstractLayers +class Layers extends AbstractLayers implements InfoProvider { /** * @var \Imagine\Imagick\Image @@ -54,6 +56,17 @@ public function __construct(Image $image, PaletteInterface $palette, \Imagick $r $this->offset = (int) $initialOffset; } + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + * @since 1.3.0 + */ + public static function getDriverInfo($required = true) + { + return DriverInfo::get($required); + } + /** * {@inheritdoc} * @@ -78,7 +91,8 @@ public function merge() */ public function animate($format, $delay, $loops) { - if (strtolower($format) !== 'gif') { + $formatInfo = Format::get($format); + if ($formatInfo === null || $formatInfo->getID() !== Format::ID_GIF) { throw new InvalidArgumentException('Animated picture is currently only supported on gif'); } @@ -93,7 +107,7 @@ public function animate($format, $delay, $loops) try { foreach ($this as $offset => $layer) { $this->resource->setIteratorIndex($offset); - $this->resource->setFormat($format); + $this->resource->setFormat(Format::ID_GIF); if ($delay !== null) { $layer->getImagick()->setImageDelay($delay / 10); diff --git a/tests/tests/Constraint/AbstractIsImageEqualTest.php b/tests/tests/Constraint/AbstractIsImageEqualTest.php index fc32c32ce..46c2842e1 100644 --- a/tests/tests/Constraint/AbstractIsImageEqualTest.php +++ b/tests/tests/Constraint/AbstractIsImageEqualTest.php @@ -11,13 +11,19 @@ namespace Imagine\Test\Constraint; +use Imagine\Driver\InfoProvider; use Imagine\Image\Box; use Imagine\Image\ImageInterface; use Imagine\Image\Palette\RGB; use Imagine\Test\ImagineTestCase; -abstract class AbstractIsImageEqualTest extends ImagineTestCase +abstract class AbstractIsImageEqualTest extends ImagineTestCase implements InfoProvider { + /** + * @return \Imagine\Image\ImagineInterface + */ + abstract protected function getImagine(); + public function testThrowsExceptionWithInvalidArguments() { $image = $this->getImagine()->create(new Box(1, 1)); @@ -129,9 +135,4 @@ public function testDifferentImages(ImageInterface $image1, ImageInterface $imag } $this->assertInstanceOf('PHPUnit\Framework\ExpectationFailedException', $error, 'different images should be detected as different'); } - - /** - * @return \Imagine\Image\ImagineInterface - */ - abstract protected function getImagine(); } diff --git a/tests/tests/Draw/AbstractAlphaBlendingAwareDrawerTest.php b/tests/tests/Draw/AbstractAlphaBlendingAwareDrawerTest.php index 09d18b7cb..c9a1b4a3d 100644 --- a/tests/tests/Draw/AbstractAlphaBlendingAwareDrawerTest.php +++ b/tests/tests/Draw/AbstractAlphaBlendingAwareDrawerTest.php @@ -12,14 +12,20 @@ namespace Imagine\Test\Draw; use Imagine\Draw\AlphaBlendingAwareDrawerInterface; +use Imagine\Driver\InfoProvider; use Imagine\Image\Box; use Imagine\Image\Palette\Color\ColorInterface; use Imagine\Image\Palette\RGB; use Imagine\Image\Point; use Imagine\Test\ImagineTestCase; -abstract class AbstractAlphaBlendingAwareDrawerTest extends ImagineTestCase +abstract class AbstractAlphaBlendingAwareDrawerTest extends ImagineTestCase implements InfoProvider { + /** + * @return \Imagine\Image\ImagineInterface + */ + abstract protected function getImagine(); + /** * {@inheritdoc} * @@ -86,9 +92,4 @@ public function testUsingValue() $this->assertGreaterThan(0, $blendedColor->getValue(ColorInterface::COLOR_GREEN)); $this->assertSame(0, $blendedColor->getValue(ColorInterface::COLOR_BLUE)); } - - /** - * @return \Imagine\Image\ImagineInterface - */ - abstract protected function getImagine(); } diff --git a/tests/tests/Draw/AbstractDrawerTest.php b/tests/tests/Draw/AbstractDrawerTest.php index 1119ec62b..38e6bbd92 100644 --- a/tests/tests/Draw/AbstractDrawerTest.php +++ b/tests/tests/Draw/AbstractDrawerTest.php @@ -11,15 +11,21 @@ namespace Imagine\Test\Draw; +use Imagine\Driver\Info; +use Imagine\Driver\InfoProvider; use Imagine\Image\Box; -use Imagine\Image\ImagineInterface; use Imagine\Image\Palette\RGB; use Imagine\Image\Point; use Imagine\Image\Point\Center; use Imagine\Test\ImagineTestCase; -abstract class AbstractDrawerTest extends ImagineTestCase +abstract class AbstractDrawerTest extends ImagineTestCase implements InfoProvider { + /** + * @return \Imagine\Image\ImagineInterface + */ + abstract protected function getImagine(); + public function thicknessProvider() { return array( @@ -211,8 +217,8 @@ public function testPolygon($thickness, $fill) public function testText() { - if (!$this->isFontTestSupported()) { - $this->markTestSkipped('This install does not support font tests'); + if (!$this->getDriverInfo()->hasFeature(Info::FEATURE_TEXTFUNCTIONS)) { + $this->isGoingToThrowException('Imagine\Exception\NotSupportedException'); } $imagine = $this->getImagine(); $image = $imagine->create(new Box(60, 60), $this->getColor('fff')); @@ -247,10 +253,9 @@ public function testDrawASmileyFace() public function testText2() { - if (!$this->isFontTestSupported()) { - $this->markTestSkipped('This install does not support font tests'); + if (!$this->getDriverInfo()->hasFeature(Info::FEATURE_TEXTFUNCTIONS)) { + $this->isGoingToThrowException('Imagine\Exception\NotSupportedException'); } - $path = IMAGINE_TEST_FIXTURESFOLDER . '/font/Arial.ttf'; $black = $this->getColor('000'); $file36 = $this->getTemporaryFilename('36.png'); @@ -308,6 +313,11 @@ public function testText2() $this->assertFileExists($file12); } + /** + * @param string|int[]|int $color + * + * @return \Imagine\Image\Palette\Color\RGB + */ private function getColor($color) { static $palette; @@ -318,11 +328,4 @@ private function getColor($color) return $palette->color($color); } - - /** - * @return ImagineInterface - */ - abstract protected function getImagine(); - - abstract protected function isFontTestSupported(); } diff --git a/tests/tests/Driver/AbstractDriverInfoTest.php b/tests/tests/Driver/AbstractDriverInfoTest.php new file mode 100644 index 000000000..f284a2cb9 --- /dev/null +++ b/tests/tests/Driver/AbstractDriverInfoTest.php @@ -0,0 +1,34 @@ +assertInstanceOf('Imagine\Image\Format', $format); + $this->assertSame($format->getID(), $formatID); + $driverInfo = $this->getDriverInfo(); + $this->assertTrue($driverInfo->isFormatSupported($format)); + $this->assertTrue($driverInfo->isFormatSupported($formatID)); + $this->assertSame($format, $driverInfo->getSupportedFormats()->find($format)); + $this->assertSame($format, $driverInfo->getSupportedFormats()->find($formatID)); + } +} diff --git a/tests/tests/Effects/AbstractEffectsTest.php b/tests/tests/Effects/AbstractEffectsTest.php index 9d1f6a0f5..2b9e3e061 100644 --- a/tests/tests/Effects/AbstractEffectsTest.php +++ b/tests/tests/Effects/AbstractEffectsTest.php @@ -11,17 +11,26 @@ namespace Imagine\Test\Effects; +use Imagine\Driver\Info; +use Imagine\Driver\InfoProvider; use Imagine\Image\Box; -use Imagine\Image\ImagineInterface; use Imagine\Image\Palette\RGB; use Imagine\Image\Point; use Imagine\Test\ImagineTestCase; use Imagine\Utils\Matrix; -abstract class AbstractEffectsTest extends ImagineTestCase +abstract class AbstractEffectsTest extends ImagineTestCase implements InfoProvider { + /** + * @return \Imagine\Image\ImagineInterface + */ + abstract protected function getImagine(); + public function testNegate() { + if (!$this->getDriverInfo()->hasFeature(Info::FEATURE_NEGATEIMAGE)) { + $this->isGoingToThrowException('Imagine\Exception\NotSupportedException'); + } $palette = new RGB(); $imagine = $this->getImagine(); @@ -59,6 +68,9 @@ public function testGamma() public function testGrayscale() { + if (!$this->getDriverInfo()->hasFeature(Info::FEATURE_GRAYSCALEEFFECT)) { + $this->isGoingToThrowException('Imagine\Exception\NotSupportedException'); + } $palette = new RGB(); $imagine = $this->getImagine(); @@ -114,6 +126,9 @@ public function testBrightness($color, $brightness, $expectedColor) public function testColorize() { + if (!$this->getDriverInfo()->hasFeature(Info::FEATURE_COLORIZEIMAGE)) { + $this->isGoingToThrowException('Imagine\Exception\NotSupportedException'); + } $palette = new RGB(); $imagine = $this->getImagine(); @@ -154,6 +169,9 @@ public function testBlur() public function testConvolution() { + if (!$this->getDriverInfo()->hasFeature(Info::FEATURE_CONVOLVEIMAGE)) { + $this->isGoingToThrowException('Imagine\Exception\NotSupportedException'); + } $imagine = $this->getImagine(); $image = $imagine->open(IMAGINE_TEST_FIXTURESFOLDER . '/trans.gif'); $matrix = new Matrix(3, 3, array( @@ -168,9 +186,4 @@ public function testConvolution() $imagine->open(IMAGINE_TEST_FIXTURESFOLDER . '/convolution/trans-blur.gif') ); } - - /** - * @return ImagineInterface - */ - abstract protected function getImagine(); } diff --git a/tests/tests/Factory/AbstractClassFactoryTest.php b/tests/tests/Factory/AbstractClassFactoryTest.php index f172ae843..cc6d4a478 100644 --- a/tests/tests/Factory/AbstractClassFactoryTest.php +++ b/tests/tests/Factory/AbstractClassFactoryTest.php @@ -11,34 +11,29 @@ namespace Imagine\Test\Factory; +use Imagine\Driver\Info; +use Imagine\Driver\InfoProvider; use Imagine\Image\Box; use Imagine\Image\Palette\RGB; use Imagine\Test\ImagineTestCase; -abstract class AbstractClassFactoryTest extends ImagineTestCase +abstract class AbstractClassFactoryTest extends ImagineTestCase implements InfoProvider { + /** + * @return \Imagine\Image\ImagineInterface + */ + abstract protected function getImagine(); + public function testClassFactoryIsForwarded() { $imagine = $this->getImagine(); $image = $imagine->create(new Box(1, 1)); $this->assertSame($imagine->getClassFactory(), $image->getClassFactory()); $palette = new RGB(); - if ($this->canTestFont()) { - $font = $imagine->font(__FILE__, 1, $palette->color('#000000')); - $this->assertSame($imagine->getClassFactory(), $font->getClassFactory()); + if (!$this->getDriverInfo()->hasFeature(Info::FEATURE_TEXTFUNCTIONS)) { + $this->isGoingToThrowException('Imagine\Exception\NotSupportedException'); } - } - - /** - * @return \Imagine\Image\ImagineInterface - */ - abstract protected function getImagine(); - - /** - * @return bool - */ - protected function canTestFont() - { - return true; + $font = $imagine->font(__FILE__, 1, $palette->color('#000000')); + $this->assertSame($imagine->getClassFactory(), $font->getClassFactory()); } } diff --git a/tests/tests/Functional/GdTransparentGifHandlingTest.php b/tests/tests/Functional/GdTransparentGifHandlingTest.php index 0eabef2dd..2f7793250 100644 --- a/tests/tests/Functional/GdTransparentGifHandlingTest.php +++ b/tests/tests/Functional/GdTransparentGifHandlingTest.php @@ -11,7 +11,8 @@ namespace Imagine\Test\Functional; -use Imagine\Exception\RuntimeException; +use Imagine\Driver\InfoProvider; +use Imagine\Gd\DriverInfo; use Imagine\Gd\Imagine; use Imagine\Image\Point; use Imagine\Test\ImagineTestCase; @@ -19,17 +20,16 @@ /** * @group gd */ -class GdTransparentGifHandlingTest extends ImagineTestCase +class GdTransparentGifHandlingTest extends ImagineTestCase implements InfoProvider { - private function getImagine() + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + */ + public static function getDriverInfo($required = true) { - try { - $imagine = new Imagine(); - } catch (RuntimeException $e) { - $this->markTestSkipped($e->getMessage()); - } - - return $imagine; + return DriverInfo::get($required); } /** @@ -37,7 +37,7 @@ private function getImagine() */ public function testShouldResize() { - $imagine = $this->getImagine(); + $imagine = new Imagine(); $new = $this->getTemporaryFilename('.jpeg'); $image = $imagine->open(IMAGINE_TEST_FIXTURESFOLDER . '/xparent.gif'); diff --git a/tests/tests/Gd/AlphaBlendingAwareDrawerTest.php b/tests/tests/Gd/AlphaBlendingAwareDrawerTest.php index 8afb16d6e..4f71254df 100644 --- a/tests/tests/Gd/AlphaBlendingAwareDrawerTest.php +++ b/tests/tests/Gd/AlphaBlendingAwareDrawerTest.php @@ -2,6 +2,7 @@ namespace Imagine\Test\Gd; +use Imagine\Gd\DriverInfo; use Imagine\Gd\Imagine; use Imagine\Test\Draw\AbstractAlphaBlendingAwareDrawerTest; @@ -10,6 +11,16 @@ */ class AlphaBlendingAwareDrawerTest extends AbstractAlphaBlendingAwareDrawerTest { + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + */ + public static function getDriverInfo($required = true) + { + return DriverInfo::get($required); + } + /** * {@inheritdoc} * diff --git a/tests/tests/Gd/ClassFactoryTest.php b/tests/tests/Gd/ClassFactoryTest.php index 4bc2d8a61..7f360ac72 100644 --- a/tests/tests/Gd/ClassFactoryTest.php +++ b/tests/tests/Gd/ClassFactoryTest.php @@ -11,6 +11,7 @@ namespace Imagine\Test\Gd; +use Imagine\Gd\DriverInfo; use Imagine\Gd\Imagine; use Imagine\Test\Factory\AbstractClassFactoryTest; @@ -19,29 +20,23 @@ */ class ClassFactoryTest extends AbstractClassFactoryTest { - protected function setUpBase() - { - parent::setUpBase(); - - if (!function_exists('gd_info')) { - $this->markTestSkipped('Gd not installed'); - } - } - - protected function getImagine() + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + */ + public static function getDriverInfo($required = true) { - return new Imagine(); + return DriverInfo::get($required); } /** * {@inheritdoc} * - * @see \Imagine\Test\Factory\AbstractClassFactoryTest::canTestFont() + * @see \Imagine\Test\Factory\AbstractClassFactoryTest::getImagine() */ - protected function canTestFont() + protected function getImagine() { - $info = gd_info(); - - return (bool) $info['FreeType Support']; + return new Imagine(); } } diff --git a/tests/tests/Gd/DrawerTest.php b/tests/tests/Gd/DrawerTest.php index 8f7537618..ec0ee25cb 100644 --- a/tests/tests/Gd/DrawerTest.php +++ b/tests/tests/Gd/DrawerTest.php @@ -11,6 +11,7 @@ namespace Imagine\Test\Gd; +use Imagine\Gd\DriverInfo; use Imagine\Gd\Imagine; use Imagine\Test\Draw\AbstractDrawerTest; @@ -22,15 +23,21 @@ class DrawerTest extends AbstractDrawerTest /** * {@inheritdoc} * - * @see \Imagine\Test\ImagineTestCaseBase::setUpBase() + * @see \Imagine\Driver\InfoProvider::getDriverInfo() */ - protected function setUpBase() + public static function getDriverInfo($required = true) { - parent::setUpBase(); + return DriverInfo::get($required); + } - if (!function_exists('gd_info')) { - $this->markTestSkipped('Gd not installed'); - } + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Draw\AbstractDrawerTest::getImagine() + */ + protected function getImagine() + { + return new Imagine(); } /** @@ -77,16 +84,4 @@ public function testEllipse($thickness, $fill) } parent::testEllipse($thickness, $fill); } - - protected function getImagine() - { - return new Imagine(); - } - - protected function isFontTestSupported() - { - $infos = gd_info(); - - return isset($infos['FreeType Support']) ? $infos['FreeType Support'] : false; - } } diff --git a/tests/tests/Gd/DriverInfoTest.php b/tests/tests/Gd/DriverInfoTest.php new file mode 100644 index 000000000..4f2d1c0a8 --- /dev/null +++ b/tests/tests/Gd/DriverInfoTest.php @@ -0,0 +1,37 @@ +markTestSkipped('Gd not installed'); - } + return DriverInfo::get($required); } + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Effects\AbstractEffectsTest::getImagine() + */ protected function getImagine() { return new Imagine(); diff --git a/tests/tests/Gd/FontTest.php b/tests/tests/Gd/FontTest.php index f7841d5bd..69092a3cd 100644 --- a/tests/tests/Gd/FontTest.php +++ b/tests/tests/Gd/FontTest.php @@ -11,6 +11,7 @@ namespace Imagine\Test\Gd; +use Imagine\Gd\DriverInfo; use Imagine\Gd\Imagine; use Imagine\Test\Image\AbstractFontTest; @@ -22,19 +23,11 @@ class FontTest extends AbstractFontTest /** * {@inheritdoc} * - * @see \Imagine\Test\ImagineTestCaseBase::setUpBase() + * @see \Imagine\Driver\InfoProvider::getDriverInfo() */ - protected function setUpBase() + public static function getDriverInfo($required = true) { - parent::setUpBase(); - - if (!function_exists('gd_info')) { - $this->markTestSkipped('Gd not installed'); - } - $infos = gd_info(); - if (empty($infos['FreeType Support'])) { - $this->markTestSkipped('This install does not support font tests'); - } + return DriverInfo::get($required); } /** diff --git a/tests/tests/Gd/ImageTest.php b/tests/tests/Gd/ImageTest.php index 0553ddd41..a7c5e0ec8 100644 --- a/tests/tests/Gd/ImageTest.php +++ b/tests/tests/Gd/ImageTest.php @@ -11,6 +11,7 @@ namespace Imagine\Test\Gd; +use Imagine\Gd\DriverInfo; use Imagine\Gd\Imagine; use Imagine\Image\ImageInterface; use Imagine\Test\Image\AbstractImageTest; @@ -23,15 +24,39 @@ class ImageTest extends AbstractImageTest /** * {@inheritdoc} * - * @see \Imagine\Test\ImagineTestCaseBase::setUpBase() + * @see \Imagine\Driver\InfoProvider::getDriverInfo() */ - protected function setUpBase() + public static function getDriverInfo($required = true) { - parent::setUpBase(); + return DriverInfo::get($required); + } - if (!function_exists('gd_info')) { - $this->markTestSkipped('Gd not installed'); - } + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImageTest::getImagine() + */ + protected function getImagine() + { + return new Imagine(); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImageTest::getImageResolution() + */ + protected function getImageResolution(ImageInterface $image) + { + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImageTest::getSamplingFactors() + */ + protected function getSamplingFactors(ImageInterface $image) + { } /** @@ -46,6 +71,11 @@ public function testImageResolutionChange() $this->markTestSkipped('GD driver does not support resolution options'); } + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImageTest::provideFilters() + */ public function provideFilters() { return array( @@ -53,6 +83,11 @@ public function provideFilters() ); } + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImageTest::providePalettes() + */ public function providePalettes() { return array( @@ -60,6 +95,11 @@ public function providePalettes() ); } + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImageTest::provideFromAndToPalettes() + */ public function provideFromAndToPalettes() { return array( @@ -71,6 +111,11 @@ public function provideFromAndToPalettes() ); } + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImageTest::testProfile() + */ public function testProfile() { $this->isGoingToThrowException('Imagine\Exception\RuntimeException'); @@ -149,11 +194,11 @@ public function testStripGBRImageHasGoodColors() $this->markTestSkipped('GD driver does not support ICC profiles'); } - protected function getImagine() - { - return new Imagine(); - } - + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImageTest::testRotateWithNoBackgroundColor() + */ public function testRotateWithNoBackgroundColor() { $vFrom = '5.5'; @@ -238,12 +283,4 @@ public function testResizeAnimatedGifResizeResult() { $this->markTestSkipped('GD driver does not support multiple layers'); } - - protected function getImageResolution(ImageInterface $image) - { - } - - protected function getSamplingFactors(ImageInterface $image) - { - } } diff --git a/tests/tests/Gd/ImagineTest.php b/tests/tests/Gd/ImagineTest.php index f8e30fd86..a6538f03b 100644 --- a/tests/tests/Gd/ImagineTest.php +++ b/tests/tests/Gd/ImagineTest.php @@ -11,6 +11,7 @@ namespace Imagine\Test\Gd; +use Imagine\Gd\DriverInfo; use Imagine\Gd\Imagine; use Imagine\Test\Image\AbstractImagineTest; @@ -22,15 +23,21 @@ class ImagineTest extends AbstractImagineTest /** * {@inheritdoc} * - * @see \Imagine\Test\ImagineTestCaseBase::setUpBase() + * @see \Imagine\Driver\InfoProvider::getDriverInfo() */ - protected function setUpBase() + public static function getDriverInfo($required = true) { - parent::setUpBase(); + return DriverInfo::get($required); + } - if (!function_exists('gd_info')) { - $this->markTestSkipped('Gd not installed'); - } + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImagineTest::getImagine() + */ + protected function getImagine() + { + return new Imagine(); } /** @@ -84,14 +91,4 @@ public function testShouldOpenAJxlImage() { $this->markTestSkipped('GD does not support JXL'); } - - /** - * {@inheritdoc} - * - * @see \Imagine\Test\Image\AbstractImagineTest::getImagine() - */ - protected function getImagine() - { - return new Imagine(); - } } diff --git a/tests/tests/Gd/IsImageEqualTest.php b/tests/tests/Gd/IsImageEqualTest.php index 213eebe34..508bf8f65 100644 --- a/tests/tests/Gd/IsImageEqualTest.php +++ b/tests/tests/Gd/IsImageEqualTest.php @@ -2,6 +2,7 @@ namespace Imagine\Test\Gd; +use Imagine\Gd\DriverInfo; use Imagine\Gd\Imagine; use Imagine\Test\Constraint\AbstractIsImageEqualTest; @@ -13,15 +14,11 @@ class IsImageEqualTest extends AbstractIsImageEqualTest /** * {@inheritdoc} * - * @see \Imagine\Test\ImagineTestCaseBase::setUpBase() + * @see \Imagine\Driver\InfoProvider::getDriverInfo() */ - protected function setUpBase() + public static function getDriverInfo($required = true) { - parent::setUpBase(); - - if (!function_exists('gd_info')) { - $this->markTestSkipped('Gd not installed'); - } + return DriverInfo::get($required); } /** diff --git a/tests/tests/Gd/LayersTest.php b/tests/tests/Gd/LayersTest.php index 242451290..27739ef60 100644 --- a/tests/tests/Gd/LayersTest.php +++ b/tests/tests/Gd/LayersTest.php @@ -11,6 +11,7 @@ namespace Imagine\Test\Gd; +use Imagine\Gd\DriverInfo; use Imagine\Gd\Image; use Imagine\Gd\Imagine; use Imagine\Gd\Layers; @@ -27,15 +28,41 @@ class LayersTest extends AbstractLayersTest /** * {@inheritdoc} * - * @see \Imagine\Test\ImagineTestCaseBase::setUpBase() + * @see \Imagine\Driver\InfoProvider::getDriverInfo() */ - protected function setUpBase() + public static function getDriverInfo($required = true) { - parent::setUpBase(); + return DriverInfo::get($required); + } - if (!function_exists('gd_info')) { - $this->markTestSkipped('Gd not installed'); - } + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractLayersTest::getImagine() + */ + protected function getImagine() + { + return new Imagine(); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractLayersTest::getImage() + */ + protected function getImage($path = null) + { + return new Image(imagecreatetruecolor(10, 10), new RGB(), new MetadataBag()); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractLayersTest::assertLayersEquals() + */ + protected function assertLayersEquals(ImageInterface $expected, ImageInterface $actual) + { + $this->assertEquals($expected->getGdResource(), $actual->getGdResource()); } public function testCount() @@ -58,6 +85,11 @@ public function testGetLayer() } } + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractLayersTest::testLayerArrayAccess() + */ public function testLayerArrayAccess() { $image = $this->getImage(IMAGINE_TEST_FIXTURESFOLDER . '/pink.gif'); @@ -67,6 +99,11 @@ public function testLayerArrayAccess() $this->assertTrue(isset($layers[0])); } + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractLayersTest::testLayerAddGetSetRemove() + */ public function testLayerAddGetSetRemove() { $image = $this->getImage(IMAGINE_TEST_FIXTURESFOLDER . '/pink.gif'); @@ -139,24 +176,4 @@ public function testAnimateWithWrongParameters($delay, $loops) { $this->markTestSkipped('GD driver does not support animated gifs'); } - - public function getImage($path = null) - { - return new Image(imagecreatetruecolor(10, 10), new RGB(), new MetadataBag()); - } - - public function getLayers(ImageInterface $image, $resource) - { - return new Layers($image, new RGB(), $resource); - } - - public function getImagine() - { - return new Imagine(); - } - - protected function assertLayersEquals($expected, $actual) - { - $this->assertEquals($expected->getGdResource(), $actual->getGdResource()); - } } diff --git a/tests/tests/Gmagick/AlphaBlendingAwareDrawerTest.php b/tests/tests/Gmagick/AlphaBlendingAwareDrawerTest.php index cbcc6d497..697cc2cfc 100644 --- a/tests/tests/Gmagick/AlphaBlendingAwareDrawerTest.php +++ b/tests/tests/Gmagick/AlphaBlendingAwareDrawerTest.php @@ -2,6 +2,7 @@ namespace Imagine\Test\Gmagick; +use Imagine\Gmagick\DriverInfo; use Imagine\Gmagick\Imagine; use Imagine\Test\Draw\AbstractAlphaBlendingAwareDrawerTest; @@ -14,14 +15,11 @@ class AlphaBlendingAwareDrawerTest extends AbstractAlphaBlendingAwareDrawerTest /** * {@inheritdoc} * - * @see \Imagine\Test\ImagineTestCaseBase::setUpBase() + * @see \Imagine\Driver\InfoProvider::getDriverInfo() */ - protected function setUpBase() + public static function getDriverInfo($required = true) { - if (!class_exists('Gmagick')) { - $this->markTestSkipped('Gmagick is not installed'); - } - parent::setUpBase(); + return DriverInfo::get($required); } /** diff --git a/tests/tests/Gmagick/ClassFactoryTest.php b/tests/tests/Gmagick/ClassFactoryTest.php index df7ac51de..b300f79fe 100644 --- a/tests/tests/Gmagick/ClassFactoryTest.php +++ b/tests/tests/Gmagick/ClassFactoryTest.php @@ -11,6 +11,7 @@ namespace Imagine\Test\Gmagick; +use Imagine\Gmagick\DriverInfo; use Imagine\Gmagick\Imagine; use Imagine\Test\Factory\AbstractClassFactoryTest; @@ -22,17 +23,18 @@ class ClassFactoryTest extends AbstractClassFactoryTest /** * {@inheritdoc} * - * @see \Imagine\Test\ImagineTestCaseBase::setUpBase() + * @see \Imagine\Driver\InfoProvider::getDriverInfo() */ - protected function setUpBase() + public static function getDriverInfo($required = true) { - parent::setUpBase(); - - if (!class_exists('Gmagick')) { - $this->markTestSkipped('Gmagick is not installed'); - } + return DriverInfo::get($required); } + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Factory\AbstractClassFactoryTest::getImagine() + */ protected function getImagine() { return new Imagine(); diff --git a/tests/tests/Gmagick/DrawerTest.php b/tests/tests/Gmagick/DrawerTest.php index 3a4b98f59..16b0570cb 100644 --- a/tests/tests/Gmagick/DrawerTest.php +++ b/tests/tests/Gmagick/DrawerTest.php @@ -11,6 +11,7 @@ namespace Imagine\Test\Gmagick; +use Imagine\Gmagick\DriverInfo; use Imagine\Gmagick\Imagine; use Imagine\Test\Draw\AbstractDrawerTest; @@ -22,24 +23,20 @@ class DrawerTest extends AbstractDrawerTest /** * {@inheritdoc} * - * @see \Imagine\Test\ImagineTestCaseBase::setUpBase() + * @see \Imagine\Driver\InfoProvider::getDriverInfo() */ - protected function setUpBase() + public static function getDriverInfo($required = true) { - parent::setUpBase(); - - if (!class_exists('Gmagick')) { - $this->markTestSkipped('Gmagick is not installed'); - } + return DriverInfo::get($required); } + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Draw\AbstractDrawerTest::getImagine() + */ protected function getImagine() { return new Imagine(); } - - protected function isFontTestSupported() - { - return true; - } } diff --git a/tests/tests/Gmagick/DriverInfoTest.php b/tests/tests/Gmagick/DriverInfoTest.php new file mode 100644 index 000000000..8154c278a --- /dev/null +++ b/tests/tests/Gmagick/DriverInfoTest.php @@ -0,0 +1,39 @@ +markTestSkipped('Gmagick is not installed'); - } + return DriverInfo::get($required); } /** * {@inheritdoc} * - * @see \Imagine\Test\Effects\AbstractEffectsTest::testColorize() + * @see \Imagine\Test\Effects\AbstractEffectsTest::getImagine() */ - public function testColorize() - { - $this->isGoingToThrowException('Imagine\Exception\NotSupportedException'); - parent::testColorize(); - } - protected function getImagine() { return new Imagine(); } - - public function testConvolution() - { - $gm = new \Gmagick(); - if (!method_exists($gm, 'convolveimage')) { - // convolveimage has been added in gmagick 2.0.1RC2 - $this->isGoingToThrowException('Imagine\Exception\NotSupportedException'); - } - - parent::testConvolution(); - } } diff --git a/tests/tests/Gmagick/FontTest.php b/tests/tests/Gmagick/FontTest.php index c159a33d9..53b2f401e 100644 --- a/tests/tests/Gmagick/FontTest.php +++ b/tests/tests/Gmagick/FontTest.php @@ -11,6 +11,7 @@ namespace Imagine\Test\Gmagick; +use Imagine\Gmagick\DriverInfo; use Imagine\Gmagick\Imagine; use Imagine\Test\Image\AbstractFontTest; @@ -22,15 +23,11 @@ class FontTest extends AbstractFontTest /** * {@inheritdoc} * - * @see \Imagine\Test\ImagineTestCaseBase::setUpBase() + * @see \Imagine\Driver\InfoProvider::getDriverInfo() */ - protected function setUpBase() + public static function getDriverInfo($required = true) { - parent::setUpBase(); - - if (!class_exists('Gmagick')) { - $this->markTestSkipped('Gmagick is not installed'); - } + return DriverInfo::get($required); } /** diff --git a/tests/tests/Gmagick/ImageTest.php b/tests/tests/Gmagick/ImageTest.php index 9ac2396e5..583bce6db 100644 --- a/tests/tests/Gmagick/ImageTest.php +++ b/tests/tests/Gmagick/ImageTest.php @@ -11,6 +11,7 @@ namespace Imagine\Test\Gmagick; +use Imagine\Gmagick\DriverInfo; use Imagine\Gmagick\Imagine; use Imagine\Image\ImageInterface; use Imagine\Test\Image\AbstractImageTest; @@ -20,6 +21,59 @@ */ class ImageTest extends AbstractImageTest { + /** + * {@inheritdoc} + * + * @see \Imagine\Test\ImagineTestCaseBase::setUpBase() + */ + protected function setUpBase() + { + parent::setUpBase(); + // disable GC while https://bugs.php.net/bug.php?id=63677 is still open + // If GC enabled, Gmagick unit tests fail + gc_disable(); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + */ + public static function getDriverInfo($required = true) + { + return DriverInfo::get($required); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImageTest::getImagine() + */ + protected function getImagine() + { + return new Imagine(); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImageTest::getImageResolution() + */ + protected function getImageResolution(ImageInterface $image) + { + return $image->getGmagick()->getimageresolution(); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImageTest::getSamplingFactors() + */ + protected function getSamplingFactors(ImageInterface $image) + { + return $image->getGmagick()->getSamplingFactors(); + } + /** * {@inheritdoc} * @@ -43,21 +97,8 @@ public function testJpegSamplingFactors() /** * {@inheritdoc} * - * @see \Imagine\Test\ImagineTestCaseBase::setUpBase() + * @see \Imagine\Test\Image\AbstractImageTest::provideFromAndToPalettes() */ - protected function setUpBase() - { - parent::setUpBase(); - - // disable GC while https://bugs.php.net/bug.php?id=63677 is still open - // If GC enabled, Gmagick unit tests fail - gc_disable(); - - if (!class_exists('Gmagick')) { - $this->markTestSkipped('Gmagick is not installed'); - } - } - public function provideFromAndToPalettes() { return array( @@ -74,6 +115,11 @@ public function provideFromAndToPalettes() ); } + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImageTest::providePalettes() + */ public function providePalettes() { return array( @@ -161,6 +207,8 @@ public function pasteWithAlphaProvider() * @dataProvider imageCompressionQualityProvider * * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImageTest::testSaveCompressionQuality() */ public function testSaveCompressionQuality($format, array $smallSizeOptions, array $bigSizeOptions) { @@ -171,19 +219,4 @@ public function testSaveCompressionQuality($format, array $smallSizeOptions, arr return parent::testSaveCompressionQuality($format, $smallSizeOptions, $bigSizeOptions); } - - protected function getImagine() - { - return new Imagine(); - } - - protected function getImageResolution(ImageInterface $image) - { - return $image->getGmagick()->getimageresolution(); - } - - protected function getSamplingFactors(ImageInterface $image) - { - return $image->getGmagick()->getSamplingFactors(); - } } diff --git a/tests/tests/Gmagick/ImagineTest.php b/tests/tests/Gmagick/ImagineTest.php index 35a6121f8..40f313674 100644 --- a/tests/tests/Gmagick/ImagineTest.php +++ b/tests/tests/Gmagick/ImagineTest.php @@ -11,6 +11,7 @@ namespace Imagine\Test\Gmagick; +use Imagine\Gmagick\DriverInfo; use Imagine\Gmagick\Imagine; use Imagine\Test\Image\AbstractImagineTest; @@ -22,15 +23,21 @@ class ImagineTest extends AbstractImagineTest /** * {@inheritdoc} * - * @see \Imagine\Test\ImagineTestCaseBase::setUpBase() + * @see \Imagine\Driver\InfoProvider::getDriverInfo() */ - protected function setUpBase() + public static function getDriverInfo($required = true) { - parent::setUpBase(); + return DriverInfo::get($required); + } - if (!class_exists('Gmagick')) { - $this->markTestSkipped('Gmagick is not installed'); - } + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImagineTest::getImagine() + */ + protected function getImagine() + { + return new Imagine(); } /** @@ -104,14 +111,4 @@ public function testShouldOpenAJxlImage() return parent::testShouldOpenAJxlImage(); } - - /** - * {@inheritdoc} - * - * @see \Imagine\Test\Image\AbstractImagineTest::getImagine() - */ - protected function getImagine() - { - return new Imagine(); - } } diff --git a/tests/tests/Gmagick/IsImageEqualTest.php b/tests/tests/Gmagick/IsImageEqualTest.php index dd48eaa03..6baf85aca 100644 --- a/tests/tests/Gmagick/IsImageEqualTest.php +++ b/tests/tests/Gmagick/IsImageEqualTest.php @@ -2,6 +2,7 @@ namespace Imagine\Test\Gmagick; +use Imagine\Gmagick\DriverInfo; use Imagine\Gmagick\Imagine; use Imagine\Test\Constraint\AbstractIsImageEqualTest; @@ -13,15 +14,11 @@ class IsImageEqualTest extends AbstractIsImageEqualTest /** * {@inheritdoc} * - * @see \Imagine\Test\ImagineTestCaseBase::setUpBase() + * @see \Imagine\Driver\InfoProvider::getDriverInfo() */ - protected function setUpBase() + public static function getDriverInfo($required = true) { - parent::setUpBase(); - - if (!class_exists('Gmagick')) { - $this->markTestSkipped('Gmagick is not installed'); - } + return DriverInfo::get($required); } /** diff --git a/tests/tests/Gmagick/LayersTest.php b/tests/tests/Gmagick/LayersTest.php index de5775a15..f8678814c 100644 --- a/tests/tests/Gmagick/LayersTest.php +++ b/tests/tests/Gmagick/LayersTest.php @@ -11,6 +11,7 @@ namespace Imagine\Test\Gmagick; +use Imagine\Gmagick\DriverInfo; use Imagine\Gmagick\Image; use Imagine\Gmagick\Imagine; use Imagine\Gmagick\Layers; @@ -27,17 +28,47 @@ class LayersTest extends AbstractLayersTest /** * {@inheritdoc} * - * @see \Imagine\Test\ImagineTestCaseBase::setUpBase() + * @see \Imagine\Driver\InfoProvider::getDriverInfo() */ - protected function setUpBase() + public static function getDriverInfo($required = true) { - parent::setUpBase(); + return DriverInfo::get($required); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractLayersTest::getImagine() + */ + protected function getImagine() + { + return new Imagine(); + } - if (!class_exists('Gmagick')) { - $this->markTestSkipped('Gmagick is not installed'); + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractLayersTest::getImage() + */ + protected function getImage($path = null) + { + if ($path) { + return new Image(new \Gmagick($path), new RGB(), new MetadataBag()); + } else { + return new Image(new \Gmagick(), new RGB(), new MetadataBag()); } } + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractLayersTest::assertLayersEquals() + */ + protected function assertLayersEquals(ImageInterface $expected, ImageInterface $actual) + { + $this->assertEquals($expected->getGmagick(), $actual->getGmagick()); + } + public function testCount() { $this->checkGmagickMockable(); @@ -88,30 +119,6 @@ public function testAnimateEmpty() $this->markTestSkipped('Animate empty is skipped due to https://bugs.php.net/bug.php?id=62309'); } - public function getImage($path = null) - { - if ($path) { - return new Image(new \Gmagick($path), new RGB(), new MetadataBag()); - } else { - return new Image(new \Gmagick(), new RGB(), new MetadataBag()); - } - } - - public function getImagine() - { - return new Imagine(); - } - - public function getLayers(ImageInterface $image, $resource) - { - return new Layers($image, $resource, new MetadataBag()); - } - - protected function assertLayersEquals($expected, $actual) - { - $this->assertEquals($expected->getGmagick(), $actual->getGmagick()); - } - /** * Check if the current Gmagick version is affected by the https://github.com/vitoc/gmagick/issues/55 bug. * diff --git a/tests/tests/Image/AbstractFontTest.php b/tests/tests/Image/AbstractFontTest.php index 33b1a5f2a..78cec7304 100644 --- a/tests/tests/Image/AbstractFontTest.php +++ b/tests/tests/Image/AbstractFontTest.php @@ -11,13 +11,23 @@ namespace Imagine\Test\Image; +use Imagine\Driver\Info; +use Imagine\Driver\InfoProvider; use Imagine\Image\Palette\RGB; use Imagine\Test\ImagineTestCase; -abstract class AbstractFontTest extends ImagineTestCase +abstract class AbstractFontTest extends ImagineTestCase implements InfoProvider { + /** + * @return \Imagine\Image\ImagineInterface + */ + abstract protected function getImagine(); + public function testShouldDetermineFontSize() { + if (!$this->getDriverInfo()->hasFeature(Info::FEATURE_TEXTFUNCTIONS)) { + $this->isGoingToThrowException('Imagine\Exception\NotSupportedException'); + } $palette = new RGB(); $path = IMAGINE_TEST_FIXTURESFOLDER . '/font/Arial.ttf'; $black = $palette->color('000'); @@ -53,13 +63,11 @@ public function fontWrapTextProvider() */ public function testFontWrapText($text, $maxWidth, $expectedText) { + if (!$this->getDriverInfo()->hasFeature(Info::FEATURE_TEXTFUNCTIONS)) { + $this->isGoingToThrowException('Imagine\Exception\NotSupportedException'); + } $palette = new RGB(); $font = $this->getImagine()->font(IMAGINE_TEST_FIXTURESFOLDER . '/font/Arial.ttf', 10, $palette->color('000')); $this->assertSame($expectedText, $font->wrapText($text, $maxWidth)); } - - /** - * @return \Imagine\Image\ImagineInterface - */ - abstract protected function getImagine(); } diff --git a/tests/tests/Image/AbstractImageTest.php b/tests/tests/Image/AbstractImageTest.php index cfa003c37..2ae26e09b 100644 --- a/tests/tests/Image/AbstractImageTest.php +++ b/tests/tests/Image/AbstractImageTest.php @@ -11,6 +11,7 @@ namespace Imagine\Test\Image; +use Imagine\Driver\InfoProvider; use Imagine\Image\Box; use Imagine\Image\Fill\Gradient\Horizontal; use Imagine\Image\ImageInterface; @@ -22,8 +23,27 @@ use Imagine\Image\Profile; use Imagine\Test\ImagineTestCase; -abstract class AbstractImageTest extends ImagineTestCase +abstract class AbstractImageTest extends ImagineTestCase implements InfoProvider { + /** + * @return \Imagine\Image\ImagineInterface + */ + abstract protected function getImagine(); + + /** + * @param ImageInterface $image + * + * @return array|null + */ + abstract protected function getImageResolution(ImageInterface $image); + + /** + * @param ImageInterface $image + * + * @return array|null + */ + abstract protected function getSamplingFactors(ImageInterface $image); + public function testPaletteIsRGBIfRGBImage() { $image = $this->getImagine()->open(IMAGINE_TEST_FIXTURESFOLDER . '/google.png'); @@ -1079,8 +1099,6 @@ public function testConvertingAnimgifToJpeg() $this->assertTrue((bool) preg_match("/^\xFF\xD8\XFF\xE0..JFIF$/", $relevantOutputImageBytes), 'Exported image is not in JPEG format'); } - abstract protected function getImageResolution(ImageInterface $image); - private function getMonoLayeredImage() { return $this->getImagine()->open(IMAGINE_TEST_FIXTURESFOLDER . '/google.png'); @@ -1095,16 +1113,4 @@ private function getInconsistentMultiLayeredImage() { return $this->getImagine()->open(IMAGINE_TEST_FIXTURESFOLDER . '/anima.gif'); } - - /** - * @return \Imagine\Image\ImagineInterface - */ - abstract protected function getImagine(); - - /** - * @param ImageInterface $image - * - * @return array - */ - abstract protected function getSamplingFactors(ImageInterface $image); } diff --git a/tests/tests/Image/AbstractImagineTest.php b/tests/tests/Image/AbstractImagineTest.php index 1322f9b64..6d031f885 100644 --- a/tests/tests/Image/AbstractImagineTest.php +++ b/tests/tests/Image/AbstractImagineTest.php @@ -11,14 +11,19 @@ namespace Imagine\Test\Image; +use Imagine\Driver\InfoProvider; use Imagine\Image\Box; -use Imagine\Image\ImagineInterface; use Imagine\Image\Palette\RGB; use Imagine\Image\Point; use Imagine\Test\ImagineTestCase; -abstract class AbstractImagineTest extends ImagineTestCase +abstract class AbstractImagineTest extends ImagineTestCase implements InfoProvider { + /** + * @return \Imagine\Image\ImagineInterface + */ + abstract protected function getImagine(); + public function testShouldCreateEmptyImage() { $factory = $this->getImagine(); @@ -233,9 +238,4 @@ public function testCreateAlphaPrecision() $actualColor = $image->getColorAt(new Point(0, 0)); $this->assertEquals(17, $actualColor->getAlpha()); } - - /** - * @return ImagineInterface - */ - abstract protected function getImagine(); } diff --git a/tests/tests/Image/AbstractLayersTest.php b/tests/tests/Image/AbstractLayersTest.php index 537a82673..0f9f137ff 100644 --- a/tests/tests/Image/AbstractLayersTest.php +++ b/tests/tests/Image/AbstractLayersTest.php @@ -11,15 +11,29 @@ namespace Imagine\Test\Image; +use Imagine\Driver\InfoProvider; use Imagine\Image\Box; use Imagine\Image\ImageInterface; -use Imagine\Image\ImagineInterface; use Imagine\Image\Palette\RGB; use Imagine\Image\Point; use Imagine\Test\ImagineTestCase; -abstract class AbstractLayersTest extends ImagineTestCase +abstract class AbstractLayersTest extends ImagineTestCase implements InfoProvider { + /** + * @return \Imagine\Image\ImagineInterface + */ + abstract protected function getImagine(); + + /** + * @param string|null $path + * + * @return \Imagine\Image\ImageInterface + */ + abstract protected function getImage($path = null); + + abstract protected function assertLayersEquals(ImageInterface $expected, ImageInterface $actual); + public function testMerge() { $palette = new RGB(); @@ -258,18 +272,4 @@ public function provideOutOfBoundsArguments() array(2), ); } - - /** - * @param string|null $path - * - * @return ImageInterface - */ - abstract protected function getImage($path = null); - - /** - * @return ImagineInterface - */ - abstract protected function getImagine(); - - abstract protected function assertLayersEquals($expected, $actual); } diff --git a/tests/tests/Imagick/AlphaBlendingAwareDrawerTest.php b/tests/tests/Imagick/AlphaBlendingAwareDrawerTest.php index 3ef533559..ccaa8b2ec 100644 --- a/tests/tests/Imagick/AlphaBlendingAwareDrawerTest.php +++ b/tests/tests/Imagick/AlphaBlendingAwareDrawerTest.php @@ -2,6 +2,7 @@ namespace Imagine\Test\Imagick; +use Imagine\Imagick\DriverInfo; use Imagine\Imagick\Imagine; use Imagine\Test\Draw\AbstractAlphaBlendingAwareDrawerTest; @@ -14,14 +15,11 @@ class AlphaBlendingAwareDrawerTest extends AbstractAlphaBlendingAwareDrawerTest /** * {@inheritdoc} * - * @see \Imagine\Test\ImagineTestCaseBase::setUpBase() + * @see \Imagine\Driver\InfoProvider::getDriverInfo() */ - protected function setUpBase() + public static function getDriverInfo($required = true) { - if (!class_exists('Imagick')) { - $this->markTestSkipped('Imagick is not installed'); - } - parent::setUpBase(); + return DriverInfo::get($required); } /** diff --git a/tests/tests/Imagick/ClassFactoryTest.php b/tests/tests/Imagick/ClassFactoryTest.php index 945ae02ee..b3e94b721 100644 --- a/tests/tests/Imagick/ClassFactoryTest.php +++ b/tests/tests/Imagick/ClassFactoryTest.php @@ -11,6 +11,7 @@ namespace Imagine\Test\Imagick; +use Imagine\Imagick\DriverInfo; use Imagine\Imagick\Imagine; use Imagine\Test\Factory\AbstractClassFactoryTest; @@ -22,17 +23,18 @@ class ClassFactoryTest extends AbstractClassFactoryTest /** * {@inheritdoc} * - * @see \Imagine\Test\ImagineTestCaseBase::setUpBase() + * @see \Imagine\Driver\InfoProvider::getDriverInfo() */ - protected function setUpBase() + public static function getDriverInfo($required = true) { - parent::setUpBase(); - - if (!class_exists('Imagick')) { - $this->markTestSkipped('Imagick is not installed'); - } + return DriverInfo::get($required); } + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Factory\AbstractClassFactoryTest::getImagine() + */ protected function getImagine() { return new Imagine(); diff --git a/tests/tests/Imagick/DrawerTest.php b/tests/tests/Imagick/DrawerTest.php index 6fa0c4832..a81c99199 100644 --- a/tests/tests/Imagick/DrawerTest.php +++ b/tests/tests/Imagick/DrawerTest.php @@ -11,6 +11,7 @@ namespace Imagine\Test\Imagick; +use Imagine\Imagick\DriverInfo; use Imagine\Imagick\Imagine; use Imagine\Test\Draw\AbstractDrawerTest; @@ -22,24 +23,20 @@ class DrawerTest extends AbstractDrawerTest /** * {@inheritdoc} * - * @see \Imagine\Test\ImagineTestCaseBase::setUpBase() + * @see \Imagine\Driver\InfoProvider::getDriverInfo() */ - protected function setUpBase() + public static function getDriverInfo($required = true) { - parent::setUpBase(); - - if (!class_exists('Imagick')) { - $this->markTestSkipped('Imagick is not installed'); - } + return DriverInfo::get($required); } + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Draw\AbstractDrawerTest::getImagine() + */ protected function getImagine() { return new Imagine(); } - - protected function isFontTestSupported() - { - return true; - } } diff --git a/tests/tests/Imagick/DriverInfoTest.php b/tests/tests/Imagick/DriverInfoTest.php new file mode 100644 index 000000000..1fee85ca6 --- /dev/null +++ b/tests/tests/Imagick/DriverInfoTest.php @@ -0,0 +1,39 @@ +getImageMagickSemVerVersion(), '6.8.5') < 0) { - $this->markTestSkipped("ImageMagick is too old (current version: {$version->getImageMagickFullVersion()}, minimum version: 6.8.5)"); - } - parent::testGrayscale(); + return DriverInfo::get($required); } /** * {@inheritdoc} * - * @see \Imagine\Test\ImagineTestCaseBase::setUpBase() + * @see \Imagine\Test\Effects\AbstractEffectsTest::getImagine() */ - protected function setUpBase() - { - parent::setUpBase(); - - if (!class_exists('Imagick')) { - $this->markTestSkipped('Imagick is not installed'); - } - } - protected function getImagine() { return new Imagine(); diff --git a/tests/tests/Imagick/FontTest.php b/tests/tests/Imagick/FontTest.php index 7ea2f3bed..836805f3d 100644 --- a/tests/tests/Imagick/FontTest.php +++ b/tests/tests/Imagick/FontTest.php @@ -11,6 +11,7 @@ namespace Imagine\Test\Imagick; +use Imagine\Imagick\DriverInfo; use Imagine\Imagick\Imagine; use Imagine\Test\Image\AbstractFontTest; @@ -22,15 +23,11 @@ class FontTest extends AbstractFontTest /** * {@inheritdoc} * - * @see \Imagine\Test\ImagineTestCaseBase::setUpBase() + * @see \Imagine\Driver\InfoProvider::getDriverInfo() */ - protected function setUpBase() + public static function getDriverInfo($required = true) { - parent::setUpBase(); - - if (!class_exists('Imagick')) { - $this->markTestSkipped('Imagick is not installed'); - } + return DriverInfo::get($required); } /** diff --git a/tests/tests/Imagick/ImageTest.php b/tests/tests/Imagick/ImageTest.php index 59a7e6e95..c335ec619 100644 --- a/tests/tests/Imagick/ImageTest.php +++ b/tests/tests/Imagick/ImageTest.php @@ -13,11 +13,9 @@ use Imagine\Image\Box; use Imagine\Image\ImageInterface; -use Imagine\Image\Metadata\MetadataBag; -use Imagine\Image\Palette\CMYK; use Imagine\Image\Palette\RGB; use Imagine\Image\Point; -use Imagine\Imagick\Image; +use Imagine\Imagick\DriverInfo; use Imagine\Imagick\Imagine; use Imagine\Test\Image\AbstractImageTest; @@ -26,6 +24,46 @@ */ class ImageTest extends AbstractImageTest { + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + */ + public static function getDriverInfo($required = true) + { + return DriverInfo::get($required); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImageTest::getImagine() + */ + protected function getImagine() + { + return new Imagine(); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImageTest::getImageResolution() + */ + protected function getImageResolution(ImageInterface $image) + { + return $image->getImagick()->getImageResolution(); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImageTest::getSamplingFactors() + */ + protected function getSamplingFactors(ImageInterface $image) + { + return $image->getImagick()->getSamplingFactors(); + } + /** * @dataProvider provideFromAndToPalettes * @@ -109,41 +147,6 @@ public function testResolutionOnSave($source) parent::testResolutionOnSave($source); } - /** - * {@inheritdoc} - * - * @see \Imagine\Test\ImagineTestCaseBase::setUpBase() - */ - protected function setUpBase() - { - parent::setUpBase(); - - if (!class_exists('Imagick')) { - $this->markTestSkipped('Imagick is not installed'); - } - } - - /** - * {@inheritdoc} - * - * @see \Imagine\Test\ImagineTestCaseBase::tearDownBase() - */ - protected function tearDownBase() - { - if (class_exists('Imagick')) { - $prop = new \ReflectionProperty('Imagine\Imagick\Image', 'supportsColorspaceConversion'); - $prop->setAccessible(true); - $prop->setValue(null); - } - - parent::tearDownBase(); - } - - protected function getImagine() - { - return new Imagine(); - } - /** * @doesNotPerformAssertions */ @@ -181,39 +184,6 @@ public function testAnimatedGifResize() ); } - /** - * Older imagemagick versions does not support colorspace conversion. - * - * @doesNotPerformAssertions - * - * @return \Imagine\Imagick\Image - */ - public function testOlderImageMagickDoesNotAffectColorspaceUsageOnConstruct() - { - $palette = new CMYK(); - $imagick = $this->getMockBuilder('\Imagick')->getMock(); - $imagick->expects($this->any()) - ->method('setColorspace') - ->will($this->throwException(new \RuntimeException('Method not supported'))); - - $prop = new \ReflectionProperty('Imagine\Imagick\Image', 'supportsColorspaceConversion'); - $prop->setAccessible(true); - $prop->setValue(false); - - return new Image($imagick, $palette, new MetadataBag()); - } - - /** - * @depends testOlderImageMagickDoesNotAffectColorspaceUsageOnConstruct - * - * @param mixed $image - */ - public function testOlderImageMagickDoesNotAffectColorspaceUsageOnPaletteChange($image) - { - $this->isGoingToThrowException('Imagine\Exception\RuntimeException', 'Your version of Imagick does not support colorspace conversions.'); - $image->usePalette(new RGB()); - } - public function testAnimatedGifCrop() { $imagine = $this->getImagine(); @@ -274,14 +244,4 @@ public function testOptimizeWithDifferentFrameSizes() $filename = $this->getTemporaryFilename('.gif'); $image->save($filename, array('animated' => true, 'optimize' => true)); } - - protected function getImageResolution(ImageInterface $image) - { - return $image->getImagick()->getImageResolution(); - } - - protected function getSamplingFactors(ImageInterface $image) - { - return $image->getImagick()->getSamplingFactors(); - } } diff --git a/tests/tests/Imagick/ImagineTest.php b/tests/tests/Imagick/ImagineTest.php index 70959cf5a..ee701b63d 100644 --- a/tests/tests/Imagick/ImagineTest.php +++ b/tests/tests/Imagick/ImagineTest.php @@ -11,6 +11,7 @@ namespace Imagine\Test\Imagick; +use Imagine\Imagick\DriverInfo; use Imagine\Imagick\Imagine; use Imagine\Test\Image\AbstractImagineTest; @@ -22,15 +23,21 @@ class ImagineTest extends AbstractImagineTest /** * {@inheritdoc} * - * @see \Imagine\Test\ImagineTestCaseBase::setUpBase() + * @see \Imagine\Driver\InfoProvider::getDriverInfo() */ - protected function setUpBase() + public static function getDriverInfo($required = true) { - parent::setUpBase(); + return DriverInfo::get($required); + } - if (!class_exists('Imagick')) { - $this->markTestSkipped('Imagick is not installed'); - } + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractImagineTest::getImagine() + */ + protected function getImagine() + { + return new Imagine(); } /** @@ -88,14 +95,4 @@ public function testShouldOpenAJxlImage() return parent::testShouldOpenAJxlImage(); } - - /** - * {@inheritdoc} - * - * @see \Imagine\Test\Image\AbstractImagineTest::getImagine() - */ - protected function getImagine() - { - return new Imagine(); - } } diff --git a/tests/tests/Imagick/IsImageEqualTest.php b/tests/tests/Imagick/IsImageEqualTest.php index f0ce80b36..c88ebbd47 100644 --- a/tests/tests/Imagick/IsImageEqualTest.php +++ b/tests/tests/Imagick/IsImageEqualTest.php @@ -2,6 +2,7 @@ namespace Imagine\Test\Imagick; +use Imagine\Imagick\DriverInfo; use Imagine\Imagick\Imagine; use Imagine\Test\Constraint\AbstractIsImageEqualTest; @@ -13,15 +14,11 @@ class IsImageEqualTest extends AbstractIsImageEqualTest /** * {@inheritdoc} * - * @see \Imagine\Test\ImagineTestCaseBase::setUpBase() + * @see \Imagine\Driver\InfoProvider::getDriverInfo() */ - protected function setUpBase() + public static function getDriverInfo($required = true) { - parent::setUpBase(); - - if (!class_exists('Imagick')) { - $this->markTestSkipped('Imagick is not installed'); - } + return DriverInfo::get($required); } /** diff --git a/tests/tests/Imagick/LayersTest.php b/tests/tests/Imagick/LayersTest.php index 9eeb90fa0..3454aadea 100644 --- a/tests/tests/Imagick/LayersTest.php +++ b/tests/tests/Imagick/LayersTest.php @@ -11,8 +11,10 @@ namespace Imagine\Test\Imagick; +use Imagine\Image\ImageInterface; use Imagine\Image\Metadata\MetadataBag; use Imagine\Image\Palette\RGB; +use Imagine\Imagick\DriverInfo; use Imagine\Imagick\Image; use Imagine\Imagick\Imagine; use Imagine\Imagick\Layers; @@ -26,17 +28,47 @@ class LayersTest extends AbstractLayersTest /** * {@inheritdoc} * - * @see \Imagine\Test\ImagineTestCaseBase::setUpBase() + * @see \Imagine\Driver\InfoProvider::getDriverInfo() */ - protected function setUpBase() + public static function getDriverInfo($required = true) { - parent::setUpBase(); + return DriverInfo::get($required); + } - if (!class_exists('Imagick')) { - $this->markTestSkipped('Imagick is not installed'); + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractLayersTest::getImagine() + */ + protected function getImagine() + { + return new Imagine(); + } + + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractLayersTest::getImage() + */ + protected function getImage($path = null) + { + if ($path) { + return new Image(new \Imagick($path), new RGB(), new MetadataBag()); + } else { + return new Image(new \Imagick(), new RGB(), new MetadataBag()); } } + /** + * {@inheritdoc} + * + * @see \Imagine\Test\Image\AbstractLayersTest::assertLayersEquals() + */ + protected function assertLayersEquals(ImageInterface $expected, ImageInterface $actual) + { + $this->assertEquals($expected->getImagick(), $actual->getImagick()); + } + public function testCount() { $palette = new RGB(); @@ -102,23 +134,4 @@ public function testCoalesce() } } } - - public function getImage($path = null) - { - if ($path) { - return new Image(new \Imagick($path), new RGB(), new MetadataBag()); - } else { - return new Image(new \Imagick(), new RGB(), new MetadataBag()); - } - } - - protected function getImagine() - { - return new Imagine(); - } - - protected function assertLayersEquals($expected, $actual) - { - $this->assertEquals($expected->getImagick(), $actual->getImagick()); - } } diff --git a/tests/tests/ImagineTestCaseBase.php b/tests/tests/ImagineTestCaseBase.php index be41eeea0..afe26b04e 100644 --- a/tests/tests/ImagineTestCaseBase.php +++ b/tests/tests/ImagineTestCaseBase.php @@ -11,6 +11,8 @@ namespace Imagine\Test; +use Imagine\Driver\InfoProvider; +use Imagine\Exception\NotSupportedException; use Imagine\Image\ImagineInterface; use Imagine\Test\Constraint\IsBoxInRange; use Imagine\Test\Constraint\IsColorSimilar; @@ -152,6 +154,13 @@ protected static function tearDownAfterClassBase() */ protected function setUpBase() { + if ($this instanceof InfoProvider) { + try { + $this->getDriverInfo()->checkVersionIsSupported(); + } catch (NotSupportedException $x) { + $this->markTestSkipped($x->getMessage()); + } + } } /** diff --git a/tests/tests/Issues/Issue131Test.php b/tests/tests/Issues/Issue131Test.php index 1fc3a3cf4..070244f17 100644 --- a/tests/tests/Issues/Issue131Test.php +++ b/tests/tests/Issues/Issue131Test.php @@ -2,8 +2,11 @@ namespace Imagine\Test\Issues; +use Imagine\Exception\NotSupportedException; use Imagine\Exception\RuntimeException; +use Imagine\Gmagick\DriverInfo as GmagickDriverInfo; use Imagine\Gmagick\Imagine as GmagickImagine; +use Imagine\Imagick\DriverInfo as ImagickDriverInfo; use Imagine\Imagick\Imagine as ImagickImagine; use Imagine\Test\ImagineTestCase; @@ -35,25 +38,31 @@ private function getDirContent($dir) private function getImagickImagine($file) { try { - $imagine = new ImagickImagine(); - $image = $imagine->open($file); - } catch (RuntimeException $e) { - $this->markTestSkipped($e->getMessage()); + ImagickDriverInfo::get()->checkVersionIsSupported(); + } catch (NotSupportedException $x) { + $this->markTestSkipped($x->getMessage()); + } + $imagine = new ImagickImagine(); + try { + return $imagine->open($file); + } catch (RuntimeException $x) { + $this->markTestSkipped($x->getMessage()); } - - return $image; } private function getGmagickImagine($file) { try { - $imagine = new GmagickImagine(); - $image = $imagine->open($file); - } catch (RuntimeException $e) { - $this->markTestSkipped($e->getMessage()); + GmagickDriverInfo::get()->checkVersionIsSupported(); + } catch (NotSupportedException $x) { + $this->markTestSkipped($x->getMessage()); + } + $imagine = new GmagickImagine(); + try { + return $imagine->open($file); + } catch (RuntimeException $x) { + $this->markTestSkipped($x->getMessage()); } - - return $image; } /** diff --git a/tests/tests/Issues/Issue17Test.php b/tests/tests/Issues/Issue17Test.php index adb24d1dc..cdeea7be9 100644 --- a/tests/tests/Issues/Issue17Test.php +++ b/tests/tests/Issues/Issue17Test.php @@ -2,7 +2,8 @@ namespace Imagine\Test\Issues; -use Imagine\Exception\RuntimeException; +use Imagine\Driver\InfoProvider; +use Imagine\Gd\DriverInfo; use Imagine\Gd\Imagine; use Imagine\Image\Box; use Imagine\Image\ImageInterface; @@ -11,23 +12,22 @@ /** * @group gd */ -class Issue17Test extends ImagineTestCase +class Issue17Test extends ImagineTestCase implements InfoProvider { - private function getImagine() + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + */ + public static function getDriverInfo($required = true) { - try { - $imagine = new Imagine(); - } catch (RuntimeException $e) { - $this->markTestSkipped($e->getMessage()); - } - - return $imagine; + return DriverInfo::get($required); } public function testShouldResize() { $size = new Box(100, 10); - $imagine = $this->getImagine(); + $imagine = new Imagine(); $imagine->open(IMAGINE_TEST_FIXTURESFOLDER . '/large.jpg') ->thumbnail($size, ImageInterface::THUMBNAIL_OUTBOUND) diff --git a/tests/tests/Issues/Issue59Test.php b/tests/tests/Issues/Issue59Test.php index 21374321a..226a076cb 100644 --- a/tests/tests/Issues/Issue59Test.php +++ b/tests/tests/Issues/Issue59Test.php @@ -2,29 +2,29 @@ namespace Imagine\Test\Issues; -use Imagine\Exception\RuntimeException; +use Imagine\Driver\InfoProvider; +use Imagine\Gd\DriverInfo; use Imagine\Gd\Imagine; use Imagine\Test\ImagineTestCase; /** * @group gd */ -class Issue59Test extends ImagineTestCase +class Issue59Test extends ImagineTestCase implements InfoProvider { - private function getImagine() + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + */ + public static function getDriverInfo($required = true) { - try { - $imagine = new Imagine(); - } catch (RuntimeException $e) { - $this->markTestSkipped($e->getMessage()); - } - - return $imagine; + return DriverInfo::get($required); } public function testShouldResize() { - $imagine = $this->getImagine(); + $imagine = new Imagine(); $new = $this->getTemporaryFilename('.jpeg'); $imagine diff --git a/tests/tests/Issues/Issue67Test.php b/tests/tests/Issues/Issue67Test.php index 835f87ad1..fae532051 100644 --- a/tests/tests/Issues/Issue67Test.php +++ b/tests/tests/Issues/Issue67Test.php @@ -2,24 +2,24 @@ namespace Imagine\Test\Issues; -use Imagine\Exception\RuntimeException; +use Imagine\Driver\InfoProvider; +use Imagine\Gd\DriverInfo; use Imagine\Gd\Imagine; use Imagine\Test\ImagineTestCase; /** * @group gd */ -class Issue67Test extends ImagineTestCase +class Issue67Test extends ImagineTestCase implements InfoProvider { - private function getImagine() + /** + * {@inheritdoc} + * + * @see \Imagine\Driver\InfoProvider::getDriverInfo() + */ + public static function getDriverInfo($required = true) { - try { - $imagine = new Imagine(); - } catch (RuntimeException $e) { - $this->markTestSkipped($e->getMessage()); - } - - return $imagine; + return DriverInfo::get($required); } public function testShouldThrowExceptionNotError() @@ -27,7 +27,7 @@ public function testShouldThrowExceptionNotError() $this->isGoingToThrowException('Imagine\Exception\RuntimeException'); $invalidPath = '/thispathdoesnotexist'; - $imagine = $this->getImagine(); + $imagine = new Imagine(); $imagine->open(IMAGINE_TEST_FIXTURESFOLDER . '/large.jpg') ->save($invalidPath . '/myfile.jpg');