diff --git a/core/core.services.yml b/core/core.services.yml index 6f8cce6..8cfa7fb 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -492,6 +492,9 @@ services: class: Drupal\system\Plugin\ImageToolkitInterface factory_method: getDefaultToolkit factory_service: image.toolkit.manager + image.factory: + class: Drupal\Core\Image\ImageFactory + arguments: ['@image.toolkit'] breadcrumb: class: Drupal\Core\Breadcrumb\BreadcrumbManager token: diff --git a/core/includes/common.inc b/core/includes/common.inc index c513411..21455bf 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -3083,7 +3083,6 @@ function _drupal_bootstrap_code() { require_once __DIR__ . '/tablesort.inc'; require_once __DIR__ . '/file.inc'; require_once __DIR__ . '/unicode.inc'; - require_once __DIR__ . '/image.inc'; require_once __DIR__ . '/form.inc'; require_once __DIR__ . '/mail.inc'; require_once __DIR__ . '/ajax.inc'; diff --git a/core/includes/image.inc b/core/includes/image.inc deleted file mode 100644 index 9e2d06f..0000000 --- a/core/includes/image.inc +++ /dev/null @@ -1,332 +0,0 @@ -source = $filepath; - $image->toolkit = $toolkit; - $details = $toolkit->getInfo($image); - if (isset($details) && is_array($details)) { - $details['file_size'] = filesize($filepath); - } - } - - return $details; -} - -/** - * Scales an image to the exact width and height given. - * - * This function achieves the target aspect ratio by cropping the original image - * equally on both sides, or equally on the top and bottom. This function is - * useful to create uniform sized avatars from larger images. - * - * The resulting image always has the exact target dimensions. - * - * @param object $image - * An image object returned by image_load(). - * @param int $width - * The target width, in pixels. - * @param int $height - * The target height, in pixels. - * - * @return bool - * TRUE on success, FALSE on failure. - * - * @see image_load() - * @see image_resize() - * @see image_crop() - */ -function image_scale_and_crop($image, $width, $height) { - $scale = max($width / $image->info['width'], $height / $image->info['height']); - $x = ($image->info['width'] * $scale - $width) / 2; - $y = ($image->info['height'] * $scale - $height) / 2; - - if (image_resize($image, $image->info['width'] * $scale, $image->info['height'] * $scale)) { - return image_crop($image, $x, $y, $width, $height); - } - return FALSE; -} - -/** - * Scales image dimensions while maintaining aspect ratio. - * - * @deprecated as of Drupal 8.0. Use - * \Drupal\Component\Image\Image::scaleDimensions() directly instead. - * - * @see image_scale() - */ -function image_dimensions_scale(array &$dimensions, $width = NULL, $height = NULL, $upscale = FALSE) { - return Image::scaleDimensions($dimensions, $width, $height, $upscale); -} - -/** - * Scales an image while maintaining aspect ratio. - * - * The resulting image can be smaller for one or both target dimensions. - * - * @param object $image - * An image object returned by image_load(). - * @param int $width - * (optional) The target width, in pixels. This value is omitted then the - * scaling will based only on the height value. - * @param int $height - * (optional) The target height, in pixels. This value is omitted then the - * scaling will based only on the width value. - * @param bool $upscale - * (optional) Boolean indicating that files smaller than the dimensions will - * be scaled up. This generally results in a low quality image. - * - * @return bool - * TRUE on success, FALSE on failure. - * - * @see image_dimensions_scale() - * @see image_load() - * @see image_scale_and_crop() - */ -function image_scale($image, $width = NULL, $height = NULL, $upscale = FALSE) { - $dimensions = $image->info; - - // Scale the dimensions - if they don't change then just return success. - if (!image_dimensions_scale($dimensions, $width, $height, $upscale)) { - return TRUE; - } - - return image_resize($image, $dimensions['width'], $dimensions['height']); -} - -/** - * Resizes an image to the given dimensions (ignoring aspect ratio). - * - * @param object $image - * An image object returned by image_load(). - * @param int $width - * The target width, in pixels. - * @param int $height - * The target height, in pixels. - * - * @return bool - * TRUE on success, FALSE on failure. - * - * @see image_load() - * @see \Drupal\system\Plugin\ImageToolkitInterface::resize() - */ -function image_resize($image, $width, $height) { - $width = (int) round($width); - $height = (int) round($height); - - return $image->toolkit->resize($image, $width, $height); -} - -/** - * Rotates an image by the given number of degrees. - * - * @param $image - * An image object returned by image_load(). - * @param int $degrees - * The number of (clockwise) degrees to rotate the image. - * @param string $background - * (optional) An hexadecimal integer specifying the background color to use - * for the uncovered area of the image after the rotation. E.g. 0x000000 for - * black, 0xff00ff for magenta, and 0xffffff for white. For images that - * support transparency, this will default to transparent. Otherwise it will - * be white. - * - * @return bool - * TRUE on success, FALSE on failure. - * - * @see image_load() - * @see \Drupal\system\Plugin\ImageToolkitInterface::rotate() - */ -function image_rotate($image, $degrees, $background = NULL) { - return $image->toolkit->rotate($image, $degrees, $background); -} - -/** - * Crops an image to a rectangle specified by the given dimensions. - * - * @param $image - * An image object returned by image_load(). - * @param int $x - * The top left coordinate, in pixels, of the crop area (x axis value). - * @param int $y - * The top left coordinate, in pixels, of the crop area (y axis value). - * @param int $width - * The target width, in pixels. - * @param int $height - * The target height, in pixels. - * - * @return bool - * TRUE on success, FALSE on failure. - * - * @see image_load() - * @see image_scale_and_crop() - * @see \Drupal\system\Plugin\ImageToolkitInterface::crop() - */ -function image_crop($image, $x, $y, $width, $height) { - $aspect = $image->info['height'] / $image->info['width']; - if (empty($height)) $height = $width / $aspect; - if (empty($width)) $width = $height * $aspect; - - $width = (int) round($width); - $height = (int) round($height); - - return $image->toolkit->crop($image, $x, $y, $width, $height); -} - -/** - * Converts an image to grayscale. - * - * @param $image - * An image object returned by image_load(). - * - * @return bool - * TRUE on success, FALSE on failure. - * - * @see image_load() - * @see \Drupal\system\Plugin\ImageToolkitInterface::desaturate() - */ -function image_desaturate($image) { - return $image->toolkit->desaturate($image); -} - -/** - * Loads an image file and returns an image object. - * - * Any changes to the file are not saved until image_save() is called. - * - * @param string $file - * Path to an image file. - * @param \Drupal\system\Plugin\ImageToolkitInterface $toolkit - * (optional) Image toolkit object to override the default. - * - * @return object - * An image object or FALSE if there was a problem loading the file. The - * image object has the following properties: - * - 'source' - The original file path. - * - 'info' - The array of information returned by image_get_info() - * - 'toolkit' - The name of the image toolkit requested when the image was - * loaded. - * Image toolkits may add additional properties. The caller is advised not to - * monkey about with them. - * - * @see image_save() - * @see image_get_info() - */ -function image_load($file, ImageToolkitInterface $toolkit = NULL) { - if ($toolkit === NULL) { - $toolkit = Drupal::service('image.toolkit'); - } - if ($toolkit) { - $image = new stdClass(); - $image->source = $file; - $image->info = image_get_info($file, $toolkit); - if (isset($image->info) && is_array($image->info)) { - $image->toolkit = $toolkit; - if ($toolkit->load($image)) { - return $image; - } - } - } - return FALSE; -} - -/** - * Closes the image and saves the changes to a file. - * - * @param object $image - * An image object returned by image_load(). The object's 'info' property - * will be updated if the file is saved successfully. - * @param $destination - * (optional) Destination path where the image should be saved. If it is empty - * the original image file will be overwritten. - * - * @return bool - * TRUE on success, FALSE on failure. - * - * @see image_load() - * @see \Drupal\system\Plugin\ImageToolkitInterface::save() - */ -function image_save($image, $destination = NULL) { - if (empty($destination)) { - $destination = $image->source; - } - if ($return = $image->toolkit->save($image, $destination)) { - // Clear the cached file size and refresh the image information. - clearstatcache(TRUE, $destination); - $image->info = image_get_info($destination, $image->toolkit); - - if (drupal_chmod($destination)) { - return $return; - } - } - return FALSE; -} - -/** - * @} End of "defgroup image". - */ diff --git a/core/lib/Drupal/Component/Image/Image.php b/core/lib/Drupal/Component/Utility/Image.php similarity index 96% rename from core/lib/Drupal/Component/Image/Image.php rename to core/lib/Drupal/Component/Utility/Image.php index 635b374..dd06806 100644 --- a/core/lib/Drupal/Component/Image/Image.php +++ b/core/lib/Drupal/Component/Utility/Image.php @@ -2,10 +2,10 @@ /** * @file - * Contains \Drupal\Component\Image\Image. + * Contains \Drupal\Component\Utility\Image. */ -namespace Drupal\Component\Image; +namespace Drupal\Component\Utility; /** * Provides helpers to operate on images. diff --git a/core/lib/Drupal/Core/Image/Image.php b/core/lib/Drupal/Core/Image/Image.php new file mode 100644 index 0000000..4d0a167 --- /dev/null +++ b/core/lib/Drupal/Core/Image/Image.php @@ -0,0 +1,347 @@ +source = $source; + $this->toolkit = $toolkit; + } + + /** + * {@inheritdoc} + */ + public function getExtension() { + $this->processInfo(); + return $this->extension; + } + + /** + * {@inheritdoc} + */ + public function getHeight() { + $this->processInfo(); + return $this->height; + } + + /** + * {@inheritdoc} + */ + public function setHeight($height) { + $this->height = $height; + return $this; + } + + /** + * {@inheritdoc} + */ + public function getWidth() { + $this->processInfo(); + return $this->width; + } + + /** + * {@inheritdoc} + */ + public function setWidth($width) { + $this->width = $width; + return $this; + } + + /** + * {@inheritdoc} + */ + public function getFileSize() { + $this->processInfo(); + return $this->fileSize; + } + + /** + * {@inheritdoc} + */ + public function getMimeType() { + $this->processInfo(); + return $this->mimeType; + } + + /** + * {@inheritdoc} + */ + public function setResource($resource) { + $this->resource = $resource; + return $this; + } + + /** + * {@inheritdoc} + */ + public function hasResource() { + return (bool) $this->resource; + } + + /** + * {@inheritdoc} + */ + public function getResource() { + if (!$this->hasResource()) { + $this->processInfo(); + $this->toolkit->load($this); + } + return $this->resource; + } + + /** + * {@inheritdoc} + */ + public function setSource($source) { + $this->source = $source; + return $this; + } + + /** + * {@inheritdoc} + */ + public function getSource() { + return $this->source; + } + + /** + * {@inheritdoc} + */ + public function getToolkitId() { + return $this->toolkit->getPluginId(); + } + + /** + * {@inheritdoc} + */ + public function save($destination = NULL) { + if (empty($destination)) { + $destination = $this->getSource(); + } + if ($return = $this->toolkit->save($this, $destination)) { + // Clear the cached file size and refresh the image information. + clearstatcache(TRUE, $destination); + $this->setSource($destination); + $this->processInfo(); + + // @todo Use injected File utility when https://drupal.org/node/2050759 is + // in. + if ($this->chmod($destination)) { + return $return; + } + } + return FALSE; + } + + /** + * Prepares the image information. + * + * Drupal supports GIF, JPG and PNG file formats when used with the GD + * toolkit, and may support others, depending on which toolkits are + * installed. + * + * @return bool + * FALSE, if the file could not be found or is not an image. Otherwise, the + * image information is populated. + */ + protected function processInfo() { + if ($this->processed) { + return TRUE; + } + + $destination = $this->getSource(); + if (!is_file($destination) && !is_uploaded_file($destination)) { + return FALSE; + } + + if ($details = $this->toolkit->getInfo($this)) { + $this->height = $details['height']; + $this->width = $details['width']; + $this->extension = $details['extension']; + $this->mimeType = $details['mime_type']; + $this->fileSize = filesize($destination); + $this->processed = TRUE; + } + return TRUE; + } + + /** + * {@inheritdoc} + */ + public function scale($width = NULL, $height = NULL, $upscale = FALSE) { + $dimensions = array( + 'width' => $this->getWidth(), + 'height' => $this->getHeight(), + ); + + // Scale the dimensions - if they don't change then just return success. + if (!ImageUtility::scaleDimensions($dimensions, $width, $height, $upscale)) { + return TRUE; + } + + return $this->resize($dimensions['width'], $dimensions['height']); + + } + + /** + * {@inheritdoc} + */ + public function scaleAndCrop($width, $height) { + $scale = max($width / $this->getWidth(), $height / $this->getHeight()); + $x = ($this->getWidth() * $scale - $width) / 2; + $y = ($this->getHeight() * $scale - $height) / 2; + + if ($this->resize($this->getWidth() * $scale, $this->getHeight() * $scale)) { + return $this->crop($x, $y, $width, $height); + } + return FALSE; + } + + /** + * {@inheritdoc} + */ + public function crop($x, $y, $width, $height) { + $aspect = $this->getHeight() / $this->getWidth(); + if (empty($height)) $height = $width * $aspect; + if (empty($width)) $width = $height / $aspect; + + $width = (int) round($width); + $height = (int) round($height); + + return $this->toolkit->crop($this, $x, $y, $width, $height); + } + + /** + * {@inheritdoc} + */ + public function resize($width, $height) { + $width = (int) round($width); + $height = (int) round($height); + + return $this->toolkit->resize($this, $width, $height); + } + + /** + * {@inheritdoc} + */ + public function desaturate() { + return $this->toolkit->desaturate($this); + } + + /** + * {@inheritdoc} + */ + public function rotate($degrees, $background = NULL) { + return $this->toolkit->rotate($this, $degrees, $background); + } + + /** + * Wrapper to drupal_chmod() to allow unit testing. + * + * @param string $uri + * A string containing a URI file, or directory path. + * @param int $mode + * Integer value for the permissions. Consult PHP chmod() documentation for + * more information. + * + * @see drupal_chmod() + * + * @todo Remove when https://drupal.org/node/2050759 is in. + * + * @return bool + * TRUE for success, FALSE in the event of an error. + */ + public function chmod($destination) { + return drupal_chmod($destination); + } + +} diff --git a/core/lib/Drupal/Core/Image/ImageFactory.php b/core/lib/Drupal/Core/Image/ImageFactory.php new file mode 100644 index 0000000..91b28d2 --- /dev/null +++ b/core/lib/Drupal/Core/Image/ImageFactory.php @@ -0,0 +1,58 @@ +toolkit = $toolkit; + } + + /** + * Sets a custom image toolkit. + * + * @param \Drupal\system\Plugin\ImageToolkitInterface $toolkit + * The image toolkit to use for this image factory. + * + * @return self + * Returns this image. + */ + public function setToolkit(ImageToolkitInterface $toolkit) { + $this->toolkit = $toolkit; + return $this; + } + + /** + * Constructs a new Image object. + * + * @param string $source + * The path to an image file. + * + * @return \Drupal\Core\Image\ImageInterface + */ + public function get($source) { + return new Image($source, $this->toolkit); + } + +} diff --git a/core/lib/Drupal/Core/Image/ImageInterface.php b/core/lib/Drupal/Core/Image/ImageInterface.php new file mode 100644 index 0000000..ea6682d --- /dev/null +++ b/core/lib/Drupal/Core/Image/ImageInterface.php @@ -0,0 +1,247 @@ +getFileUri()); - if (!$info || empty($info['extension'])) { + $image = Drupal::service('image.factory')->get($file->getFileUri()); + if (!$image->getExtension()) { $errors[] = t('Only JPEG, PNG and GIF images are allowed.'); } @@ -456,16 +455,19 @@ function file_validate_image_resolution(File $file, $maximum_dimensions = 0, $mi $errors = array(); // Check first that the file is an image. - if ($info = image_get_info($file->getFileUri())) { + $image_factory = Drupal::service('image.factory'); + $image = $image_factory->get($file->getFileUri()); + if ($image->getExtension()) { if ($maximum_dimensions) { // Check that it is smaller than the given dimensions. list($width, $height) = explode('x', $maximum_dimensions); - if ($info['width'] > $width || $info['height'] > $height) { + if ($image->getWidth() > $width || $image->getHeight() > $height) { // Try to resize the image to fit the dimensions. - if ($image = image_load($file->getFileUri())) { - image_scale($image, $width, $height); - image_save($image); - $file->filesize = $image->info['file_size']; + $image = $image_factory->get($file->getFileUri()); + if ($image->getResource()) { + $image->scale($width, $height); + $image->save(); + $file->filesize = $image->getFileSize(); drupal_set_message(t('The image was resized to fit within the maximum allowed dimensions of %dimensions pixels.', array('%dimensions' => $maximum_dimensions))); } else { @@ -477,7 +479,7 @@ function file_validate_image_resolution(File $file, $maximum_dimensions = 0, $mi if ($minimum_dimensions) { // Check that it is larger than the given dimensions. list($width, $height) = explode('x', $minimum_dimensions); - if ($info['width'] < $width || $info['height'] < $height) { + if ($image->getWidth() < $width || $image->getHeight() < $height) { $errors[] = t('The image is too small; the minimum dimensions are %dimensions pixels.', array('%dimensions' => $minimum_dimensions)); } } diff --git a/core/modules/file/lib/Drupal/file/Tests/ValidatorTest.php b/core/modules/file/lib/Drupal/file/Tests/ValidatorTest.php index 8012c4d..5214aa4 100644 --- a/core/modules/file/lib/Drupal/file/Tests/ValidatorTest.php +++ b/core/modules/file/lib/Drupal/file/Tests/ValidatorTest.php @@ -87,9 +87,9 @@ function testFileValidateImageResolution() { $errors = file_validate_image_resolution($this->image, '10x5'); $this->assertEqual(count($errors), 0, 'No errors should be reported when an oversized image can be scaled down.', 'File'); - $info = image_get_info($this->image->getFileUri()); - $this->assertTrue($info['width'] <= 10, 'Image scaled to correct width.', 'File'); - $this->assertTrue($info['height'] <= 5, 'Image scaled to correct height.', 'File'); + $image = $this->container->get('image.factory')->get($this->image->getFileUri()); + $this->assertTrue($image->getWidth() <= 10, 'Image scaled to correct width.', 'File'); + $this->assertTrue($image->getHeight() <= 5, 'Image scaled to correct height.', 'File'); drupal_unlink('temporary://druplicon.png'); } diff --git a/core/modules/image/image.admin.inc b/core/modules/image/image.admin.inc index 1e2646f..0eb33c6 100644 --- a/core/modules/image/image.admin.inc +++ b/core/modules/image/image.admin.inc @@ -8,7 +8,6 @@ use Drupal\Component\Utility\String; use Drupal\image\ConfigurableImageEffectInterface; use Drupal\image\ImageStyleInterface; -use Symfony\Component\HttpFoundation\RedirectResponse; /** * Menu callback; Listing of all current image styles. @@ -380,7 +379,12 @@ function theme_image_style_preview($variables) { // Set up original file information. $original_path = $sample_image; - $original_image = image_get_info($original_path); + $image_factory = Drupal::service('image.factory'); + $original_image = $image_factory->get($original_path); + $original_image = array( + 'width' => $original_image->getWidth(), + 'height' => $original_image->getHeight(), + ); if ($original_image['width'] > $original_image['height']) { $original_width = min($original_image['width'], $sample_width); $original_height = round($original_width / $original_image['width'] * $original_image['height']); @@ -389,15 +393,18 @@ function theme_image_style_preview($variables) { $original_height = min($original_image['height'], $sample_height); $original_width = round($original_height / $original_image['height'] * $original_image['width']); } - $original_attributes = array_intersect_key($original_image, array('width' => '', 'height' => '')); - $original_attributes['style'] = 'width: ' . $original_width . 'px; height: ' . $original_height . 'px;'; + $original_image['style'] = 'width: ' . $original_width . 'px; height: ' . $original_height . 'px;'; // Set up preview file information. $preview_file = $style->buildUri($original_path); if (!file_exists($preview_file)) { $style->createDerivative($original_path, $preview_file); } - $preview_image = image_get_info($preview_file); + $preview_image = $image_factory->get($preview_file); + $preview_image = array( + 'width' => $preview_image->getWidth(), + 'height' => $preview_image->getHeight(), + ); if ($preview_image['width'] > $preview_image['height']) { $preview_width = min($preview_image['width'], $sample_width); $preview_height = round($preview_width / $preview_image['width'] * $preview_image['height']); @@ -406,8 +413,7 @@ function theme_image_style_preview($variables) { $preview_height = min($preview_image['height'], $sample_height); $preview_width = round($preview_height / $preview_image['height'] * $preview_image['width']); } - $preview_attributes = array_intersect_key($preview_image, array('width' => '', 'height' => '')); - $preview_attributes['style'] = 'width: ' . $preview_width . 'px; height: ' . $preview_height . 'px;'; + $preview_image['style'] = 'width: ' . $preview_width . 'px; height: ' . $preview_height . 'px;'; // In the previews, timestamps are added to prevent caching of images. $output = '
'; @@ -416,8 +422,8 @@ function theme_image_style_preview($variables) { $original_url = file_create_url($original_path); $output .= '
'; $output .= t('original') . ' (' . l(t('view actual size'), $original_url) . ')'; - $output .= '
'; - $output .= '' . theme('image', array('uri' => $original_path, 'alt' => t('Sample original image'), 'title' => '', 'attributes' => $original_attributes)) . ''; + $output .= '
'; + $output .= '' . theme('image', array('uri' => $original_path, 'alt' => t('Sample original image'), 'title' => '', 'attributes' => $original_image)) . ''; $output .= '
' . $original_image['height'] . 'px
'; $output .= '
' . $original_image['width'] . 'px
'; $output .= '
'; // End preview-image. @@ -427,8 +433,8 @@ function theme_image_style_preview($variables) { $preview_url = file_create_url($preview_file) . '?cache_bypass=' . REQUEST_TIME; $output .= '
'; $output .= check_plain($style->label()) . ' (' . l(t('view actual size'), file_create_url($preview_file) . '?' . time()) . ')'; - $output .= '
'; - $output .= '' . theme('image', array('uri' => $preview_url, 'alt' => t('Sample modified image'), 'title' => '', 'attributes' => $preview_attributes)) . ''; + $output .= '
'; + $output .= '' . theme('image', array('uri' => $preview_url, 'alt' => t('Sample modified image'), 'title' => '', 'attributes' => $preview_image)) . ''; $output .= '
' . $preview_image['height'] . 'px
'; $output .= '
' . $preview_image['width'] . 'px
'; $output .= '
'; // End preview-image. diff --git a/core/modules/image/image.field.inc b/core/modules/image/image.field.inc index 1f0e87b..b8153b3 100644 --- a/core/modules/image/image.field.inc +++ b/core/modules/image/image.field.inc @@ -226,15 +226,14 @@ function _image_field_resolution_validate($element, &$form_state) { * Implements hook_field_presave(). */ function image_field_presave(EntityInterface $entity, $field, $instance, $langcode, &$items) { - + $image_factory = Drupal::service('image.factory'); // Determine the dimensions if necessary. foreach ($items as &$item) { if (!isset($item['width']) || !isset($item['height'])) { - $info = image_get_info(file_load($item['target_id'])->getFileUri()); - - if (is_array($info)) { - $item['width'] = $info['width']; - $item['height'] = $info['height']; + $image = $image_factory->get(file_load($item['target_id'])->getFileUri()); + if ($image->getExtension()) { + $item['width'] = $image->getWidth(); + $item['height'] = $image->getHeight(); } } } @@ -301,11 +300,10 @@ function image_field_widget_process($element, &$form_state, $form) { $variables['height'] = $element['#value']['height']; } else { - $info = image_get_info($file->getFileUri()); - - if (is_array($info)) { - $variables['width'] = $info['width']; - $variables['height'] = $info['height']; + $image = Drupal::service('image.factory')->get($file->getFileUri()); + if ($image->getExtension()) { + $variables['width'] = $image->getWidth(); + $variables['height'] = $image->getHeight(); } else { $variables['width'] = $variables['height'] = NULL; diff --git a/core/modules/image/image.install b/core/modules/image/image.install index 1617e8c..58cf110 100644 --- a/core/modules/image/image.install +++ b/core/modules/image/image.install @@ -6,7 +6,6 @@ */ use Drupal\Component\Uuid\Uuid; -use Drupal\field\Plugin\Core\Entity\Field; /** * Implements hook_install(). diff --git a/core/modules/image/image.module b/core/modules/image/image.module index fefbf00..7def491 100644 --- a/core/modules/image/image.module +++ b/core/modules/image/image.module @@ -9,7 +9,6 @@ use Drupal\field\Plugin\Core\Entity\Field; use Drupal\field\Plugin\Core\Entity\FieldInstance; use Drupal\file\Plugin\Core\Entity\File; -use Drupal\image\ImageStyleInterface; use Drupal\image\Plugin\Core\Entity\ImageStyle; use Drupal\field\FieldInterface; use Drupal\field\FieldInstanceInterface; @@ -276,15 +275,16 @@ function image_file_download($uri) { $original_uri = file_uri_scheme($uri) . '://' . implode('/', $args); // Check that the file exists and is an image. - if ($info = image_get_info($uri)) { + $image = Drupal::service('image.factory')->get($uri); + if ($image->getExtension()) { // Check the permissions of the original to grant access to this image. $headers = module_invoke_all('file_download', $original_uri); // Confirm there's at least one module granting access and none denying access. if (!empty($headers) && !in_array(-1, $headers)) { return array( // Send headers describing the image's size, and MIME-type... - 'Content-Type' => $info['mime_type'], - 'Content-Length' => $info['file_size'], + 'Content-Type' => $image->getMimeType(), + 'Content-Length' => $image->getFileSize(), // By not explicitly setting them here, this uses normal Drupal // Expires, Cache-Control and ETag headers to prevent proxy or // browser caching of private images. diff --git a/core/modules/image/lib/Drupal/image/Controller/ImageStyleDownloadController.php b/core/modules/image/lib/Drupal/image/Controller/ImageStyleDownloadController.php index 34146c2..8013962 100644 --- a/core/modules/image/lib/Drupal/image/Controller/ImageStyleDownloadController.php +++ b/core/modules/image/lib/Drupal/image/Controller/ImageStyleDownloadController.php @@ -11,6 +11,7 @@ use Drupal\Core\Config\ConfigFactory; use Drupal\Core\Controller\ControllerInterface; use Drupal\Core\Extension\ModuleHandlerInterface; +use Drupal\Core\Image\ImageFactory; use Drupal\Core\Lock\LockBackendInterface; use Drupal\Core\StringTranslation\Translator\TranslatorInterface; use Drupal\image\ImageStyleInterface; @@ -49,6 +50,13 @@ class ImageStyleDownloadController extends FileDownloadController implements Con protected $translator; /** + * The image factory. + * + * @var \Drupal\Core\Image\ImageFactory + */ + protected $imageFactory; + + /** * Constructs a ImageStyleDownloadController object. * * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler @@ -59,12 +67,15 @@ class ImageStyleDownloadController extends FileDownloadController implements Con * The lock backend. * @param \Drupal\Core\StringTranslation\Translator\TranslatorInterface $translator * The translator service. + * @param \Drupal\Core\Image\ImageFactory $image_factory + * The image factory. */ - public function __construct(ModuleHandlerInterface $module_handler, ConfigFactory $config_factory, LockBackendInterface $lock, TranslatorInterface $translator) { + public function __construct(ModuleHandlerInterface $module_handler, ConfigFactory $config_factory, LockBackendInterface $lock, TranslatorInterface $translator, ImageFactory $image_factory) { parent::__construct($module_handler); $this->configFactory = $config_factory; $this->lock = $lock; $this->translator = $translator; + $this->imageFactory = $image_factory; } /** @@ -75,7 +86,8 @@ public static function create(ContainerInterface $container) { $container->get('module_handler'), $container->get('config.factory'), $container->get('lock'), - $container->get('string_translation') + $container->get('string_translation'), + $container->get('image.factory') ); } @@ -159,11 +171,11 @@ public function deliver(Request $request, $scheme, ImageStyleInterface $image_st } if ($success) { - $image = image_load($derivative_uri); - $uri = $image->source; + $image = $this->imageFactory->get($derivative_uri); + $uri = $image->getSource(); $headers += array( - 'Content-Type' => $image->info['mime_type'], - 'Content-Length' => $image->info['file_size'], + 'Content-Type' => $image->getMimeType(), + 'Content-Length' => $image->getFileSize(), ); return new BinaryFileResponse($uri, 200, $headers); } diff --git a/core/modules/image/lib/Drupal/image/ImageEffectInterface.php b/core/modules/image/lib/Drupal/image/ImageEffectInterface.php index 05d5efd..acda391 100644 --- a/core/modules/image/lib/Drupal/image/ImageEffectInterface.php +++ b/core/modules/image/lib/Drupal/image/ImageEffectInterface.php @@ -8,6 +8,7 @@ namespace Drupal\image; use Drupal\Component\Plugin\PluginInspectionInterface; +use Drupal\Core\Image\ImageInterface; /** * Defines the interface for image effects. @@ -17,13 +18,13 @@ /** * Applies an image effect to the image object. * - * @param \stdClass $image - * An image object returned by image_load(). + * @param \Drupal\Core\Image\ImageInterface $image + * An image file object. * * @return bool * TRUE on success. FALSE if unable to perform the image effect on the image. */ - public function applyEffect($image); + public function applyEffect(ImageInterface $image); /** * Determines the dimensions of the styled image. diff --git a/core/modules/image/lib/Drupal/image/Plugin/Core/Entity/ImageStyle.php b/core/modules/image/lib/Drupal/image/Plugin/Core/Entity/ImageStyle.php index ed17dee..97f23de 100644 --- a/core/modules/image/lib/Drupal/image/Plugin/Core/Entity/ImageStyle.php +++ b/core/modules/image/lib/Drupal/image/Plugin/Core/Entity/ImageStyle.php @@ -277,7 +277,8 @@ public function createDerivative($original_uri, $derivative_uri) { return FALSE; } - if (!$image = image_load($original_uri)) { + $image = \Drupal::service('image.factory')->get($original_uri); + if (!$image->getResource()) { return FALSE; } @@ -285,7 +286,7 @@ public function createDerivative($original_uri, $derivative_uri) { $effect->applyEffect($image); } - if (!image_save($image, $derivative_uri)) { + if (!$image->save($derivative_uri)) { if (file_exists($derivative_uri)) { watchdog('image', 'Cached image file %destination already exists. There may be an issue with your rewrite configuration.', array('%destination' => $derivative_uri), WATCHDOG_ERROR); } diff --git a/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/CropImageEffect.php b/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/CropImageEffect.php index 11f228e..e46d2fa 100644 --- a/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/CropImageEffect.php +++ b/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/CropImageEffect.php @@ -8,6 +8,7 @@ namespace Drupal\image\Plugin\ImageEffect; use Drupal\Core\Annotation\Translation; +use Drupal\Core\Image\ImageInterface; use Drupal\image\Annotation\ImageEffect; /** @@ -24,17 +25,17 @@ class CropImageEffect extends ResizeImageEffect { /** * {@inheritdoc} */ - public function applyEffect($image) { + public function applyEffect(ImageInterface $image) { // Set sane default values. $this->configuration += array( 'anchor' => 'center-center', ); list($x, $y) = explode('-', $this->configuration['anchor']); - $x = image_filter_keyword($x, $image->info['width'], $this->configuration['width']); - $y = image_filter_keyword($y, $image->info['height'], $this->configuration['height']); - if (!image_crop($image, $x, $y, $this->configuration['width'], $this->configuration['height'])) { - watchdog('image', 'Image crop failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->toolkit->getPluginId(), '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR); + $x = image_filter_keyword($x, $image->getWidth(), $this->configuration['width']); + $y = image_filter_keyword($y, $image->getHeight(), $this->configuration['height']); + if (!$image->crop($x, $y, $this->configuration['width'], $this->configuration['height'])) { + watchdog('image', 'Image crop failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->getToolkitId(), '%path' => $image->getSource(), '%mimetype' => $image->getMimeType(), '%dimensions' => $image->getWidth() . 'x' . $image->getHeight()), WATCHDOG_ERROR); return FALSE; } return TRUE; diff --git a/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/DesaturateImageEffect.php b/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/DesaturateImageEffect.php index 816ed3e..912bec9 100644 --- a/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/DesaturateImageEffect.php +++ b/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/DesaturateImageEffect.php @@ -8,6 +8,7 @@ namespace Drupal\image\Plugin\ImageEffect; use Drupal\Core\Annotation\Translation; +use Drupal\Core\Image\ImageInterface; use Drupal\image\Annotation\ImageEffect; use Drupal\image\ImageEffectBase; @@ -31,9 +32,9 @@ public function transformDimensions(array &$dimensions) { /** * {@inheritdoc} */ - public function applyEffect($image) { - if (!image_desaturate($image)) { - watchdog('image', 'Image desaturate failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->toolkit->getPluginId(), '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR); + public function applyEffect(ImageInterface $image) { + if (!$image->desaturate()) { + watchdog('image', 'Image desaturate failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->getToolkitId(), '%path' => $image->getSource(), '%mimetype' => $image->getMimeType(), '%dimensions' => $image->getWidth() . 'x' . $image->getHeight()), WATCHDOG_ERROR); return FALSE; } return TRUE; diff --git a/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/ResizeImageEffect.php b/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/ResizeImageEffect.php index 484e6a0..766e5a7 100644 --- a/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/ResizeImageEffect.php +++ b/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/ResizeImageEffect.php @@ -8,6 +8,7 @@ namespace Drupal\image\Plugin\ImageEffect; use Drupal\Core\Annotation\Translation; +use Drupal\Core\Image\ImageInterface; use Drupal\image\Annotation\ImageEffect; use Drupal\image\ConfigurableImageEffectInterface; use Drupal\image\ImageEffectBase; @@ -26,9 +27,9 @@ class ResizeImageEffect extends ImageEffectBase implements ConfigurableImageEffe /** * {@inheritdoc} */ - public function applyEffect($image) { - if (!image_resize($image, $this->configuration['width'], $this->configuration['height'])) { - watchdog('image', 'Image resize failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->toolkit->getPluginId(), '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR); + public function applyEffect(ImageInterface $image) { + if (!$image->resize($this->configuration['width'], $this->configuration['height'])) { + watchdog('image', 'Image resize failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->getToolkitId(), '%path' => $image->getSource(), '%mimetype' => $image->getMimeType(), '%dimensions' => $image->getWidth() . 'x' . $image->getHeight()), WATCHDOG_ERROR); return FALSE; } return TRUE; diff --git a/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/RotateImageEffect.php b/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/RotateImageEffect.php index dee537e..fe563ae 100644 --- a/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/RotateImageEffect.php +++ b/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/RotateImageEffect.php @@ -8,6 +8,7 @@ namespace Drupal\image\Plugin\ImageEffect; use Drupal\Core\Annotation\Translation; +use Drupal\Core\Image\ImageInterface; use Drupal\image\Annotation\ImageEffect; use Drupal\image\ConfigurableImageEffectInterface; use Drupal\image\ImageEffectBase; @@ -26,7 +27,7 @@ class RotateImageEffect extends ImageEffectBase implements ConfigurableImageEffe /** * {@inheritdoc} */ - public function applyEffect($image) { + public function applyEffect(ImageInterface $image) { // Set sane default values. $this->configuration += array( 'degrees' => 0, @@ -53,8 +54,8 @@ public function applyEffect($image) { $this->configuration['degrees'] = rand(-1 * $degrees, $degrees); } - if (!image_rotate($image, $this->configuration['degrees'], $this->configuration['bgcolor'])) { - watchdog('image', 'Image rotate failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->toolkit->getPluginId(), '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR); + if (!$image->rotate($this->configuration['degrees'], $this->configuration['bgcolor'])) { + watchdog('image', 'Image rotate failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->getToolkitId(), '%path' => $image->getSource(), '%mimetype' => $image->getMimeType(), '%dimensions' => $image->getWidth() . 'x' . $image->getHeight()), WATCHDOG_ERROR); return FALSE; } return TRUE; diff --git a/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/ScaleAndCropImageEffect.php b/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/ScaleAndCropImageEffect.php index dfa5955..39bd2ec 100644 --- a/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/ScaleAndCropImageEffect.php +++ b/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/ScaleAndCropImageEffect.php @@ -8,6 +8,7 @@ namespace Drupal\image\Plugin\ImageEffect; use Drupal\Core\Annotation\Translation; +use Drupal\Core\Image\ImageInterface; use Drupal\image\Annotation\ImageEffect; /** @@ -24,9 +25,9 @@ class ScaleAndCropImageEffect extends ResizeImageEffect { /** * {@inheritdoc} */ - public function applyEffect($image) { - if (!image_scale_and_crop($image, $this->configuration['width'], $this->configuration['height'])) { - watchdog('image', 'Image scale and crop failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->toolkit->getPluginId(), '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR); + public function applyEffect(ImageInterface $image) { + if (!$image->scaleAndCrop($this->configuration['width'], $this->configuration['height'])) { + watchdog('image', 'Image scale and crop failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->getToolkitId(), '%path' => $image->getSource(), '%mimetype' => $image->getMimeType(), '%dimensions' => $image->getWidth() . 'x' . $image->getHeight()), WATCHDOG_ERROR); return FALSE; } return TRUE; diff --git a/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/ScaleImageEffect.php b/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/ScaleImageEffect.php index 47ada5a..c7b2f53 100644 --- a/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/ScaleImageEffect.php +++ b/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/ScaleImageEffect.php @@ -7,8 +7,9 @@ namespace Drupal\image\Plugin\ImageEffect; -use Drupal\Component\Image\Image; use Drupal\Core\Annotation\Translation; +use Drupal\Component\Utility\Image; +use Drupal\Core\Image\ImageInterface; use Drupal\image\Annotation\ImageEffect; /** @@ -25,7 +26,7 @@ class ScaleImageEffect extends ResizeImageEffect { /** * {@inheritdoc} */ - public function applyEffect($image) { + public function applyEffect(ImageInterface $image) { // Set sane default values. $this->configuration += array( 'width' => NULL, @@ -33,8 +34,8 @@ public function applyEffect($image) { 'upscale' => FALSE, ); - if (!image_scale($image, $this->configuration['width'], $this->configuration['height'], $this->configuration['upscale'])) { - watchdog('image', 'Image scale failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->toolkit->getPluginId(), '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR); + if (!$image->scale($this->configuration['width'], $this->configuration['height'], $this->configuration['upscale'])) { + watchdog('image', 'Image scale failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->getToolkitId(), '%path' => $image->getSource(), '%mimetype' => $image->getMimeType(), '%dimensions' => $image->getWidth() . 'x' . $image->getHeight()), WATCHDOG_ERROR); return FALSE; } return TRUE; diff --git a/core/modules/image/lib/Drupal/image/Tests/FileMoveTest.php b/core/modules/image/lib/Drupal/image/Tests/FileMoveTest.php index 2fc0b68..13518e0 100644 --- a/core/modules/image/lib/Drupal/image/Tests/FileMoveTest.php +++ b/core/modules/image/lib/Drupal/image/Tests/FileMoveTest.php @@ -7,12 +7,12 @@ namespace Drupal\image\Tests; -use Drupal\system\Tests\Image\ToolkitTestBase; +use Drupal\simpletest\WebTestBase; /** * Tests the file move function for images and image styles. */ -class FileMoveTest extends ToolkitTestBase { +class FileMoveTest extends WebTestBase { /** * Modules to enable. @@ -38,7 +38,7 @@ function testNormal() { // Create derivative image. $styles = entity_load_multiple('image_style'); - $style = image_style_load(key($styles)); + $style = reset($styles); $original_uri = $file->getFileUri(); $derivative_uri = $style->buildUri($original_uri); $style->createDerivative($original_uri, $derivative_uri); diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageDimensionsTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageDimensionsTest.php index 0ff6738..c136fa6 100644 --- a/core/modules/image/lib/Drupal/image/Tests/ImageDimensionsTest.php +++ b/core/modules/image/lib/Drupal/image/Tests/ImageDimensionsTest.php @@ -35,6 +35,7 @@ public static function getInfo() { * Test styled image dimensions cumulatively. */ function testImageDimensions() { + $image_factory = $this->container->get('image.factory'); // Create a working copy of the file. $files = $this->drupalGetTestFiles('image'); $file = reset($files); @@ -53,9 +54,9 @@ function testImageDimensions() { 'height' => 20, ); // Verify that the original image matches the hard-coded values. - $image_info = image_get_info($original_uri); - $this->assertEqual($image_info['width'], $variables['width']); - $this->assertEqual($image_info['height'], $variables['height']); + $image_file = $image_factory->get($original_uri); + $this->assertEqual($image_file->getWidth(), $variables['width']); + $this->assertEqual($image_file->getHeight(), $variables['height']); // Scale an image that is wider than it is high. $effect = array( @@ -75,9 +76,9 @@ function testImageDimensions() { $this->drupalGet($url); $this->assertResponse(200, 'Image was generated at the URL.'); $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.'); - $image_info = image_get_info($generated_uri); - $this->assertEqual($image_info['width'], 120); - $this->assertEqual($image_info['height'], 60); + $image_file = $image_factory->get($generated_uri); + $this->assertEqual($image_file->getWidth(), 120); + $this->assertEqual($image_file->getHeight(), 60); // Rotate 90 degrees anticlockwise. $effect = array( @@ -96,9 +97,9 @@ function testImageDimensions() { $this->drupalGet($url); $this->assertResponse(200, 'Image was generated at the URL.'); $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.'); - $image_info = image_get_info($generated_uri); - $this->assertEqual($image_info['width'], 60); - $this->assertEqual($image_info['height'], 120); + $image_file = $image_factory->get($generated_uri); + $this->assertEqual($image_file->getWidth(), 60); + $this->assertEqual($image_file->getHeight(), 120); // Scale an image that is higher than it is wide (rotated by previous effect). $effect = array( @@ -118,9 +119,9 @@ function testImageDimensions() { $this->drupalGet($url); $this->assertResponse(200, 'Image was generated at the URL.'); $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.'); - $image_info = image_get_info($generated_uri); - $this->assertEqual($image_info['width'], 45); - $this->assertEqual($image_info['height'], 90); + $image_file = $image_factory->get($generated_uri); + $this->assertEqual($image_file->getWidth(), 45); + $this->assertEqual($image_file->getHeight(), 90); // Test upscale disabled. $effect = array( @@ -140,9 +141,9 @@ function testImageDimensions() { $this->drupalGet($url); $this->assertResponse(200, 'Image was generated at the URL.'); $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.'); - $image_info = image_get_info($generated_uri); - $this->assertEqual($image_info['width'], 45); - $this->assertEqual($image_info['height'], 90); + $image_file = $image_factory->get($generated_uri); + $this->assertEqual($image_file->getWidth(), 45); + $this->assertEqual($image_file->getHeight(), 90); // Add a desaturate effect. $effect = array( @@ -158,9 +159,9 @@ function testImageDimensions() { $this->drupalGet($url); $this->assertResponse(200, 'Image was generated at the URL.'); $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.'); - $image_info = image_get_info($generated_uri); - $this->assertEqual($image_info['width'], 45); - $this->assertEqual($image_info['height'], 90); + $image_file = $image_factory->get($generated_uri); + $this->assertEqual($image_file->getWidth(), 45); + $this->assertEqual($image_file->getHeight(), 90); // Add a random rotate effect. $effect = array( @@ -199,9 +200,9 @@ function testImageDimensions() { $this->drupalGet($url); $this->assertResponse(200, 'Image was generated at the URL.'); $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.'); - $image_info = image_get_info($generated_uri); - $this->assertEqual($image_info['width'], 30); - $this->assertEqual($image_info['height'], 30); + $image_file = $image_factory->get($generated_uri); + $this->assertEqual($image_file->getWidth(), 30); + $this->assertEqual($image_file->getHeight(), 30); // Rotate to a non-multiple of 90 degrees. $effect = array( diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageFieldValidateTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageFieldValidateTest.php index 1cd0ce9..e3d48bf 100644 --- a/core/modules/image/lib/Drupal/image/Tests/ImageFieldValidateTest.php +++ b/core/modules/image/lib/Drupal/image/Tests/ImageFieldValidateTest.php @@ -36,12 +36,13 @@ function testResolution() { // big, so cycle through test image files until we have what we need. $image_that_is_too_big = FALSE; $image_that_is_too_small = FALSE; + $image_factory = $this->container->get('image.factory'); foreach ($this->drupalGetTestFiles('image') as $image) { - $info = image_get_info($image->uri); - if ($info['width'] > $max_resolution) { + $image_file = $image_factory->get($image->uri); + if ($image_file->getWidth() > $max_resolution) { $image_that_is_too_big = $image; } - if ($info['width'] < $min_resolution) { + if ($image_file->getWidth() < $min_resolution) { $image_that_is_too_small = $image; } if ($image_that_is_too_small && $image_that_is_too_big) { diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageItemTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageItemTest.php index 5e7472f..fdd3686 100644 --- a/core/modules/image/lib/Drupal/image/Tests/ImageItemTest.php +++ b/core/modules/image/lib/Drupal/image/Tests/ImageItemTest.php @@ -30,6 +30,11 @@ class ImageItemTest extends FieldUnitTestBase { */ protected $image; + /** + * @var \Drupal\Core\Image\ImageFactory + */ + protected $imageFactory; + public static function getInfo() { return array( 'name' => 'Image field item API', @@ -58,6 +63,7 @@ public function setUp() { 'uri' => 'public://example.jpg', )); $this->image->save(); + $this->imageFactory = $this->container->get('image.factory'); } /** @@ -78,9 +84,9 @@ public function testImageItem() { $this->assertEqual($entity->image_test->target_id, $this->image->id()); $this->assertEqual($entity->image_test->alt, $alt); $this->assertEqual($entity->image_test->title, $title); - $info = image_get_info('public://example.jpg'); - $this->assertEqual($entity->image_test->width, $info['width']); - $this->assertEqual($entity->image_test->height, $info['height']); + $image = $this->imageFactory->get('public://example.jpg'); + $this->assertEqual($entity->image_test->width, $image->getWidth()); + $this->assertEqual($entity->image_test->height, $image->getHeight()); $this->assertEqual($entity->image_test->entity->id(), $this->image->id()); $this->assertEqual($entity->image_test->entity->uuid(), $this->image->uuid()); @@ -98,9 +104,9 @@ public function testImageItem() { $entity->save(); $this->assertEqual($entity->image_test->entity->id(), $image2->id()); $this->assertEqual($entity->image_test->entity->getFileUri(), $image2->getFileUri()); - $info = image_get_info('public://example-2.jpg'); - $this->assertEqual($entity->image_test->width, $info['width']); - $this->assertEqual($entity->image_test->height, $info['height']); + $image = $this->imageFactory->get('public://example-2.jpg'); + $this->assertEqual($entity->image_test->width, $image->getWidth()); + $this->assertEqual($entity->image_test->height, $image->getHeight()); $this->assertEqual($entity->image_test->alt, $new_alt); // Check that the image item can be set to the referenced file directly. diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageStylesPathAndUrlTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageStylesPathAndUrlTest.php index cae45d7..4648701 100644 --- a/core/modules/image/lib/Drupal/image/Tests/ImageStylesPathAndUrlTest.php +++ b/core/modules/image/lib/Drupal/image/Tests/ImageStylesPathAndUrlTest.php @@ -153,9 +153,9 @@ function doImageStyleUrlAndPathTests($scheme, $clean_url = TRUE, $extra_slash = $this->assertResponse(200, 'Image was generated at the URL.'); $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.'); $this->assertRaw(file_get_contents($generated_uri), 'URL returns expected file.'); - $generated_image_info = image_get_info($generated_uri); - $this->assertEqual($this->drupalGetHeader('Content-Type'), $generated_image_info['mime_type'], 'Expected Content-Type was reported.'); - $this->assertEqual($this->drupalGetHeader('Content-Length'), $generated_image_info['file_size'], 'Expected Content-Length was reported.'); + $image = $this->container->get('image.factory')->get($generated_uri); + $this->assertEqual($this->drupalGetHeader('Content-Type'), $image->getMimeType(), 'Expected Content-Type was reported.'); + $this->assertEqual($this->drupalGetHeader('Content-Length'), $image->getFileSize(), 'Expected Content-Length was reported.'); if ($scheme == 'private') { $this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.'); $this->assertNotEqual(strpos($this->drupalGetHeader('Cache-Control'), 'no-cache'), FALSE, 'Cache-Control header contains \'no-cache\' to prevent caching.'); diff --git a/core/modules/image/tests/modules/image_module_test/lib/Drupal/image_module_test/Plugin/ImageEffect/NullTestImageEffect.php b/core/modules/image/tests/modules/image_module_test/lib/Drupal/image_module_test/Plugin/ImageEffect/NullTestImageEffect.php index 23b1931..52731fe 100644 --- a/core/modules/image/tests/modules/image_module_test/lib/Drupal/image_module_test/Plugin/ImageEffect/NullTestImageEffect.php +++ b/core/modules/image/tests/modules/image_module_test/lib/Drupal/image_module_test/Plugin/ImageEffect/NullTestImageEffect.php @@ -8,6 +8,7 @@ namespace Drupal\image_module_test\Plugin\ImageEffect; use Drupal\Core\Annotation\Translation; +use Drupal\Core\Image\ImageInterface; use Drupal\image\Annotation\ImageEffect; use Drupal\image\ImageEffectBase; @@ -24,7 +25,7 @@ class NullTestImageEffect extends ImageEffectBase { /** * {@inheritdoc} */ - public function applyEffect($image) { + public function applyEffect(ImageInterface $image) { return TRUE; } diff --git a/core/modules/system/lib/Drupal/system/Plugin/ImageToolkit/GDToolkit.php b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkit/GDToolkit.php index 06cb4a6..df63bb6 100644 --- a/core/modules/system/lib/Drupal/system/Plugin/ImageToolkit/GDToolkit.php +++ b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkit/GDToolkit.php @@ -10,6 +10,7 @@ use Drupal\Component\Plugin\PluginBase; use Drupal\Component\Annotation\Plugin; use Drupal\Core\Annotation\Translation; +use Drupal\Core\Image\ImageInterface; use Drupal\system\Plugin\ImageToolkitInterface; /** @@ -23,7 +24,7 @@ class GDToolkit extends PluginBase implements ImageToolkitInterface { /** - * Implements \Drupal\system\Plugin\ImageToolkitInterface::settingsForm(). + * {@inheritdoc} */ public function settingsForm() { $form['image_jpeg_quality'] = array( @@ -39,7 +40,7 @@ public function settingsForm() { } /** - * Implements \Drupal\system\Plugin\ImageToolkitInterface::settingsFormSubmit(). + * {@inheritdoc} */ public function settingsFormSubmit($form, &$form_state) { config('system.image.gd') @@ -48,35 +49,36 @@ public function settingsFormSubmit($form, &$form_state) { } /** - * Implements \Drupal\system\Plugin\ImageToolkitInterface::resize(). + * {@inheritdoc} */ - public function resize($image, $width, $height) { + public function resize(ImageInterface $image, $width, $height) { $res = $this->createTmp($image, $width, $height); - if (!imagecopyresampled($res, $image->resource, 0, 0, 0, 0, $width, $height, $image->info['width'], $image->info['height'])) { + if (!imagecopyresampled($res, $image->getResource(), 0, 0, 0, 0, $width, $height, $image->getWidth(), $image->getHeight())) { return FALSE; } - imagedestroy($image->resource); + imagedestroy($image->getResource()); // Update image object. - $image->resource = $res; - $image->info['width'] = $width; - $image->info['height'] = $height; + $image + ->setResource($res) + ->setWidth($width) + ->setHeight($height); return TRUE; } /** - * Implements \Drupal\system\Plugin\ImageToolkitInterface::rotate(). + * {@inheritdoc} */ - public function rotate($image, $degrees, $background = NULL) { + public function rotate(ImageInterface $image, $degrees, $background = NULL) { // PHP installations using non-bundled GD do not have imagerotate. if (!function_exists('imagerotate')) { - watchdog('image', 'The image %file could not be rotated because the imagerotate() function is not available in this PHP installation.', array('%file' => $image->source)); + watchdog('image', 'The image %file could not be rotated because the imagerotate() function is not available in this PHP installation.', array('%file' => $image->getSource())); return FALSE; } - $width = $image->info['width']; - $height = $image->info['height']; + $width = $image->getWidth(); + $height = $image->getHeight(); // Convert the hexadecimal background value to a color index value. if (isset($background)) { @@ -84,97 +86,100 @@ public function rotate($image, $degrees, $background = NULL) { for ($i = 16; $i >= 0; $i -= 8) { $rgb[] = (($background >> $i) & 0xFF); } - $background = imagecolorallocatealpha($image->resource, $rgb[0], $rgb[1], $rgb[2], 0); + $background = imagecolorallocatealpha($image->getResource(), $rgb[0], $rgb[1], $rgb[2], 0); } // Set the background color as transparent if $background is NULL. else { // Get the current transparent color. - $background = imagecolortransparent($image->resource); + $background = imagecolortransparent($image->getResource()); // If no transparent colors, use white. if ($background == 0) { - $background = imagecolorallocatealpha($image->resource, 255, 255, 255, 0); + $background = imagecolorallocatealpha($image->getResource(), 255, 255, 255, 0); } } // Images are assigned a new color palette when rotating, removing any // transparency flags. For GIF images, keep a record of the transparent color. - if ($image->info['extension'] == 'gif') { - $transparent_index = imagecolortransparent($image->resource); + if ($image->getExtension() == 'gif') { + $transparent_index = imagecolortransparent($image->getResource()); if ($transparent_index != 0) { - $transparent_gif_color = imagecolorsforindex($image->resource, $transparent_index); + $transparent_gif_color = imagecolorsforindex($image->getResource(), $transparent_index); } } - $image->resource = imagerotate($image->resource, 360 - $degrees, $background); + $image->setResource(imagerotate($image->getResource(), 360 - $degrees, $background)); // GIFs need to reassign the transparent color after performing the rotate. if (isset($transparent_gif_color)) { - $background = imagecolorexactalpha($image->resource, $transparent_gif_color['red'], $transparent_gif_color['green'], $transparent_gif_color['blue'], $transparent_gif_color['alpha']); - imagecolortransparent($image->resource, $background); + $background = imagecolorexactalpha($image->getResource(), $transparent_gif_color['red'], $transparent_gif_color['green'], $transparent_gif_color['blue'], $transparent_gif_color['alpha']); + imagecolortransparent($image->getResource(), $background); } - $image->info['width'] = imagesx($image->resource); - $image->info['height'] = imagesy($image->resource); + $image + ->setWidth(imagesx($image->getResource())) + ->setHeight(imagesy($image->getResource())); return TRUE; } /** - * Implements \Drupal\system\Plugin\ImageToolkitInterface::crop(). + * {@inheritdoc} */ - public function crop($image, $x, $y, $width, $height) { + public function crop(ImageInterface $image, $x, $y, $width, $height) { $res = $this->createTmp($image, $width, $height); - if (!imagecopyresampled($res, $image->resource, 0, 0, $x, $y, $width, $height, $width, $height)) { + if (!imagecopyresampled($res, $image->getResource(), 0, 0, $x, $y, $width, $height, $width, $height)) { return FALSE; } // Destroy the original image and return the modified image. - imagedestroy($image->resource); - $image->resource = $res; - $image->info['width'] = $width; - $image->info['height'] = $height; + imagedestroy($image->getResource()); + $image + ->setResource($res) + ->setWidth($width) + ->setHeight($height); return TRUE; } /** - * Implements \Drupal\system\Plugin\ImageToolkitInterface::desaturate(). + * {@inheritdoc} */ - public function desaturate($image) { + public function desaturate(ImageInterface $image) { // PHP installations using non-bundled GD do not have imagefilter. if (!function_exists('imagefilter')) { - watchdog('image', 'The image %file could not be desaturated because the imagefilter() function is not available in this PHP installation.', array('%file' => $image->source)); + watchdog('image', 'The image %file could not be desaturated because the imagefilter() function is not available in this PHP installation.', array('%file' => $image->getSource())); return FALSE; } - return imagefilter($image->resource, IMG_FILTER_GRAYSCALE); + return imagefilter($image->getResource(), IMG_FILTER_GRAYSCALE); } /** - * Implements \Drupal\system\Plugin\ImageToolkitInterface::load(). + * {@inheritdoc} */ - public function load($image) { - $extension = str_replace('jpg', 'jpeg', $image->info['extension']); + public function load(ImageInterface $image) { + $extension = str_replace('jpg', 'jpeg', $image->getExtension()); $function = 'imagecreatefrom' . $extension; - if (function_exists($function) && $image->resource = $function($image->source)) { - if (!imageistruecolor($image->resource)) { + if (function_exists($function) && $resource = $function($image->getSource())) { + $image->setResource($resource); + if (!imageistruecolor($resource)) { // Convert indexed images to true color, so that filters work // correctly and don't result in unnecessary dither. - $new_image = $this->createTmp($image, $image->info['width'], $image->info['height']); - imagecopy($new_image, $image->resource, 0, 0, 0, 0, $image->info['width'], $image->info['height']); - imagedestroy($image->resource); - $image->resource = $new_image; + $new_image = $this->createTmp($image, $image->getWidth(), $image->getHeight()); + imagecopy($new_image, $resource, 0, 0, 0, 0, $image->getWidth(), $image->getHeight()); + imagedestroy($resource); + $image->setResource($new_image); } - return (bool) $image->resource; + return (bool) $image->getResource(); } return FALSE; } /** - * Implements \Drupal\system\Plugin\ImageToolkitInterface::save(). + * {@inheritdoc} */ - public function save($image, $destination) { + public function save(ImageInterface $image, $destination) { $scheme = file_uri_scheme($destination); // Work around lack of stream wrapper support in imagejpeg() and imagepng(). if ($scheme && file_stream_wrapper_valid_scheme($scheme)) { @@ -188,21 +193,21 @@ public function save($image, $destination) { $destination = drupal_realpath($destination); } - $extension = str_replace('jpg', 'jpeg', $image->info['extension']); + $extension = str_replace('jpg', 'jpeg', $image->getExtension()); $function = 'image' . $extension; if (!function_exists($function)) { return FALSE; } if ($extension == 'jpeg') { - $success = $function($image->resource, $destination, config('system.image.gd')->get('jpeg_quality')); + $success = $function($image->getResource(), $destination, config('system.image.gd')->get('jpeg_quality')); } else { // Always save PNG images with full transparency. if ($extension == 'png') { - imagealphablending($image->resource, FALSE); - imagesavealpha($image->resource, TRUE); + imagealphablending($image->getResource(), FALSE); + imagesavealpha($image->getResource(), TRUE); } - $success = $function($image->resource, $destination); + $success = $function($image->getResource(), $destination); } // Move temporary local file to remote destination. if (isset($permanent_destination) && $success) { @@ -212,11 +217,11 @@ public function save($image, $destination) { } /** - * Implements \Drupal\system\Plugin\ImageToolkitInterface::getInfo(). + * {@inheritdoc} */ - public function getInfo($image) { + public function getInfo(ImageInterface $image) { $details = FALSE; - $data = getimagesize($image->source); + $data = getimagesize($image->getSource()); if (isset($data) && is_array($data)) { $extensions = array('1' => 'gif', '2' => 'jpg', '3' => 'png'); @@ -235,7 +240,7 @@ public function getInfo($image) { /** * Creates a truecolor image preserving transparency from a provided image. * - * @param object $image + * @param \Drupal\Core\Image\ImageInterface $image * An image object. * @param int $width * The new width of the new image, in pixels. @@ -245,16 +250,16 @@ public function getInfo($image) { * @return resource * A GD image handle. */ - public function createTmp($image, $width, $height) { + public function createTmp(ImageInterface $image, $width, $height) { $res = imagecreatetruecolor($width, $height); - if ($image->info['extension'] == 'gif') { + if ($image->getExtension() == 'gif') { // Grab transparent color index from image resource. - $transparent = imagecolortransparent($image->resource); + $transparent = imagecolortransparent($image->getResource()); if ($transparent >= 0) { // The original must have a transparent color, allocate to the new image. - $transparent_color = imagecolorsforindex($image->resource, $transparent); + $transparent_color = imagecolorsforindex($image->getResource(), $transparent); $transparent = imagecolorallocate($res, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']); // Flood with our new transparent color. @@ -262,7 +267,7 @@ public function createTmp($image, $width, $height) { imagecolortransparent($res, $transparent); } } - elseif ($image->info['extension'] == 'png') { + elseif ($image->getExtension() == 'png') { imagealphablending($res, FALSE); $transparency = imagecolorallocatealpha($res, 0, 0, 0, 127); imagefill($res, 0, 0, $transparency); @@ -277,7 +282,7 @@ public function createTmp($image, $width, $height) { } /** - * Implements \Drupal\system\Plugin\ImageToolkitInterface::isAvailable(). + * {@inheritdoc} */ public static function isAvailable() { if ($check = get_extension_funcs('gd')) { diff --git a/core/modules/system/lib/Drupal/system/Plugin/ImageToolkitInterface.php b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkitInterface.php index 0b22f3c..774f050 100644 --- a/core/modules/system/lib/Drupal/system/Plugin/ImageToolkitInterface.php +++ b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkitInterface.php @@ -7,13 +7,43 @@ namespace Drupal\system\Plugin; +use Drupal\Component\Plugin\PluginInspectionInterface; +use Drupal\Core\Image\ImageInterface; + +/** + * @defgroup image Image toolkits + * @{ + * Functions for image file manipulations. + * + * Drupal's image toolkits provide an abstraction layer for common image file + * manipulations like scaling, cropping, and rotating. The abstraction frees + * module authors from the need to support multiple image libraries, and it + * allows site administrators to choose the library that's best for them. + * + * PHP includes the GD library by default so a GD toolkit is installed with + * Drupal. Other toolkits like ImageMagick are available from contrib modules. + * GD works well for small images, but using it with larger files may cause PHP + * to run out of memory. In contrast the ImageMagick library does not suffer + * from this problem, but it requires the ISP to have installed additional + * software. + * + * Image toolkits are discovered using the Plugin system using + * \Drupal\system\Plugin\ImageToolkitManager. The toolkit must then be enabled + * using the admin/config/media/image-toolkit form. + * + * Only one toolkit may be selected at a time. If a module author wishes to call + * a specific toolkit they can check that it is installed by calling + * \Drupal\system\Plugin\ImageToolkitManager::getAvailableToolkits(), and then + * calling its functions directly. + */ + /** * Defines an interface for image toolkits. * * An image toolkit provides common image file manipulations like scaling, * cropping, and rotating. */ -interface ImageToolkitInterface { +interface ImageToolkitInterface extends PluginInspectionInterface { /** * Retrieves toolkit's settings form. @@ -32,7 +62,7 @@ function settingsFormSubmit($form, &$form_state); /** * Scales an image to the specified size. * - * @param object $image + * @param \Drupal\Core\Image\ImageInterface $image * An image object. The $image->resource, $image->info['width'], and * $image->info['height'] values will be modified by this call. * @param int $width @@ -42,15 +72,13 @@ function settingsFormSubmit($form, &$form_state); * * @return bool * TRUE or FALSE, based on success. - * - * @see image_resize() */ - function resize($image, $width, $height); + function resize(ImageInterface $image, $width, $height); /** * Rotates an image the given number of degrees. * - * @param object $image + * @param \Drupal\Core\Image\ImageInterface $image * An image object. The $image->resource, $image->info['width'], and * $image->info['height'] values will be modified by this call. * @param int $degrees @@ -64,15 +92,13 @@ function resize($image, $width, $height); * * @return bool * TRUE or FALSE, based on success. - * - * @see image_rotate() */ - function rotate($image, $degrees, $background = NULL); + function rotate(ImageInterface $image, $degrees, $background = NULL); /** * Crops an image. * - * @param object $image + * @param \Drupal\Core\Image\ImageInterface $image * An image object. The $image->resource, $image->info['width'], and * $image->info['height'] values will be modified by this call. * @param int $x @@ -89,56 +115,50 @@ function rotate($image, $degrees, $background = NULL); * * @see image_crop() */ - function crop($image, $x, $y, $width, $height); + function crop(ImageInterface $image, $x, $y, $width, $height); /** * Converts an image resource to grayscale. * * Note that transparent GIFs loose transparency when desaturated. * - * @param object $image + * @param \Drupal\Core\Image\ImageInterface $image * An image object. The $image->resource value will be modified by this * call. * * @return bool * TRUE or FALSE, based on success. - * - * @see image_desaturate() */ - function desaturate($image); + function desaturate(ImageInterface $image); /** * Creates an image resource from a file. * - * @param object $image + * @param \Drupal\Core\Image\ImageInterface $image * An image object. The $image->resource value will populated by this call. * * @return bool * TRUE or FALSE, based on success. - * - * @see image_load() */ - function load($image); + function load(ImageInterface $image); /** * Writes an image resource to a destination file. * - * @param object $image + * @param \Drupal\Core\Image\ImageInterface $image * An image object. * @param string $destination * A string file URI or path where the image should be saved. * * @return bool * TRUE or FALSE, based on success. - * - * @see image_save() */ - function save($image, $destination); + function save(ImageInterface $image, $destination); /** * Gets details about an image. * - * @param object $image + * @param \Drupal\Core\Image\ImageInterface $image * An image object. * * @return array @@ -149,9 +169,9 @@ function save($image, $destination); * - "extension": Commonly used file extension for the image. * - "mime_type": MIME type ('image/jpeg', 'image/gif', 'image/png'). * - * @see image_get_info() + * @see \Drupal\Core\Image\ImageInterface::processInfo() */ - function getInfo($image); + function getInfo(ImageInterface $image); /** * Verifies Image Toolkit is set up correctly. diff --git a/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitGdTest.php b/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitGdTest.php index 624dc79..1797b78 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitGdTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitGdTest.php @@ -7,8 +7,8 @@ namespace Drupal\system\Tests\Image; +use Drupal\Core\Image\ImageInterface; use Drupal\simpletest\DrupalUnitTestBase; -use Drupal\system\Plugin\ImageToolkitManager; /** * Test the core GD image manipulation functions. @@ -79,15 +79,15 @@ function colorsAreEqual($color_a, $color_b) { /** * Function for finding a pixel's RGBa values. */ - function getPixelColor($image, $x, $y) { - $color_index = imagecolorat($image->resource, $x, $y); + function getPixelColor(ImageInterface $image, $x, $y) { + $color_index = imagecolorat($image->getResource(), $x, $y); - $transparent_index = imagecolortransparent($image->resource); + $transparent_index = imagecolortransparent($image->getResource()); if ($color_index == $transparent_index) { return array(0, 0, 0, 127); } - return array_values(imagecolorsforindex($image->resource, $color_index)); + return array_values(imagecolorsforindex($image->getResource(), $color_index)); } /** @@ -152,7 +152,7 @@ function testManipulations() { 'corners' => array_fill(0, 4, $this->white), ), 'scale_and_crop' => array( - 'function' => 'scale_and_crop', + 'function' => 'scaleAndCrop', 'arguments' => array(10, 8), 'width' => 10, 'height' => 8, @@ -215,21 +215,22 @@ function testManipulations() { ); } - $manager = new ImageToolkitManager($this->container->get('container.namespaces'), $this->container->get('cache.cache'), $this->container->get('language_manager')); + $toolkit = $this->container->get('image.toolkit.manager')->createInstance('gd'); + $image_factory = $this->container->get('image.factory')->setToolkit($toolkit); foreach ($files as $file) { foreach ($operations as $op => $values) { // Load up a fresh image. - $image = image_load(drupal_get_path('module', 'simpletest') . '/files/' . $file, $manager->createInstance('gd')); + $image = $image_factory->get(drupal_get_path('module', 'simpletest') . '/files/' . $file); if (!$image) { $this->fail(t('Could not load image %file.', array('%file' => $file))); continue 2; } // All images should be converted to truecolor when loaded. - $image_truecolor = imageistruecolor($image->resource); + $image_truecolor = imageistruecolor($image->getResource()); $this->assertTrue($image_truecolor, format_string('Image %file after load is a truecolor image.', array('%file' => $file))); - if ($image->info['extension'] == 'gif') { + if ($image->getExtension() == 'gif') { if ($op == 'desaturate') { // Transparent GIFs and the imagefilter function don't work together. $values['corners'][3][3] = 0; @@ -237,11 +238,7 @@ function testManipulations() { } // Perform our operation. - $function = 'image_' . $values['function']; - $arguments = array(); - $arguments[] = &$image; - $arguments = array_merge($arguments, $values['arguments']); - call_user_func_array($function, $arguments); + call_user_func_array(array($image, $values['function']), $values['arguments']); // To keep from flooding the test with assert values, make a general // value for whether each group of values fail. @@ -250,24 +247,24 @@ function testManipulations() { $correct_colors = TRUE; // Check the real dimensions of the image first. - if (imagesy($image->resource) != $values['height'] || imagesx($image->resource) != $values['width']) { + if (imagesy($image->getResource()) != $values['height'] || imagesx($image->getResource()) != $values['width']) { $correct_dimensions_real = FALSE; } // Check that the image object has an accurate record of the dimensions. - if ($image->info['width'] != $values['width'] || $image->info['height'] != $values['height']) { + if ($image->getWidth() != $values['width'] || $image->getHeight() != $values['height']) { $correct_dimensions_object = FALSE; } $directory = $this->public_files_directory .'/imagetest'; file_prepare_directory($directory, FILE_CREATE_DIRECTORY); - image_save($image, $directory . '/' . $op . '.' . $image->info['extension']); + $image->save($directory . '/' . $op . '.' . $image->getExtension()); $this->assertTrue($correct_dimensions_real, format_string('Image %file after %action action has proper dimensions.', array('%file' => $file, '%action' => $op))); $this->assertTrue($correct_dimensions_object, format_string('Image %file object after %action action is reporting the proper height and width values.', array('%file' => $file, '%action' => $op))); // JPEG colors will always be messed up due to compression. - if ($image->info['extension'] != 'jpg') { + if ($image->getExtension() != 'jpg') { // Now check each of the corners to ensure color correctness. foreach ($values['corners'] as $key => $corner) { // Get the location of the corner. diff --git a/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTest.php b/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTest.php index 14a84e9..5f6c4dc 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTest.php @@ -10,7 +10,7 @@ use Drupal\system\Plugin\ImageToolkitManager; /** - * Test that the functions in image.inc correctly pass data to the toolkit. + * Tests that the methods in Image correctly pass data to the toolkit. */ class ToolkitTest extends ToolkitTestBase { public static function getInfo() { @@ -34,12 +34,12 @@ function testGetAvailableToolkits() { } /** - * Test the image_load() function. + * Tests Image's methods. */ function testLoad() { - $image = image_load($this->file, $this->toolkit); + $image = $this->getImage(); $this->assertTrue(is_object($image), 'Returned an object.'); - $this->assertEqual($this->toolkit, $image->toolkit, 'Image had toolkit set.'); + $this->assertEqual($this->toolkit->getPluginId(), $image->getToolkitId(), 'Image had toolkit set.'); $this->assertToolkitOperationsCalled(array('load', 'get_info')); } @@ -47,7 +47,7 @@ function testLoad() { * Test the image_save() function. */ function testSave() { - $this->assertFalse(image_save($this->image), 'Function returned the expected value.'); + $this->assertFalse($this->image->save(), 'Function returned the expected value.'); $this->assertToolkitOperationsCalled(array('save')); } @@ -55,7 +55,7 @@ function testSave() { * Test the image_resize() function. */ function testResize() { - $this->assertTrue(image_resize($this->image, 1, 2), 'Function returned the expected value.'); + $this->assertTrue($this->image->resize(1, 2), 'Function returned the expected value.'); $this->assertToolkitOperationsCalled(array('resize')); // Check the parameters. @@ -69,7 +69,7 @@ function testResize() { */ function testScale() { // TODO: need to test upscaling - $this->assertTrue(image_scale($this->image, 10, 10), 'Function returned the expected value.'); + $this->assertTrue($this->image->scale(10, 10), 'Function returned the expected value.'); $this->assertToolkitOperationsCalled(array('resize')); // Check the parameters. @@ -82,7 +82,7 @@ function testScale() { * Test the image_scale_and_crop() function. */ function testScaleAndCrop() { - $this->assertTrue(image_scale_and_crop($this->image, 5, 10), 'Function returned the expected value.'); + $this->assertTrue($this->image->scaleAndCrop(5, 10), 'Function returned the expected value.'); $this->assertToolkitOperationsCalled(array('resize', 'crop')); // Check the parameters. @@ -98,7 +98,7 @@ function testScaleAndCrop() { * Test the image_rotate() function. */ function testRotate() { - $this->assertTrue(image_rotate($this->image, 90, 1), 'Function returned the expected value.'); + $this->assertTrue($this->image->rotate(90, 1), 'Function returned the expected value.'); $this->assertToolkitOperationsCalled(array('rotate')); // Check the parameters. @@ -111,7 +111,7 @@ function testRotate() { * Test the image_crop() function. */ function testCrop() { - $this->assertTrue(image_crop($this->image, 1, 2, 3, 4), 'Function returned the expected value.'); + $this->assertTrue($this->image->crop(1, 2, 3, 4), 'Function returned the expected value.'); $this->assertToolkitOperationsCalled(array('crop')); // Check the parameters. @@ -126,7 +126,7 @@ function testCrop() { * Test the image_desaturate() function. */ function testDesaturate() { - $this->assertTrue(image_desaturate($this->image), 'Function returned the expected value.'); + $this->assertTrue($this->image->desaturate(), 'Function returned the expected value.'); $this->assertToolkitOperationsCalled(array('desaturate')); // Check the parameters. diff --git a/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTestBase.php index 80b1588..43cc2c2 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTestBase.php +++ b/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTestBase.php @@ -9,7 +9,6 @@ use Drupal\simpletest\WebTestBase; use Drupal\system\Plugin\ImageToolkitManager; -use stdClass; /** * Base class for image manipulation testing. @@ -23,8 +22,19 @@ */ public static $modules = array('image_test'); + /** + * @var \Drupal\system\Plugin\ImageToolkitInterface + */ protected $toolkit; + + /** + * @var string + */ protected $file; + + /** + * @var \Drupal\Core\Image\ImageInterface + */ protected $image; function setUp() { @@ -38,18 +48,28 @@ function setUp() { $file = current($this->drupalGetTestFiles('image')); $this->file = $file->uri; - // Setup a dummy image to work with, this replicate image_load() so we - // can avoid calling it. - $this->image = new stdClass(); - $this->image->source = $this->file; - $this->image->info = image_get_info($this->file); - $this->image->toolkit = $this->toolkit; + // Setup a dummy image to work with. + $this->image = $this->getImage(); // Clear out any hook calls. $this->imageTestReset(); } /** + * Sets up an image with the custom toolkit. + * + * @return \Drupal\Core\Image\ImageInterface + * The image object. + */ + protected function getImage() { + $image = $this->container->get('image.factory') + ->setToolkit($this->toolkit) + ->get($this->file); + $image->getResource(); + return $image; + } + + /** * Assert that all of the specified image toolkit operations were called * exactly once once, other values result in failure. * diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php index 97e730c..c680ea7 100644 --- a/core/modules/system/system.api.php +++ b/core/modules/system/system.api.php @@ -2150,8 +2150,8 @@ function hook_file_download($uri) { return -1; } else { - $info = image_get_info($uri); - return array('Content-Type' => $info['mime_type']); + $image = Drupal::service('image.factory')->get($uri); + return array('Content-Type' => $image->getMimeType()); } } } diff --git a/core/modules/system/tests/modules/image_test/lib/Drupal/image_test/Plugin/ImageToolkit/TestToolkit.php b/core/modules/system/tests/modules/image_test/lib/Drupal/image_test/Plugin/ImageToolkit/TestToolkit.php index 12ebae7..7f1492f 100644 --- a/core/modules/system/tests/modules/image_test/lib/Drupal/image_test/Plugin/ImageToolkit/TestToolkit.php +++ b/core/modules/system/tests/modules/image_test/lib/Drupal/image_test/Plugin/ImageToolkit/TestToolkit.php @@ -10,6 +10,7 @@ use Drupal\Component\Plugin\PluginBase; use Drupal\Component\Annotation\Plugin; use Drupal\Core\Annotation\Translation; +use Drupal\Core\Image\ImageInterface; use Drupal\system\Plugin\ImageToolkitInterface; /** @@ -23,7 +24,7 @@ class TestToolkit extends PluginBase implements ImageToolkitInterface { /** - * Implements \Drupal\system\Plugin\ImageToolkitInterface::settingsForm(). + * {@inheritdoc} */ public function settingsForm() { $this->logCall('settings', array()); @@ -31,30 +32,45 @@ public function settingsForm() { } /** - * Implements \Drupal\system\Plugin\ImageToolkitInterface::settingsFormSubmit(). + * {@inheritdoc} */ public function settingsFormSubmit($form, &$form_state) {} /** - * Implements \Drupal\system\Plugin\ImageToolkitInterface::getInfo(). + * {@inheritdoc} */ - public function getInfo($image) { + public function getInfo(ImageInterface $image) { $this->logCall('get_info', array($image)); - return array(); + + $details = FALSE; + $data = getimagesize($image->getSource()); + + if (isset($data) && is_array($data)) { + $extensions = array('1' => 'gif', '2' => 'jpg', '3' => 'png'); + $extension = isset($extensions[$data[2]]) ? $extensions[$data[2]] : ''; + $details = array( + 'width' => $data[0], + 'height' => $data[1], + 'extension' => $extension, + 'mime_type' => $data['mime'], + ); + } + + return $details; } /** - * Implements \Drupal\system\Plugin\ImageToolkitInterface::load(). + * {@inheritdoc} */ - public function load($image) { + public function load(ImageInterface $image) { $this->logCall('load', array($image)); return $image; } /** - * Implements \Drupal\system\Plugin\ImageToolkitInterface::save(). + * {@inheritdoc} */ - public function save($image, $destination) { + public function save(ImageInterface $image, $destination) { $this->logCall('save', array($image, $destination)); // Return false so that image_save() doesn't try to chmod the destination // file that we didn't bother to create. @@ -62,33 +78,33 @@ public function save($image, $destination) { } /** - * Implements \Drupal\system\Plugin\ImageToolkitInterface::crop(). + * {@inheritdoc} */ - public function crop($image, $x, $y, $width, $height) { + public function crop(ImageInterface $image, $x, $y, $width, $height) { $this->logCall('crop', array($image, $x, $y, $width, $height)); return TRUE; } /** - * Implements \Drupal\system\Plugin\ImageToolkitInterface::resize(). + * {@inheritdoc} */ - public function resize($image, $width, $height) { + public function resize(ImageInterface $image, $width, $height) { $this->logCall('resize', array($image, $width, $height)); return TRUE; } /** - * Implements \Drupal\system\Plugin\ImageToolkitInterface::rotate(). + * {@inheritdoc} */ - public function rotate($image, $degrees, $background = NULL) { + public function rotate(ImageInterface $image, $degrees, $background = NULL) { $this->logCall('rotate', array($image, $degrees, $background)); return TRUE; } /** - * Implements \Drupal\system\Plugin\ImageToolkitInterface::desaturate(). + * {@inheritdoc} */ - public function desaturate($image) { + public function desaturate(ImageInterface $image) { $this->logCall('desaturate', array($image)); return TRUE; } @@ -112,7 +128,7 @@ protected function logCall($op, $args) { } /** - * Implements Drupal\system\Plugin\ImageToolkitInterface::isAvailable(). + * {@inheritdoc} */ public static function isAvailable() { return TRUE; diff --git a/core/tests/Drupal/Tests/Component/Image/ImageTest.php b/core/tests/Drupal/Tests/Component/Image/ImageTest.php index 05d1be9..3129fa5 100644 --- a/core/tests/Drupal/Tests/Component/Image/ImageTest.php +++ b/core/tests/Drupal/Tests/Component/Image/ImageTest.php @@ -7,19 +7,19 @@ namespace Drupal\Tests\Component\Image; -use Drupal\Component\Image\Image; +use Drupal\Component\Utility\Image; use Drupal\Tests\UnitTestCase; /** * Tests the Image component. * - * @see \Drupal\Component\Image\Image + * @see \Drupal\Component\Utility\Image */ class ImageTest extends UnitTestCase { public static function getInfo() { return array( 'name' => 'Tests for the Image component', - 'description' => 'Tests all control flow branches in Drupal\Component\Image\Image.', + 'description' => 'Tests all control flow branches in \Drupal\Component\Utility\Image.', 'group' => 'Image', ); } @@ -58,7 +58,7 @@ function testScaleDimensions($input, $output) { */ public function providerTestScaleDimensions() { // Define input / output datasets to test different branch conditions. - $test = array(); + $tests = array(); // Test branch conditions: // - No height. diff --git a/core/tests/Drupal/Tests/Core/Image/ImageTest.php b/core/tests/Drupal/Tests/Core/Image/ImageTest.php new file mode 100644 index 0000000..92e4804 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Image/ImageTest.php @@ -0,0 +1,356 @@ + 'Image class functionality', + 'description' => 'Tests the Image class.', + 'group' => 'Image', + ); + } + + protected function setUp() { + // Use the Druplicon image. + $source = __DIR__ . '/../../../../../misc/druplicon.png'; + $this->toolkit = $this->getMockBuilder('Drupal\system\Plugin\ImageToolkit\GDToolkit') + ->disableOriginalConstructor() + ->getMock(); + + $this->toolkit->expects($this->any()) + ->method('getPluginId') + ->will($this->returnValue('gd')); + + $this->toolkit->expects($this->any()) + ->method('getInfo') + ->will($this->returnValue(array( + 'width' => 88, + 'height' => 100, + 'extension' => 'png', + 'mime_type' => 'image/png', + ))); + + $this->image = new Image($source, $this->toolkit); + } + + /** + * Tests Drupal\Core\Image\Image::getExtension(). + */ + public function testGetExtension() { + $this->assertEquals($this->image->getExtension(), 'png'); + } + + /** + * Tests Drupal\Core\Image\Image::getHeight(). + */ + public function testGetHeight() { + $this->assertEquals($this->image->getHeight(), 100); + } + + /** + * Tests Drupal\Core\Image\Image::setHeight(). + */ + public function testSetHeight() { + $this->image->getHeight(); + $this->image->setHeight(400); + $this->assertEquals($this->image->getHeight(), 400); + } + + /** + * Tests Drupal\Core\Image\Image::getWidth(). + */ + public function testGetWidth() { + $this->assertEquals($this->image->getWidth(), 88); + } + + /** + * Tests Drupal\Core\Image\Image::setWidth(). + */ + public function testSetWidth() { + $this->image->getHeight(); + $this->image->setWidth(337); + $this->assertEquals($this->image->getWidth(), 337); + } + + /** + * Tests Drupal\Core\Image\Image::getFileSize + */ + public function testGetFileSize() { + $this->assertEquals($this->image->getFileSize(), 3905); + } + + /** + * Tests Drupal\Core\Image\Image::getMimeType(). + */ + public function testGetMimeType() { + $this->assertEquals($this->image->getMimeType(), 'image/png'); + } + + /** + * Tests Drupal\Core\Image\Image::setResource(). + */ + public function testSetResource() { + $resource = fopen($this->image->getSource(), 'r'); + $this->image->setResource($resource); + $this->assertEquals($this->image->getResource(), $resource); + $this->image->setResource(FALSE); + $this->assertNotNull($this->image->getResource()); + } + + /** + * Tests Drupal\Core\Image\Image::hasResource(). + */ + public function testHasResource() { + $this->assertFalse($this->image->hasResource()); + $resource = fopen($this->image->getSource(), 'r'); + $this->image->setResource($resource); + $this->assertTrue($this->image->hasResource()); + } + + /** + * Tests Drupal\Core\Image\Image::setSource(). + */ + public function testSetSource() { + $source = __DIR__ . '/../../../../../misc/grippie.png'; + $this->image->setSource($source); + $this->assertEquals($this->image->getSource(), $source); + } + + /** + * Tests Drupal\Core\Image\Image::getToolkitId(). + */ + public function testGetToolkitId() { + $this->assertEquals($this->image->getToolkitId(), 'gd'); + } + + /** + * Tests Drupal\Core\Image\Image::save(). + */ + public function testSave() { + // This will fail if save() method isn't called on the toolkit. + $this->toolkit->expects($this->once()) + ->method('save') + ->will($this->returnValue(TRUE)); + + $image = $this->getMock('Drupal\Core\Image\Image', array('chmod'), array($this->image->getSource(), $this->toolkit)); + $image->expects($this->any()) + ->method('chmod') + ->will($this->returnValue(TRUE)); + + $image->save(); + } + + /** + * Tests Drupal\Core\Image\Image::save(). + */ + public function testSaveFails() { + // This will fail if save() method isn't called on the toolkit. + $this->toolkit->expects($this->once()) + ->method('save') + ->will($this->returnValue(FALSE)); + + $this->assertFalse($this->image->save()); + } + + /** + * Tests Drupal\Core\Image\Image::save(). + */ + public function testChmodFails() { + // This will fail if save() method isn't called on the toolkit. + $this->toolkit->expects($this->once()) + ->method('save') + ->will($this->returnValue(TRUE)); + + $image = $this->getMock('Drupal\Core\Image\Image', array('chmod'), array($this->image->getSource(), $this->toolkit)); + $image->expects($this->any()) + ->method('chmod') + ->will($this->returnValue(FALSE)); + + $this->assertFalse($image->save()); + } + + /** + * Tests Drupal\Core\Image\Image::save(). + */ + public function testProcessInfoFails() { + $this->image->setSource('magic-foobars.png'); + $this->assertFalse((bool) $this->image->getWidth()); + } + + /** + * Tests Drupal\Core\Image\Image::scale(). + */ + public function testScaleWidth() { + $this->toolkit->expects($this->once()) + ->method('resize') + ->will($this->returnArgument(2)); + $height = $this->image->scale(44); + $this->assertEquals($height, 50); + } + + /** + * Tests Drupal\Core\Image\Image::scale(). + */ + public function testScaleHeight() { + $this->toolkit->expects($this->once()) + ->method('resize') + ->will($this->returnArgument(1)); + + $width = $this->image->scale(NULL, 50); + $this->assertEquals($width, 44); + } + + /** + * Tests Drupal\Core\Image\Image::scale(). + */ + public function testScaleSame() { + // Dimensions are the same, resize should not be called. + $this->toolkit->expects($this->never()) + ->method('resize') + ->will($this->returnArgument(1)); + + $width = $this->image->scale(88, 100); + $this->assertEquals($width, 88); + } + + /** + * Tests Drupal\Core\Image\Image::scaleAndCrop(). + */ + public function testScaleAndCropWidth() { + $this->toolkit->expects($this->once()) + ->method('resize') + ->will($this->returnValue(TRUE)); + + $this->toolkit->expects($this->once()) + ->method('crop') + ->will($this->returnArgument(1)); + + $x = $this->image->scaleAndCrop(34, 50); + $this->assertEquals($x, 5); + } + + /** + * Tests Drupal\Core\Image\Image::scaleAndCrop(). + */ + public function testScaleAndCropHeight() { + $this->toolkit->expects($this->once()) + ->method('resize') + ->will($this->returnValue(TRUE)); + + $this->toolkit->expects($this->once()) + ->method('crop') + ->will($this->returnArgument(2)); + + $y = $this->image->scaleAndCrop(44, 40); + $this->assertEquals($y, 5); + } + + /** + * Tests Drupal\Core\Image\Image::scaleAndCrop(). + */ + public function testScaleAndCropFails() { + $this->toolkit->expects($this->once()) + ->method('resize') + ->will($this->returnValue(FALSE)); + + $this->toolkit->expects($this->never()) + ->method('crop'); + $this->image->scaleAndCrop(44, 40); + } + + /** + * Tests Drupal\Core\Image\Image::crop(). + */ + public function testCropWidth() { + $this->toolkit->expects($this->once()) + ->method('crop') + ->will($this->returnArgument(4)); + // Cropping with width only should preserve the aspect ratio. + $height = $this->image->crop(0, 0, 44, NULL); + $this->assertEquals($height, 50); + } + + /** + * Tests Drupal\Core\Image\Image::crop(). + */ + public function testCropHeight() { + $this->toolkit->expects($this->once()) + ->method('crop') + ->will($this->returnArgument(3)); + // Cropping with height only should preserve the aspect ratio. + $width = $this->image->crop(0, 0, NULL, 50); + $this->assertEquals($width, 44); + } + + /** + * Tests Drupal\Core\Image\Image::crop(). + */ + public function testCrop() { + $this->toolkit->expects($this->once()) + ->method('crop') + ->will($this->returnArgument(3)); + $width = $this->image->crop(0, 0, 44, 50); + $this->assertEquals($width, 44); + } + + /** + * Tests Drupal\Core\Image\Image::resize(). + */ + public function testResize() { + $this->toolkit->expects($this->exactly(2)) + ->method('resize') + ->will($this->returnArgument(1)); + // Resize with integer for width and height. + $this->image->resize(30, 40); + // Pass a float for width. + $width = $this->image->resize(30.4, 40); + // Ensure that the float was rounded to an integer first. + $this->assertEquals($width, 30); + } + + /** + * Tests Drupal\Core\Image\Image::desaturate(). + */ + public function testDesaturate() { + $this->toolkit->expects($this->once()) + ->method('desaturate'); + $this->image->desaturate(); + } + + /** + * Tests Drupal\Core\Image\Image::rotate(). + */ + public function testRotate() { + $this->toolkit->expects($this->once()) + ->method('rotate'); + $this->image->rotate(90); + } + +}