diff --git a/core/includes/image.inc b/core/includes/image.inc index 9e2d06f..447500e 100644 --- a/core/includes/image.inc +++ b/core/includes/image.inc @@ -5,8 +5,7 @@ * API for manipulating images. */ -use Drupal\system\Plugin\ImageToolkitInterface; -use Drupal\Component\Image\Image; +use Drupal\Core\Image\ImageFile; /** * @defgroup image Image toolkits @@ -44,8 +43,6 @@ * * @param string $filepath * String specifying the path of the image file. - * @param \Drupal\system\Plugin\ImageToolkitInterface $toolkit - * (optional) An image toolkit object to override the default. * * @return array * FALSE, if the file could not be found or is not an image. Otherwise, a @@ -55,276 +52,13 @@ * - "extension": Commonly used file extension for the image. * - "mime_type": MIME type ('image/jpeg', 'image/gif', 'image/png'). * - "file_size": File size in bytes. - */ -function image_get_info($filepath, ImageToolkitInterface $toolkit = NULL) { - $details = FALSE; - if (!is_file($filepath) && !is_uploaded_file($filepath)) { - return $details; - } - - if ($toolkit === NULL) { - $toolkit = Drupal::service('image.toolkit'); - } - if ($toolkit) { - $image = new stdClass(); - $image->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() + * \Drupal\Core\Image\ImageFile::getFileInfo(). */ -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; +function image_get_info($filepath) { + $image = new ImageFile($filepath); + return $image->getFileInfo(); } /** diff --git a/core/lib/Drupal/Core/Image/ImageFile.php b/core/lib/Drupal/Core/Image/ImageFile.php new file mode 100644 index 0000000..3e914f5 --- /dev/null +++ b/core/lib/Drupal/Core/Image/ImageFile.php @@ -0,0 +1,439 @@ +source = $source; + } + + /** + * Sets a value for a given key. + * + * @param string $key + * The key to set the value for. + * @param mixed $value + * The value to set for this key. + * + * @return self + * Returns this image file. + */ + public function set($key, $value) { + $this->info[$key] = $value; + return $this; + } + + /** + * Replaces the file info. + * + * @param array $info + * Information about this file. + * + * @return self + * Returns this image file. + */ + public function setInfo(array $info) { + $this->info = $info; + return $this; + } + + /** + * Retrieves specific information about this image file. + * + * @param string $key + * The key of the info to retrieve, e.g., 'height', 'width', 'extension', + * 'mime_type', 'file_size'. + * + * @return mixed|null + * The value requested, or NULL. + */ + public function get($key) { + $info = $this->getInfo(); + if (isset($info[$key])) { + return $info[$key]; + } + return NULL; + } + + /** + * Retrives all information about this image file. + * + * @return array + * An associative array of image file information. + */ + public function getInfo() { + if (!$this->info) { + $this->processInfo(); + } + return $this->info; + } + + /** + * Sets the image file resource. + * + * @param resource $resource + * The image file handle. + * + * @return self + * Returns this image file. + */ + public function setResource($resource) { + $this->resource = $resource; + return $this; + } + + /** + * Determines if this image file has a resource set. + * + * @return bool + * TRUE if this image file has a resource set, FALSE otherwise. + */ + public function hasResource() { + return (bool) $this->resource; + } + + /** + * Retrieves the image file resource. + * + * @return resource + * The image file handle. + */ + public function getResource() { + if (!$this->hasResource()) { + $this->processInfo(); + $this->getToolkit()->load($this); + } + return $this->resource; + } + + /** + * Sets the source path of the image file. + * + * @param string $source + * A string specifying the path of the image file. + * + * @return self + * Returns this image file. + */ + public function setSource($source) { + $this->source = $source; + return $this; + } + + /** + * Retrieves the source path of the image file. + * + * @return string + * The source path of the image file. + */ + public function getSource() { + return $this->source; + } + + /** + * Sets a custom image toolkit. + * + * @param \Drupal\system\Plugin\ImageToolkitInterface $toolkit + * The image toolkit to use for this image file. + * + * @return self + * Returns this image file. + */ + public function setToolkit(ImageToolkitInterface $toolkit) { + $this->toolkit = $toolkit; + return $this; + } + + /** + * Returns the image toolkit being used for this image file. + * + * If a custom toolkit was not specified, this will fallback to the default. + * + * @return \Drupal\system\Plugin\ImageToolkitInterface + * The image toolkit used for this image file. + */ + protected function getToolkit() { + if (!$this->toolkit) { + $this->toolkit = \Drupal::service('image.toolkit'); + } + return $this->toolkit; + } + + /** + * Returns the ID of the image toolkit used for this image file. + * + * @return string + * The ID of the image toolkit. + */ + public function getToolkitId() { + return $this->getToolkit()->getPluginId(); + } + + /** + * Gets details about an image. + * + * 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 array|bool + * FALSE, if the file could not be found or is not an image. Otherwise, a + * keyed array containing information about the image: + * - "width": Width, in pixels. + * - "height": Height, in pixels. + * - "extension": Commonly used file extension for the image. + * - "mime_type": MIME type ('image/jpeg', 'image/gif', 'image/png'). + * - "file_size": File size in bytes. + */ + public function getFileInfo() { + if ($this->processInfo()) { + return $this->getInfo(); + } + return FALSE; + } + + /** + * Closes the image and saves the changes to a file. + * + * @param string|null $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 \Drupal\system\Plugin\ImageToolkitInterface::save() + */ + public function save($destination = NULL) { + if (empty($destination)) { + $destination = $this->getSource(); + } + if ($return = $this->getToolkit()->save($this, $destination)) { + // Clear the cached file size and refresh the image information. + clearstatcache(TRUE, $destination); + $this->setSource($destination); + $this->processInfo(); + + if (drupal_chmod($destination)) { + return $return; + } + } + return FALSE; + } + + /** + * Prepares the image information. + * + * @return bool + * FALSE, if the file could not be found or is not an image. Otherwise, the + * image information is populated. + */ + protected function processInfo() { + $destination = $this->getSource(); + if (!is_file($destination) && !is_uploaded_file($destination)) { + return FALSE; + } + + if ($details = $this->getToolkit()->getInfo($this)) { + $details['file_size'] = filesize($destination); + $this->setInfo($details); + } + return TRUE; + } + + /** + * Scales an image while maintaining aspect ratio. + * + * The resulting image can be smaller for one or both target dimensions. + * + * @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. + */ + public function scale($width = NULL, $height = NULL, $upscale = FALSE) { + $dimensions = $this->getInfo(); + + // Scale the dimensions - if they don't change then just return success. + if (!Image::scaleDimensions($dimensions, $width, $height, $upscale)) { + return TRUE; + } + + return $this->resize($dimensions['width'], $dimensions['height']); + + } + + /** + * 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 int $width + * The target width, in pixels. + * @param int $height + * The target height, in pixels. + * + * @return bool + * TRUE on success, FALSE on failure. + */ + public function scaleAndCrop($width, $height) { + $scale = max($width / $this->get('width'), $height / $this->get('height')); + $x = ($this->get('width') * $scale - $width) / 2; + $y = ($this->get('height') * $scale - $height) / 2; + + if ($this->resize($this->get('width') * $scale, $this->get('height') * $scale)) { + return $this->crop($x, $y, $width, $height); + } + return FALSE; + } + + /** + * Crops an image to a rectangle specified by the given dimensions. + * + * @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 \Drupal\system\Plugin\ImageToolkitInterface::crop() + */ + function crop($x, $y, $width, $height) { + $aspect = $this->get('height') / $this->get('width'); + if (empty($height)) $height = $width / $aspect; + if (empty($width)) $width = $height * $aspect; + + $width = (int) round($width); + $height = (int) round($height); + + return $this->getToolkit()->crop($this, $x, $y, $width, $height); + } + + /** + * Resizes an image to the given dimensions (ignoring aspect ratio). + * + * @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 \Drupal\system\Plugin\ImageToolkitInterface::resize() + */ + public function resize($width, $height) { + $width = (int) round($width); + $height = (int) round($height); + + return $this->getToolkit()->resize($this, $width, $height); + } + + /** + * Converts an image to grayscale. + * + * @return bool + * TRUE on success, FALSE on failure. + * + * @see \Drupal\system\Plugin\ImageToolkitInterface::desaturate() + */ + public function desaturate() { + return $this->getToolkit()->desaturate($this); + } + + /** + * Rotates an image by the given number of degrees. + * + * @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 \Drupal\system\Plugin\ImageToolkitInterface::rotate() + */ + public function rotate($degrees, $background = NULL) { + return $this->getToolkit()->rotate($this, $degrees, $background); + } + +} diff --git a/core/modules/file/file.module b/core/modules/file/file.module index bcdb460..bbd5e11 100644 --- a/core/modules/file/file.module +++ b/core/modules/file/file.module @@ -5,11 +5,11 @@ * Defines a "managed_file" Form API field and a "file" field for Field module. */ +use Drupal\Core\Image\ImageFile; use Drupal\file\Plugin\Core\Entity\File; use Drupal\Component\Utility\NestedArray; use Drupal\Core\Template\Attribute; use Symfony\Component\HttpFoundation\JsonResponse; -use Drupal\file\FileUsage\DatabaseFileUsageBackend; use Drupal\file\FileUsage\FileUsageInterface; use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Ajax\ReplaceCommand; @@ -462,10 +462,11 @@ function file_validate_image_resolution(File $file, $maximum_dimensions = 0, $mi list($width, $height) = explode('x', $maximum_dimensions); if ($info['width'] > $width || $info['height'] > $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 = new ImageFile($file->getFileUri()); + if ($image->getResource()) { + $image->scale($width, $height); + $image->save(); + $file->filesize = $image->get('file_size'); drupal_set_message(t('The image was resized to fit within the maximum allowed dimensions of %dimensions pixels.', array('%dimensions' => $maximum_dimensions))); } else { diff --git a/core/modules/image/image.admin.inc b/core/modules/image/image.admin.inc index 5111177..b15258f 100644 --- a/core/modules/image/image.admin.inc +++ b/core/modules/image/image.admin.inc @@ -7,7 +7,6 @@ use Drupal\Component\Utility\String; use Drupal\image\ImageStyleInterface; -use Symfony\Component\HttpFoundation\RedirectResponse; /** * Menu callback; Listing of all current image styles. @@ -365,7 +364,7 @@ function theme_image_style_effects($variables) { * * @param $variables * An associative array containing: - * - style: \Drupal\image\ImageStyleInterface image style being previewed. + * - style: The image style array being previewed. * * @ingroup themeable */ @@ -391,9 +390,9 @@ function theme_image_style_preview($variables) { $original_attributes['style'] = 'width: ' . $original_width . 'px; height: ' . $original_height . 'px;'; // Set up preview file information. - $preview_file = $style->buildUri($original_path); + $preview_file = image_style_path($style->id(), $original_path); if (!file_exists($preview_file)) { - $style->createDerivative($original_path, $preview_file); + image_style_create_derivative($style, $original_path, $preview_file); } $preview_image = image_get_info($preview_file); if ($preview_image['width'] > $preview_image['height']) { diff --git a/core/modules/image/image.api.php b/core/modules/image/image.api.php index 2909507..471f9fa 100644 --- a/core/modules/image/image.api.php +++ b/core/modules/image/image.api.php @@ -32,8 +32,8 @@ function hook_image_effect_info_alter(&$effects) { * be cleared using this hook. This hook is called whenever a style is updated, * deleted, or any effect associated with the style is update or deleted. * - * @param \Drupal\image\ImageStyleInterface $style - * The image style object that is being flushed. + * @param Drupal\image\Plugin\Core\Entity\ImageStyle $style + * The image style array that is being flushed. */ function hook_image_style_flush($style) { // Empty cached data that contains information about the style. 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 71bc42c..5387cc5 100644 --- a/core/modules/image/image.module +++ b/core/modules/image/image.module @@ -6,17 +6,14 @@ */ use Drupal\Core\Entity\EntityInterface; -use Drupal\Core\Language\Language; +use Drupal\Core\Image\ImageFile; use Drupal\field\Plugin\Core\Entity\Field; use Drupal\field\Plugin\Core\Entity\FieldInstance; -use Drupal\image\ImageEffectInterface; -use Drupal\image\ImageStyleInterface; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException; use Drupal\Component\Utility\Crypt; -use Drupal\Component\Uuid\Uuid; use Drupal\file\Plugin\Core\Entity\File; use Drupal\image\Plugin\Core\Entity\ImageStyle; use Drupal\field\FieldInterface; @@ -361,7 +358,10 @@ function image_file_predelete(File $file) { function image_path_flush($path) { $styles = entity_load_multiple('image_style'); foreach ($styles as $style) { - $style->flush($path); + $image_path = image_style_path($style->id(), $path); + if (file_exists($image_path)) { + file_unmanaged_delete($image_path); + } } } @@ -405,16 +405,263 @@ function image_style_options($include_empty = TRUE) { * After generating an image, transfer it to the requesting agent. * * @param $style - * The image style. - * - * @todo: Remove this wrapper in https://drupal.org/node/1987712. + * The image style */ function image_style_deliver($style, $scheme) { $args = func_get_args(); array_shift($args); array_shift($args); $target = implode('/', $args); - return $style->deliver($scheme, $target); + + // Check that the style is defined, the scheme is valid, and the image + // derivative token is valid. (Sites which require image derivatives to be + // generated without a token can set the + // 'image.settings:allow_insecure_derivatives' configuration to TRUE to bypass + // the latter check, but this will increase the site's vulnerability to + // denial-of-service attacks.) + $valid = !empty($style) && file_stream_wrapper_valid_scheme($scheme); + if (!config('image.settings')->get('allow_insecure_derivatives')) { + $image_derivative_token = Drupal::request()->query->get(IMAGE_DERIVATIVE_TOKEN); + $valid = $valid && isset($image_derivative_token) && $image_derivative_token === image_style_path_token($style->name, $scheme . '://' . $target); + } + if (!$valid) { + throw new AccessDeniedHttpException(); + } + + $image_uri = $scheme . '://' . $target; + $derivative_uri = image_style_path($style->id(), $image_uri); + + // If using the private scheme, let other modules provide headers and + // control access to the file. + if ($scheme == 'private') { + if (file_exists($derivative_uri)) { + file_download($scheme, file_uri_target($derivative_uri)); + } + else { + $headers = module_invoke_all('file_download', $image_uri); + if (in_array(-1, $headers) || empty($headers)) { + throw new AccessDeniedHttpException(); + } + if (count($headers)) { + foreach ($headers as $name => $value) { + drupal_add_http_header($name, $value); + } + } + } + } + + // Don't try to generate file if source is missing. + if (!file_exists($image_uri)) { + watchdog('image', 'Source image at %source_image_path not found while trying to generate derivative image at %derivative_path.', array('%source_image_path' => $image_uri, '%derivative_path' => $derivative_uri)); + return new Response(t('Error generating image, missing source file.'), 404); + } + + // Don't start generating the image if the derivative already exists or if + // generation is in progress in another thread. + $lock_name = 'image_style_deliver:' . $style->id() . ':' . Crypt::hashBase64($image_uri); + if (!file_exists($derivative_uri)) { + $lock_acquired = lock()->acquire($lock_name); + if (!$lock_acquired) { + // Tell client to retry again in 3 seconds. Currently no browsers are known + // to support Retry-After. + throw new ServiceUnavailableHttpException(3, t('Image generation in progress. Try again shortly.')); + } + } + + // Try to generate the image, unless another thread just did it while we were + // acquiring the lock. + $success = file_exists($derivative_uri) || image_style_create_derivative($style, $image_uri, $derivative_uri); + + if (!empty($lock_acquired)) { + lock()->release($lock_name); + } + + if ($success) { + $image = new ImageFile($derivative_uri); + $uri = $image->getSource(); + $headers = array( + 'Content-Type' => $image->get('mime_type'), + 'Content-Length' => $image->get('file_size'), + ); + return new BinaryFileResponse($uri, 200, $headers); + } + else { + watchdog('image', 'Unable to generate the derived image located at %path.', array('%path' => $derivative_uri)); + return new Response(t('Error generating image.'), 500); + } +} + +/** + * Creates a new image derivative based on an image style. + * + * Generates an image derivative by creating the destination folder (if it does + * not already exist), applying all image effects defined in + * $style->getEffects(), and saving a cached version of the resulting image. + * + * @param $style + * An image style array. + * @param $source + * Path of the source file. + * @param $destination + * Path or URI of the destination file. + * + * @return + * TRUE if an image derivative was generated, or FALSE if the image derivative + * could not be generated. + * + * @see image_style_load() + */ +function image_style_create_derivative($style, $source, $destination) { + // Get the folder for the final location of this style. + $directory = drupal_dirname($destination); + + // Build the destination folder tree if it doesn't already exist. + if (!file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) { + watchdog('image', 'Failed to create style directory: %directory', array('%directory' => $directory), WATCHDOG_ERROR); + return FALSE; + } + + $image = new ImageFile($source); + if (!$image->getResource()) { + return FALSE; + } + + foreach ($style->getEffects() as $effect) { + $effect->processEffect($image); + } + + if (!$image->save($destination)) { + if (file_exists($destination)) { + watchdog('image', 'Cached image file %destination already exists. There may be an issue with your rewrite configuration.', array('%destination' => $destination), WATCHDOG_ERROR); + } + return FALSE; + } + + return TRUE; +} + +/** + * Determines the dimensions of the styled image. + * + * Applies all of an image style's effects to $dimensions. + * + * @param $style_name + * The name of the style to be applied. + * @param $dimensions + * Dimensions to be modified - an array with components width and height, in + * pixels. + */ +function image_style_transform_dimensions($style_name, array &$dimensions) { + $style = entity_load('image_style', $style_name); + + foreach ($style->getEffects() as $effect) { + $effect->processDimensions($dimensions); + } +} + +/** + * Returns the URL for an image derivative given a style and image path. + * + * @param $style_name + * The name of the style to be used with this image. + * @param $path + * The path to the image. + * @param $clean_urls + * (optional) Whether clean URLs are in use. + * @return + * The absolute URL where a style image can be downloaded, suitable for use + * in an tag. Requesting the URL will cause the image to be created. + * @see image_style_deliver() + */ +function image_style_url($style_name, $path, $clean_urls = NULL) { + $uri = image_style_path($style_name, $path); + // The token query is added even if the + // 'image.settings:allow_insecure_derivatives' configuration is TRUE, so that + // the emitted links remain valid if it is changed back to the default FALSE. + // However, sites which need to prevent the token query from being emitted at + // all can additionally set the 'image.settings:suppress_itok_output' + // configuration to TRUE to achieve that (if both are set, the security token + // will neither be emitted in the image derivative URL nor checked for in + // image_style_deliver()). + $token_query = array(); + if (!config('image.settings')->get('suppress_itok_output')) { + $token_query = array(IMAGE_DERIVATIVE_TOKEN => image_style_path_token($style_name, file_stream_wrapper_uri_normalize($path))); + } + + if ($clean_urls === NULL) { + // Assume clean URLs unless the request tells us otherwise. + $clean_urls = TRUE; + try { + $request = Drupal::request(); + $clean_urls = $request->attributes->get('clean_urls'); + } + catch (ServiceNotFoundException $e) { + } + } + + // If not using clean URLs, the image derivative callback is only available + // with the script path. If the file does not exist, use url() to ensure + // that it is included. Once the file exists it's fine to fall back to the + // actual file path, this avoids bootstrapping PHP once the files are built. + if ($clean_urls === FALSE && file_uri_scheme($uri) == 'public' && !file_exists($uri)) { + $directory_path = file_stream_wrapper_get_instance_by_uri($uri)->getDirectoryPath(); + return url($directory_path . '/' . file_uri_target($uri), array('absolute' => TRUE, 'query' => $token_query)); + } + + $file_url = file_create_url($uri); + // Append the query string with the token, if necessary. + if ($token_query) { + $file_url .= (strpos($file_url, '?') !== FALSE ? '&' : '?') . drupal_http_build_query($token_query); + } + + return $file_url; +} + +/** + * Generates a token to protect an image style derivative. + * + * This prevents unauthorized generation of an image style derivative, + * which can be costly both in CPU time and disk space. + * + * @param string $style_name + * The name of the image style. + * @param string $uri + * The URI of the image for this style, for example as returned by + * image_style_path(). + * + * @return string + * An eight-character token which can be used to protect image style + * derivatives against denial-of-service attacks. + */ +function image_style_path_token($style_name, $uri) { + // Return the first eight characters. + return substr(Crypt::hmacBase64($style_name . ':' . $uri, drupal_get_private_key() . drupal_get_hash_salt()), 0, 8); +} + +/** + * Returns the URI of an image when using a style. + * + * The path returned by this function may not exist. The default generation + * method only creates images when they are requested by a user's browser. + * + * @param $style_name + * The name of the style to be used with this image. + * @param $uri + * The URI or path to the image. + * @return + * The URI to an image style image. + * @see image_style_url() + */ +function image_style_path($style_name, $uri) { + $scheme = file_uri_scheme($uri); + if ($scheme) { + $path = file_uri_target($uri); + } + else { + $path = $uri; + $scheme = file_default_scheme(); + } + return $scheme . '://styles/' . $style_name . '/' . $scheme . '/' . $path; } /** @@ -438,15 +685,13 @@ function image_style_deliver($style, $scheme) { * @ingroup themeable */ function theme_image_style($variables) { - $style = entity_load('image_style', $variables['style_name']); - // Determine the dimensions of the styled image. $dimensions = array( 'width' => $variables['width'], 'height' => $variables['height'], ); - $style->transformDimensions($dimensions); + image_style_transform_dimensions($variables['style_name'], $dimensions); // Add in the image style name as an HTML class. $variables['attributes']['class'][] = 'image-style-' . drupal_html_class($variables['style_name']); @@ -456,7 +701,7 @@ function theme_image_style($variables) { '#width' => $dimensions['width'], '#height' => $dimensions['height'], '#attributes' => $variables['attributes'], - '#uri' => $style->buildUrl($variables['uri']), + '#uri' => image_style_url($variables['style_name'], $variables['uri']), ); if (isset($variables['alt'])) { diff --git a/core/modules/image/lib/Drupal/image/ImageEffectInterface.php b/core/modules/image/lib/Drupal/image/ImageEffectInterface.php index 2c13129..a9ee455 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\ImageFile; /** * Defines the interface for image effects. @@ -17,13 +18,13 @@ /** * Applies an image effect to the image object. * - * @param \stdClass $image + * @param \Drupal\Core\Image\ImageFile $image * An image object returned by image_load(). * * @return bool * TRUE on success. FALSE if unable to perform the image effect on the image. */ - public function processEffect($image); + public function processEffect(ImageFile $image); /** * Determines the dimensions of the styled image. diff --git a/core/modules/image/lib/Drupal/image/ImageStyleInterface.php b/core/modules/image/lib/Drupal/image/ImageStyleInterface.php index 717be6a..f808eb6 100644 --- a/core/modules/image/lib/Drupal/image/ImageStyleInterface.php +++ b/core/modules/image/lib/Drupal/image/ImageStyleInterface.php @@ -16,104 +16,6 @@ interface ImageStyleInterface extends ConfigEntityInterface { /** - * Deliver an image derivative. - * - * Transfers a generated image derivative to the requesting agent. Modules may - * implement this method to set different serve different image derivatives - * from different stream wrappers or to customize different permissions on - * each image style. - * - * @param string $scheme - * The scheme name of the original image file stream wrapper ('public', - * 'private', 'temporary', etc.). - * @param string $target - * The target part of the uri. - * - * @return \Symfony\Component\HttpFoundation\BinaryFileResponse|\Symfony\Component\HttpFoundation\Response - * The image to be delivered. - * - * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException - * \Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException - * - * @todo: Move to controller after https://drupal.org/node/1987712. - */ - public function deliver($scheme, $target); - - /** - * Returns the URI of this image when using this style. - * - * The path returned by this function may not exist. The default generation - * method only creates images when they are requested by a user's browser. - * Modules may implement this method to decide where to place derivatives. - * - * @param string $uri - * The URI or path to the original image. - * - * @return string - * The URI to the image derivative for this style. - */ - public function buildUri($uri); - - /** - * Returns the URL of this image derivative for an original image path or URI. - * - * @param string $path - * The path or URI to the original image. - * @param mixed $clean_urls - * (optional) Whether clean URLs are in use. - * - * @return string - * The absolute URL where a style image can be downloaded, suitable for use - * in an tag. Requesting the URL will cause the image to be created. - * - * @see \Drupal\image\ImageStyleInterface::deliver() - */ - public function buildUrl($path, $clean_urls = NULL); - - /** - * Flushes cached media for this style. - * - * @param string $path - * (optional) The original image path or URI. If it's supplied, only this - * image derivative will be flushed. - * - * @return self - * This image style. - */ - public function flush($path = NULL); - - /** - * Creates a new image derivative based on this image style. - * - * Generates an image derivative applying all image effects and saving the - * resulting image. - * - * @param string $original_uri - * Original image file URI. - * @param string $derivative_uri - * Derivative image file URI. - * - * @return bool - * TRUE if an image derivative was generated, or FALSE if the image - * derivative could not be generated. - */ - public function createDerivative($original_uri, $derivative_uri); - - /** - * Determines the dimensions of this image style. - * - * Stores the dimensions of this image style into $dimensions associative - * array. Implementations have to provide at least values to next keys: - * - width: Integer with the derivative image width. - * - height: Integer with the derivative image height. - * - * @param array $dimensions - * Associative array passed by reference. Implementations have to store the - * resulting width and height, in pixels. - */ - public function transformDimensions(array &$dimensions); - - /** * Returns a specific image effect. * * @param string $effect @@ -127,12 +29,20 @@ public function getEffect($effect); /** * Returns the image effects for this style. * - * @return \Drupal\image\ImageEffectBag|\Drupal\image\ImageEffectInterface[] + * @return \Drupal\image\ImageEffectBag * The image effect plugin bag. */ public function getEffects(); /** + * Flushes cached media for a style. + * + * @return self + * This image style. + */ + public function flush(); + + /** * Saves an image effect for this style. * * @param array $configuration 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 71ef480..d8163c4 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 @@ -14,12 +14,6 @@ use Drupal\image\ImageEffectBag; use Drupal\image\ImageEffectInterface; use Drupal\image\ImageStyleInterface; -use Drupal\Component\Utility\Crypt; -use Drupal\Component\Utility\Url; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpFoundation\BinaryFileResponse; -use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; -use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException; /** * Defines an image style configuration entity. @@ -96,17 +90,11 @@ public function id() { * {@inheritdoc} */ public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) { - if ($update) { - if (!empty($this->original) && $this->id() !== $this->original->id()) { - // The old image style name needs flushing after a rename. - $this->original->flush(); - // Update field instance settings if necessary. - static::replaceImageStyle($this); - } - else { - // Flush image style when updating without changing the name. - $this->flush(); - } + if ($update && !empty($this->original) && $this->id() !== $this->original->id()) { + // The old image style name needs flushing after a rename. + $this->original->flush(); + // Update field instance settings if necessary. + static::replaceImageStyle($this); } } @@ -131,7 +119,7 @@ public static function postDelete(EntityStorageControllerInterface $storage_cont /** * Update field instance settings if the image style name is changed. * - * @param \Drupal\image\ImageStyleInterface $style + * @param \Drupal\image\Plugin\Core\Entity\ImageStyle $style * The image style. */ protected static function replaceImageStyle(ImageStyle $style) { @@ -169,164 +157,54 @@ protected static function replaceImageStyle(ImageStyle $style) { /** * {@inheritdoc} - * - * @todo: Move to controller after https://drupal.org/node/1987712. */ - public function deliver($scheme, $target) { - - // Check that the scheme is valid, and the image derivative token is valid. - // (Sites which require image derivatives to be generated without a token - // can set the 'image.settings:allow_insecure_derivatives' configuration to - // TRUE to bypass the latter check, but this will increase the site's - // vulnerability to denial-of-service attacks.) - $valid = file_stream_wrapper_valid_scheme($scheme); - if (!\Drupal::config('image.settings')->get('allow_insecure_derivatives')) { - $image_derivative_token = \Drupal::request()->query->get(IMAGE_DERIVATIVE_TOKEN); - $valid = $valid && isset($image_derivative_token) && $image_derivative_token === $this->getPathToken($scheme . '://' . $target); - } - if (!$valid) { - throw new AccessDeniedHttpException(); - } - - $original_uri = $scheme . '://' . $target; - $derivative_uri = $this->buildUri($original_uri); - $headers_to_send = array(); - // If using the private scheme, let other modules provide headers and - // control access to the file. - if ($scheme == 'private') { - if (file_exists($derivative_uri)) { - file_download($scheme, file_uri_target($derivative_uri)); - } - else { - $headers = \Drupal::moduleHandler()->invokeAll('file_download', array($original_uri)); - if (in_array(-1, $headers) || empty($headers)) { - throw new AccessDeniedHttpException(); - } - if (count($headers)) { - foreach ($headers as $name => $value) { - $headers_to_send[$name] = $value; - } - } - } - } - - // Don't try to generate file if source is missing. - if (!file_exists($original_uri)) { - watchdog('image', 'Source image at %source_image_path not found while trying to generate derivative image at %derivative_path.', array('%source_image_path' => $original_uri, '%derivative_path' => $derivative_uri)); - return new Response(t('Error generating image, missing source file.'), 404); - } - - // Don't start generating the image if the derivative already exists or if - // generation is in progress in another thread. - $lock_name = 'image_style_deliver:' . $this->id() . ':' . Crypt::hashBase64($original_uri); - if (!file_exists($derivative_uri)) { - $lock_acquired = \Drupal::lock()->acquire($lock_name); - if (!$lock_acquired) { - // Tell client to retry again in 3 seconds. Currently no browsers are - // known to support Retry-After. - throw new ServiceUnavailableHttpException(3, t('Image generation in progress. Try again shortly.')); - } - } - - // Try to generate the image, unless another thread just did it while we - // were acquiring the lock. - $success = file_exists($derivative_uri) || $this->createDerivative($original_uri, $derivative_uri); - - if (!empty($lock_acquired)) { - \Drupal::lock()->release($lock_name); - } - - if ($success) { - $image = image_load($derivative_uri); - $uri = $image->source; - $headers = $headers_to_send + array( - 'Content-Type' => $image->info['mime_type'], - 'Content-Length' => $image->info['file_size'], - ); - return new BinaryFileResponse($uri, 200, $headers); - } - else { - watchdog('image', 'Unable to generate the derived image located at %path.', array('%path' => $derivative_uri)); - return new Response(t('Error generating image.'), 500); - } + public function getEffect($effect) { + return $this->getEffects()->get($effect); } /** * {@inheritdoc} */ - public function buildUri($uri) { - $scheme = file_uri_scheme($uri); - if ($scheme) { - $path = file_uri_target($uri); + public function getEffects() { + if (!$this->effectsBag) { + $this->effectsBag = new ImageEffectBag(\Drupal::service('plugin.manager.image.effect'), $this->effects); } - else { - $path = $uri; - $scheme = file_default_scheme(); - } - return $scheme . '://styles/' . $this->id() . '/' . $scheme . '/' . $path; + return $this->effectsBag; } /** * {@inheritdoc} */ - public function buildUrl($path, $clean_urls = NULL) { - $uri = $this->buildUri($path); - // The token query is added even if the - // 'image.settings:allow_insecure_derivatives' configuration is TRUE, so - // that the emitted links remain valid if it is changed back to the default - // FALSE. However, sites which need to prevent the token query from being - // emitted at all can additionally set the - // 'image.settings:suppress_itok_output' configuration to TRUE to achieve - // that (if both are set, the security token will neither be emitted in the - // image derivative URL nor checked for in - // \Drupal\image\ImageStyleInterface::deliver()). - $token_query = array(); - if (!\Drupal::config('image.settings')->get('suppress_itok_output')) { - $token_query = array(IMAGE_DERIVATIVE_TOKEN => $this->getPathToken(file_stream_wrapper_uri_normalize($path))); - } - - if ($clean_urls === NULL) { - // Assume clean URLs unless the request tells us otherwise. - $clean_urls = TRUE; - try { - $request = \Drupal::request(); - $clean_urls = $request->attributes->get('clean_urls'); - } - catch (ServiceNotFoundException $e) { - } - } - - // If not using clean URLs, the image derivative callback is only available - // with the script path. If the file does not exist, use url() to ensure - // that it is included. Once the file exists it's fine to fall back to the - // actual file path, this avoids bootstrapping PHP once the files are built. - if ($clean_urls === FALSE && file_uri_scheme($uri) == 'public' && !file_exists($uri)) { - $directory_path = file_stream_wrapper_get_instance_by_uri($uri)->getDirectoryPath(); - return url($directory_path . '/' . file_uri_target($uri), array('absolute' => TRUE, 'query' => $token_query)); - } - - $file_url = file_create_url($uri); - // Append the query string with the token, if necessary. - if ($token_query) { - $file_url .= (strpos($file_url, '?') !== FALSE ? '&' : '?') . Url::buildQuery($token_query); - } - - return $file_url; + public function saveImageEffect(array $configuration) { + $effect_id = $this->getEffects()->setConfig($configuration); + $this->save(); + $this->flush(); + return $effect_id; } /** * {@inheritdoc} */ - public function flush($path = NULL) { - // A specific image path has been provided. Flush only that derivative. - if (isset($path)) { - $derivative_uri = $this->buildUri($path); - if (file_exists($derivative_uri)) { - file_unmanaged_delete($derivative_uri); - } - return $this; - } + public function deleteImageEffect(ImageEffectInterface $effect) { + $this->getEffects()->removeInstanceID($effect->getUuid()); + $this->save(); + $this->flush(); + return $this; + } + /** + * {@inheritdoc} + */ + public function getExportProperties() { + $properties = parent::getExportProperties(); + $properties['effects'] = $this->getEffects()->sort()->export(); + return $properties; + } + + /** + * {@inheritdoc} + */ + public function flush() { // Delete the style directory in each registered wrapper. $wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_WRITE_VISIBLE); foreach ($wrappers as $wrapper => $wrapper_data) { @@ -349,107 +227,4 @@ public function flush($path = NULL) { return $this; } - /** - * {@inheritdoc} - */ - public function createDerivative($original_uri, $derivative_uri) { - // Get the folder for the final location of this style. - $directory = drupal_dirname($derivative_uri); - - // Build the destination folder tree if it doesn't already exist. - if (!file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) { - watchdog('image', 'Failed to create style directory: %directory', array('%directory' => $directory), WATCHDOG_ERROR); - return FALSE; - } - - if (!$image = image_load($original_uri)) { - return FALSE; - } - - foreach ($this->getEffects() as $effect) { - $effect->processEffect($image); - } - - if (!image_save($image, $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); - } - return FALSE; - } - - return TRUE; - } - - /** - * {@inheritdoc} - */ - public function transformDimensions(array &$dimensions) { - foreach ($this->getEffects() as $effect) { - $effect->processDimensions($dimensions); - } - } - - /** - * Generates a token to protect an image style derivative. - * - * This prevents unauthorized generation of an image style derivative, - * which can be costly both in CPU time and disk space. - * - * @param string $uri - * The URI of the image for this style, for example as returned by - * \Drupal\image\ImageStyleInterface::buildUri(). - * - * @return string - * An eight-character token which can be used to protect image style - * derivatives against denial-of-service attacks. - */ - protected function getPathToken($uri) { - // Return the first eight characters. - return substr(Crypt::hmacBase64($this->id() . ':' . $uri, drupal_get_private_key() . drupal_get_hash_salt()), 0, 8); - } - - /** - * {@inheritdoc} - */ - public function deleteImageEffect(ImageEffectInterface $effect) { - $this->getEffects()->removeInstanceID($effect->getUuid()); - $this->save(); - return $this; - } - - /** - * {@inheritdoc} - */ - public function getEffect($effect) { - return $this->getEffects()->get($effect); - } - - /** - * {@inheritdoc} - */ - public function getEffects() { - if (!$this->effectsBag) { - $this->effectsBag = new ImageEffectBag(\Drupal::service('plugin.manager.image.effect'), $this->effects); - } - return $this->effectsBag; - } - - /** - * {@inheritdoc} - */ - public function saveImageEffect(array $configuration) { - $effect_id = $this->getEffects()->setConfig($configuration); - $this->save(); - return $effect_id; - } - - /** - * {@inheritdoc} - */ - public function getExportProperties() { - $properties = parent::getExportProperties(); - $properties['effects'] = $this->getEffects()->sort()->export(); - return $properties; - } - } 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 ae06d37..11cff96 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\ImageFile; use Drupal\image\Annotation\ImageEffect; /** @@ -24,17 +25,17 @@ class CropImageEffect extends ResizeImageEffect { /** * {@inheritdoc} */ - public function processEffect($image) { + public function processEffect(ImageFile $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->get('width'), $this->configuration['width']); + $y = image_filter_keyword($y, $image->get('height'), $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->get('mime_type'), '%dimensions' => $image->get('width') . 'x' . $image->get('height')), 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 b378f26..f2577c5 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\ImageFile; use Drupal\image\Annotation\ImageEffect; use Drupal\image\ImageEffectBase; @@ -32,9 +33,9 @@ public function processDimensions(array &$dimensions) { /** * {@inheritdoc} */ - public function processEffect($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 processEffect(ImageFile $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->get('mime_type'), '%dimensions' => $image->get('width') . 'x' . $image->get('height')), 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 a40f7d3..71ee0e4 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\ImageFile; use Drupal\image\Annotation\ImageEffect; use Drupal\image\ImageEffectBase; @@ -25,9 +26,9 @@ class ResizeImageEffect extends ImageEffectBase { /** * {@inheritdoc} */ - public function processEffect($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 processEffect(ImageFile $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->get('mime_type'), '%dimensions' => $image->get('width') . 'x' . $image->get('height')), 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 b676d8d..053eac7 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\ImageFile; use Drupal\image\Annotation\ImageEffect; use Drupal\image\ImageEffectBase; @@ -25,7 +26,7 @@ class RotateImageEffect extends ImageEffectBase { /** * {@inheritdoc} */ - public function processEffect($image) { + public function processEffect(ImageFile $image) { // Set sane default values. $this->configuration += array( 'degrees' => 0, @@ -52,8 +53,8 @@ public function processEffect($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->get('mime_type'), '%dimensions' => $image->get('width') . 'x' . $image->get('height')), 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 9ee30f0..66fddf7 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\ImageFile; use Drupal\image\Annotation\ImageEffect; /** @@ -24,9 +25,9 @@ class ScaleAndCropImageEffect extends ResizeImageEffect { /** * {@inheritdoc} */ - public function processEffect($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 processEffect(ImageFile $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->get('mime_type'), '%dimensions' => $image->get('width') . 'x' . $image->get('height')), 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 45a6724..577e4b7 100644 --- a/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/ScaleImageEffect.php +++ b/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/ScaleImageEffect.php @@ -9,6 +9,7 @@ use Drupal\Component\Image\Image; use Drupal\Core\Annotation\Translation; +use Drupal\Core\Image\ImageFile; use Drupal\image\Annotation\ImageEffect; /** @@ -25,7 +26,7 @@ class ScaleImageEffect extends ResizeImageEffect { /** * {@inheritdoc} */ - public function processEffect($image) { + public function processEffect(ImageFile $image) { // Set sane default values. $this->configuration += array( 'width' => NULL, @@ -33,8 +34,8 @@ public function processEffect($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->get('mime_type'), '%dimensions' => $image->get('width') . 'x' . $image->get('height')), 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..f085f2d 100644 --- a/core/modules/image/lib/Drupal/image/Tests/FileMoveTest.php +++ b/core/modules/image/lib/Drupal/image/Tests/FileMoveTest.php @@ -39,9 +39,8 @@ function testNormal() { // Create derivative image. $styles = entity_load_multiple('image_style'); $style = image_style_load(key($styles)); - $original_uri = $file->getFileUri(); - $derivative_uri = $style->buildUri($original_uri); - $style->createDerivative($original_uri, $derivative_uri); + $derivative_uri = image_style_path($style->id(), $file->getFileUri()); + image_style_create_derivative($style, $file->getFileUri(), $derivative_uri); // Check if derivative image exists. $this->assertTrue(file_exists($derivative_uri), 'Make sure derivative image is generated successfully.'); diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageAdminStylesTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageAdminStylesTest.php index f69f9b2..62a97c4 100644 --- a/core/modules/image/lib/Drupal/image/Tests/ImageAdminStylesTest.php +++ b/core/modules/image/lib/Drupal/image/Tests/ImageAdminStylesTest.php @@ -36,7 +36,7 @@ function createSampleImage($style) { $file_path = file_unmanaged_copy($file->uri); } - return $style->buildUrl($file_path) ? $file_path : FALSE; + return image_style_url($style->id(), $file_path) ? $file_path : FALSE; } /** @@ -274,13 +274,9 @@ function testStyleReplacement() { $nid = $this->uploadNodeImage($test_image, $field_name, 'article'); $node = node_load($nid); - // Get node field original image URI. - $fid = $node->get($field_name)->target_id; - $original_uri = file_load($fid)->getFileUri(); - // Test that image is displayed using newly created style. $this->drupalGet('node/' . $nid); - $this->assertRaw($style->buildUrl($original_uri), format_string('Image displayed using style @style.', array('@style' => $style_name))); + $this->assertRaw(image_style_url($style_name, file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id'])->getFileUri()), format_string('Image displayed using style @style.', array('@style' => $style_name))); // Rename the style and make sure the image field is updated. $new_style_name = strtolower($this->randomName(10)); @@ -292,10 +288,7 @@ function testStyleReplacement() { $this->drupalPost($style_path . $style_name, $edit, t('Update style')); $this->assertText(t('Changes to the style have been saved.'), format_string('Style %name was renamed to %new_name.', array('%name' => $style_name, '%new_name' => $new_style_name))); $this->drupalGet('node/' . $nid); - - // Reload the image style using the new name. - $style = entity_load('image_style', $new_style_name); - $this->assertRaw($style->buildUrl($original_uri), 'Image displayed using style replacement style.'); + $this->assertRaw(image_style_url($new_style_name, file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id'])->getFileUri()), 'Image displayed using style replacement style.'); // Delete the style and choose a replacement style. $edit = array( @@ -305,9 +298,8 @@ function testStyleReplacement() { $message = t('Style %name was deleted.', array('%name' => $new_style_label)); $this->assertRaw($message); - $replacement_style = entity_load('image_style', 'thumbnail'); $this->drupalGet('node/' . $nid); - $this->assertRaw($replacement_style->buildUrl($original_uri), 'Image displayed using style replacement style.'); + $this->assertRaw(image_style_url('thumbnail', file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id'])->getFileUri()), 'Image displayed using style replacement style.'); } /** @@ -371,13 +363,9 @@ function testConfigImport() { $nid = $this->uploadNodeImage($test_image, $field_name, 'article'); $node = node_load($nid); - // Get node field original image URI. - $fid = $node->get($field_name)->target_id; - $original_uri = file_load($fid)->getFileUri(); - // Test that image is displayed using newly created style. $this->drupalGet('node/' . $nid); - $this->assertRaw($style->buildUrl($original_uri), format_string('Image displayed using style @style.', array('@style' => $style_name))); + $this->assertRaw(image_style_url($style_name, file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id'])->getFileUri()), format_string('Image displayed using style @style.', array('@style' => $style_name))); // Copy config to staging, and delete the image style. $staging = $this->container->get('config.storage.staging'); @@ -389,5 +377,4 @@ function testConfigImport() { $this->assertFalse(entity_load('image_style', $style_name), 'Style deleted after config import.'); $this->assertEqual($this->getImageCount($style), 0, 'Image style was flushed after being deleted by config import.'); } - } diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageDimensionsTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageDimensionsTest.php index 0ff6738..7f45aec 100644 --- a/core/modules/image/lib/Drupal/image/Tests/ImageDimensionsTest.php +++ b/core/modules/image/lib/Drupal/image/Tests/ImageDimensionsTest.php @@ -44,7 +44,7 @@ function testImageDimensions() { $style = entity_create('image_style', array('name' => 'test', 'label' => 'Test')); $style->save(); $generated_uri = 'public://styles/test/public/'. drupal_basename($original_uri); - $url = $style->buildUrl($original_uri); + $url = image_style_url('test', $original_uri); $variables = array( 'style_name' => 'test', diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php index e7775ad..c0f0cfd 100644 --- a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php +++ b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php @@ -112,7 +112,7 @@ function _testImageFieldFormatters($scheme) { // Ensure the derivative image is generated so we do not have to deal with // image style callback paths. - $this->drupalGet(entity_load('image_style', 'thumbnail')->buildUrl($image_uri)); + $this->drupalGet(image_style_url('thumbnail', $image_uri)); $image_info['uri'] = $image_uri; $image_info['width'] = 100; $image_info['height'] = 50; @@ -124,7 +124,7 @@ function _testImageFieldFormatters($scheme) { if ($scheme == 'private') { // Log out and try to access the file. $this->drupalLogout(); - $this->drupalGet(entity_load('image_style', 'thumbnail')->buildUrl($image_uri)); + $this->drupalGet(image_style_url('thumbnail', $image_uri)); $this->assertResponse('403', 'Access denied to image style thumbnail as anonymous user.'); } } diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageFieldTestBase.php b/core/modules/image/lib/Drupal/image/Tests/ImageFieldTestBase.php index 7d0f054..47f7091 100644 --- a/core/modules/image/lib/Drupal/image/Tests/ImageFieldTestBase.php +++ b/core/modules/image/lib/Drupal/image/Tests/ImageFieldTestBase.php @@ -15,11 +15,10 @@ * * image.effects.inc: * image_style_generate() - * \Drupal\image\ImageStyleInterface::createDerivative() + * image_style_create_derivative() * * image.module: * image_style_options() - * \Drupal\image\ImageStyleInterface::flush() * image_filter_keyword() */ diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageStyleFlushTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageStyleFlushTest.php index b5c3776..67cf051 100644 --- a/core/modules/image/lib/Drupal/image/Tests/ImageStyleFlushTest.php +++ b/core/modules/image/lib/Drupal/image/Tests/ImageStyleFlushTest.php @@ -34,8 +34,8 @@ function createSampleImage($style, $wrapper) { // Make sure we have an image in our wrapper testing file directory. $source_uri = file_unmanaged_copy($file->uri, $wrapper . '://'); // Build the derivative image. - $derivative_uri = $style->buildUri($source_uri); - $derivative = $style->createDerivative($source_uri, $derivative_uri); + $derivative_uri = image_style_path($style->id(), $source_uri); + $derivative = image_style_create_derivative($style, $source_uri, $derivative_uri); return $derivative ? $derivative_uri : FALSE; } diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageStylesPathAndUrlTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageStylesPathAndUrlTest.php index 8629dfb..1b9e2db 100644 --- a/core/modules/image/lib/Drupal/image/Tests/ImageStylesPathAndUrlTest.php +++ b/core/modules/image/lib/Drupal/image/Tests/ImageStylesPathAndUrlTest.php @@ -9,7 +9,6 @@ use Drupal\simpletest\WebTestBase; use Symfony\Component\HttpFoundation\Request; -use Drupal\image\Plugin\Core\Entity\ImageStyle; /** * Tests the functions for generating paths and URLs for image styles. @@ -23,7 +22,7 @@ class ImageStylesPathAndUrlTest extends WebTestBase { */ public static $modules = array('image', 'image_module_test'); - protected $style; + protected $style_name; protected $image_info; protected $image_filepath; @@ -38,59 +37,55 @@ public static function getInfo() { function setUp() { parent::setUp(); - $this->style = entity_create('image_style', array('name' => 'style_foo', 'label' => $this->randomString())); - $this->style->save(); + $this->style_name = 'style_foo'; + $style = entity_create('image_style', array('name' => $this->style_name, 'label' => $this->randomString())); + $style->save(); } /** - * Test \Drupal\image\Plugin\Core\Entity\ImageStyle::buildUri(). + * Test image_style_path(). */ function testImageStylePath() { $scheme = 'public'; - $actual = $this->style->buildUri("$scheme://foo/bar.gif"); - $expected = "$scheme://styles/" . $this->style->id() . "/$scheme/foo/bar.gif"; + $actual = image_style_path($this->style_name, "$scheme://foo/bar.gif"); + $expected = "$scheme://styles/" . $this->style_name . "/$scheme/foo/bar.gif"; $this->assertEqual($actual, $expected, 'Got the path for a file URI.'); - $actual = $this->style->buildUri('foo/bar.gif'); - $expected = "$scheme://styles/" . $this->style->id() . "/$scheme/foo/bar.gif"; + $actual = image_style_path($this->style_name, 'foo/bar.gif'); + $expected = "$scheme://styles/" . $this->style_name . "/$scheme/foo/bar.gif"; $this->assertEqual($actual, $expected, 'Got the path for a relative file path.'); } /** - * Test \Drupal\image\Plugin\Core\Entity\ImageStyle::buildUrl() with a file - * using the "public://" scheme. + * Test image_style_url() with a file using the "public://" scheme. */ function testImageStyleUrlAndPathPublic() { $this->_testImageStyleUrlAndPath('public'); } /** - * Test \Drupal\image\Plugin\Core\Entity\ImageStyle::buildUrl() with a file - * using the "private://" scheme. + * Test image_style_url() with a file using the "private://" scheme. */ function testImageStyleUrlAndPathPrivate() { $this->_testImageStyleUrlAndPath('private'); } /** - * Test \Drupal\image\Plugin\Core\Entity\ImageStyle::buildUrl() with the - * "public://" scheme and unclean URLs. + * Test image_style_url() with the "public://" scheme and unclean URLs. */ function testImageStylUrlAndPathPublicUnclean() { $this->_testImageStyleUrlAndPath('public', FALSE); } /** - * Test \Drupal\image\Plugin\Core\Entity\ImageStyle::buildUrl() with the - * "private://" schema and unclean URLs. + * Test image_style_url() with the "private://" schema and unclean URLs. */ function testImageStyleUrlAndPathPrivateUnclean() { $this->_testImageStyleUrlAndPath('private', FALSE); } /** - * Tests \Drupal\image\Plugin\Core\Entity\ImageStyle::buildUrl() with a file - * URL that has an extra slash in it. + * Tests image_style_url() with a file URL that has an extra slash in it. */ function testImageStyleUrlExtraSlash() { $this->_testImageStyleUrlAndPath('public', TRUE, TRUE); @@ -101,13 +96,13 @@ function testImageStyleUrlExtraSlash() { */ function testImageStyleUrlForMissingSourceImage() { $non_existent_uri = 'public://foo.png'; - $generated_url = $this->style->buildUrl($non_existent_uri); + $generated_url = image_style_url($this->style_name, $non_existent_uri); $this->drupalGet($generated_url); $this->assertResponse(404, 'Accessing an image style URL with a source image that does not exist provides a 404 error response.'); } /** - * Tests \Drupal\image\Plugin\Core\Entity\ImageStyle::buildUrl(). + * Tests image_style_url(). */ function _testImageStyleUrlAndPath($scheme, $clean_url = TRUE, $extra_slash = FALSE) { $request = $this->prepareRequestForGenerator($clean_url); @@ -117,7 +112,7 @@ function _testImageStyleUrlAndPath($scheme, $clean_url = TRUE, $extra_slash = FA config('system.file')->set('default_scheme', 'temporary')->save(); // Create the directories for the styles. - $directory = $scheme . '://styles/' . $this->style->id(); + $directory = $scheme . '://styles/' . $this->style_name; $status = file_prepare_directory($directory, FILE_CREATE_DIRECTORY); $this->assertNotIdentical(FALSE, $status, 'Created the directory for the generated images for the test style.'); @@ -132,9 +127,9 @@ function _testImageStyleUrlAndPath($scheme, $clean_url = TRUE, $extra_slash = FA $this->assertNotIdentical(FALSE, $original_uri, 'Created the generated image file.'); // Get the URL of a file that has not been generated and try to create it. - $generated_uri = $this->style->buildUri($original_uri); + $generated_uri = image_style_path($this->style_name, $original_uri); $this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.'); - $generate_url = $this->style->buildUrl($original_uri, $clean_url); + $generate_url = image_style_url($this->style_name, $original_uri, $clean_url); // Ensure that the tests still pass when the file is generated by accessing // a poorly constructed (but still valid) file URL that has an extra slash @@ -142,7 +137,7 @@ function _testImageStyleUrlAndPath($scheme, $clean_url = TRUE, $extra_slash = FA if ($extra_slash) { $modified_uri = str_replace('://', ':///', $original_uri); $this->assertNotEqual($original_uri, $modified_uri, 'An extra slash was added to the generated file URI.'); - $generate_url = $this->style->buildUrl($modified_uri, $clean_url); + $generate_url = image_style_url($this->style_name, $modified_uri, $clean_url); } if (!$clean_url) { $this->assertTrue(strpos($generate_url, 'index.php/') !== FALSE, 'When using non-clean URLS, the system path contains the script name.'); @@ -182,9 +177,9 @@ function _testImageStyleUrlAndPath($scheme, $clean_url = TRUE, $extra_slash = FA // make sure that access is denied. $file_noaccess = array_shift($files); $original_uri_noaccess = file_unmanaged_copy($file_noaccess->uri, $scheme . '://', FILE_EXISTS_RENAME); - $generated_uri_noaccess = $scheme . '://styles/' . $this->style->id() . '/' . $scheme . '/'. drupal_basename($original_uri_noaccess); + $generated_uri_noaccess = $scheme . '://styles/' . $this->style_name . '/' . $scheme . '/'. drupal_basename($original_uri_noaccess); $this->assertFalse(file_exists($generated_uri_noaccess), 'Generated file does not exist.'); - $generate_url_noaccess = $this->style->buildUrl($original_uri_noaccess); + $generate_url_noaccess = image_style_url($this->style_name, $original_uri_noaccess); $this->drupalGet($generate_url_noaccess); $this->assertResponse(403, 'Confirmed that access is denied for the private image style.'); @@ -221,9 +216,9 @@ function _testImageStyleUrlAndPath($scheme, $clean_url = TRUE, $extra_slash = FA // has not been created and try to create it. Check that the security token // is not present in the URL but that the image is still accessible. config('image.settings')->set('suppress_itok_output', TRUE)->save(); - $generated_uri = $this->style->buildUri($original_uri); + $generated_uri = image_style_path($this->style_name, $original_uri); $this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.'); - $generate_url = $this->style->buildUrl($original_uri, $clean_url); + $generate_url = image_style_url($this->style_name, $original_uri, $clean_url); $this->assertIdentical(strpos($generate_url, IMAGE_DERIVATIVE_TOKEN . '='), FALSE, 'The security token does not appear in the image style URL.'); $this->drupalGet($generate_url); $this->assertResponse(200, 'Image was accessible at the URL with a missing token.'); diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageThemeFunctionTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageThemeFunctionTest.php index f0d540f..cd00cb1 100644 --- a/core/modules/image/lib/Drupal/image/Tests/ImageThemeFunctionTest.php +++ b/core/modules/image/lib/Drupal/image/Tests/ImageThemeFunctionTest.php @@ -41,7 +41,7 @@ function testImageFormatterTheme() { // Create a style. $style = entity_create('image_style', array('name' => 'test', 'label' => 'Test')); $style->save(); - $url = $style->buildUrl($original_uri); + $url = image_style_url('test', $original_uri); // Test using theme_image_formatter() without an image title, alt text, or // link options. @@ -84,7 +84,7 @@ function testImageStyleTheme() { // Create a style. $style = entity_create('image_style', array('name' => 'image_test', 'label' => 'Test')); $style->save(); - $url = $style->buildUrl($original_uri); + $url = image_style_url('image_test', $original_uri); $path = $this->randomName(); $element = array( 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 158afb1..c5a9ad4 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\ImageFile; use Drupal\image\Annotation\ImageEffect; use Drupal\image\ImageEffectBase; @@ -25,7 +26,7 @@ class NullTestImageEffect extends ImageEffectBase { /** * {@inheritdoc} */ - public function processEffect($image) { + public function processEffect(ImageFile $image) { return TRUE; } diff --git a/core/modules/picture/lib/Drupal/picture/Tests/PictureFieldDisplayTest.php b/core/modules/picture/lib/Drupal/picture/Tests/PictureFieldDisplayTest.php index 8009241..b79ad21 100644 --- a/core/modules/picture/lib/Drupal/picture/Tests/PictureFieldDisplayTest.php +++ b/core/modules/picture/lib/Drupal/picture/Tests/PictureFieldDisplayTest.php @@ -182,8 +182,7 @@ public function _testPictureFieldFormatters($scheme) { $display->setComponent($field_name, $display_options) ->save(); - $large_style = entity_load('image_style', 'large'); - $this->drupalGet($large_style->buildUrl($image_uri)); + $this->drupalGet(image_style_url('large', $image_uri)); $image_info['uri'] = $image_uri; $image_info['width'] = 480; $image_info['height'] = 240; @@ -195,7 +194,7 @@ public function _testPictureFieldFormatters($scheme) { if ($scheme == 'private') { // Log out and try to access the file. $this->drupalLogout(); - $this->drupalGet($large_style->buildUrl($image_uri)); + $this->drupalGet(image_style_url('large', $image_uri)); $this->assertResponse('403', 'Access denied to image style thumbnail as anonymous user.'); } } diff --git a/core/modules/picture/picture.module b/core/modules/picture/picture.module index 680f05c..deba3b0 100644 --- a/core/modules/picture/picture.module +++ b/core/modules/picture/picture.module @@ -225,7 +225,7 @@ function theme_picture($variables) { // Fallback image, output as source with media query. $sources[] = array( - 'src' => entity_load('image_style', $variables['style_name'])->buildUrl($variables['uri']), + 'src' => image_style_url($variables['style_name'], $variables['uri']), 'dimensions' => picture_get_image_dimensions($variables), ); @@ -244,7 +244,7 @@ function theme_picture($variables) { // Only one image, use src. if (count($new_sources) == 1) { $sources[] = array( - 'src' => entity_load('image_style', $new_sources[0]['style_name'])->buildUrl($new_sources[0]['uri']), + 'src' => image_style_url($new_sources[0]['style_name'], $new_sources[0]['uri']), 'dimensions' => picture_get_image_dimensions($new_sources[0]), 'media' => $breakpoint->mediaQuery, ); @@ -253,7 +253,7 @@ function theme_picture($variables) { // Multiple images, use srcset. $srcset = array(); foreach ($new_sources as $new_source) { - $srcset[] = entity_load('image_style', $new_source['style_name'])->buildUrl($new_source['uri']) . ' ' . $new_source['#multiplier']; + $srcset[] = image_style_url($new_source['style_name'], $new_source['uri']) . ' ' . $new_source['#multiplier']; } $sources[] = array( 'srcset' => implode(', ', $srcset), @@ -338,7 +338,7 @@ function picture_get_image_dimensions($variables) { 'height' => $variables['height'], ); - entity_load('image_style', $variables['style_name'])->transformDimensions($dimensions); + image_style_transform_dimensions($variables['style_name'], $dimensions); return $dimensions; } diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/ImageFieldAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/ImageFieldAttributesTest.php index a622a8c..338ddfb 100644 --- a/core/modules/rdf/lib/Drupal/rdf/Tests/ImageFieldAttributesTest.php +++ b/core/modules/rdf/lib/Drupal/rdf/Tests/ImageFieldAttributesTest.php @@ -101,7 +101,7 @@ function testNodeTeaser() { // Construct the node and image URIs for testing. $node_uri = url('node/' . $this->node->id(), array('absolute' => TRUE)); - $image_uri = entity_load('image_style', 'medium')->buildUrl($this->file->getFileUri()); + $image_uri = image_style_url('medium', $this->file->getFileUri()); // Test relations from node to image. $expected_value = array( diff --git a/core/modules/rdf/rdf.module b/core/modules/rdf/rdf.module index 95c21f3..3c03d80 100644 --- a/core/modules/rdf/rdf.module +++ b/core/modules/rdf/rdf.module @@ -344,7 +344,7 @@ function rdf_preprocess_field(&$variables) { // this field has a URI. if (isset($item['entity']->uri)) { if (!empty($element[$delta]['#image_style'])) { - $variables['item_attributes'][$delta]['resource'] = entity_load('image_style', $element[$delta]['#image_style'])->buildUrl($item['entity']->getFileUri()); + $variables['item_attributes'][$delta]['resource'] = image_style_url($element[$delta]['#image_style'], $item['entity']->getFileUri()); } else { $variables['item_attributes'][$delta]['resource'] = file_create_url($item['entity']->getFileUri()); 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..70be018 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\ImageFile; use Drupal\system\Plugin\ImageToolkitInterface; /** @@ -50,33 +51,33 @@ public function settingsFormSubmit($form, &$form_state) { /** * Implements \Drupal\system\Plugin\ImageToolkitInterface::resize(). */ - public function resize($image, $width, $height) { + public function resize(ImageFile $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->get('width'), $image->get('height'))) { 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); + $image->set('width', $width); + $image->set('height', $height); return TRUE; } /** * Implements \Drupal\system\Plugin\ImageToolkitInterface::rotate(). */ - public function rotate($image, $degrees, $background = NULL) { + public function rotate(ImageFile $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->get('width'); + $height = $image->get('height'); // Convert the hexadecimal background value to a color index value. if (isset($background)) { @@ -84,88 +85,89 @@ 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->get('extension') == '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->set('width', imagesx($image->getResource())); + $image->set('height', imagesy($image->getResource())); return TRUE; } /** * Implements \Drupal\system\Plugin\ImageToolkitInterface::crop(). */ - public function crop($image, $x, $y, $width, $height) { + public function crop(ImageFile $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); + $image->set('width', $width); + $image->set('height', $height); return TRUE; } /** * Implements \Drupal\system\Plugin\ImageToolkitInterface::desaturate(). */ - public function desaturate($image) { + public function desaturate(ImageFile $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(). */ - public function load($image) { - $extension = str_replace('jpg', 'jpeg', $image->info['extension']); + public function load(ImageFile $image) { + $extension = str_replace('jpg', 'jpeg', $image->get('extension')); $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->get('width'), $image->get('height')); + imagecopy($new_image, $resource, 0, 0, 0, 0, $image->get('width'), $image->get('height')); + imagedestroy($resource); + $image->setResource($new_image); } - return (bool) $image->resource; + return (bool) $image->getResource(); } return FALSE; @@ -174,7 +176,7 @@ public function load($image) { /** * Implements \Drupal\system\Plugin\ImageToolkitInterface::save(). */ - public function save($image, $destination) { + public function save(ImageFile $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 +190,21 @@ public function save($image, $destination) { $destination = drupal_realpath($destination); } - $extension = str_replace('jpg', 'jpeg', $image->info['extension']); + $extension = str_replace('jpg', 'jpeg', $image->get('extension')); $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) { @@ -214,9 +216,9 @@ public function save($image, $destination) { /** * Implements \Drupal\system\Plugin\ImageToolkitInterface::getInfo(). */ - public function getInfo($image) { + public function getInfo(ImageFile $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'); @@ -248,13 +250,13 @@ public function getInfo($image) { public function createTmp($image, $width, $height) { $res = imagecreatetruecolor($width, $height); - if ($image->info['extension'] == 'gif') { + if ($image->get('extension') == '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 +264,7 @@ public function createTmp($image, $width, $height) { imagecolortransparent($res, $transparent); } } - elseif ($image->info['extension'] == 'png') { + elseif ($image->get('extension') == 'png') { imagealphablending($res, FALSE); $transparency = imagecolorallocatealpha($res, 0, 0, 0, 127); imagefill($res, 0, 0, $transparency); diff --git a/core/modules/system/lib/Drupal/system/Plugin/ImageToolkitInterface.php b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkitInterface.php index 0b22f3c..90bd15f 100644 --- a/core/modules/system/lib/Drupal/system/Plugin/ImageToolkitInterface.php +++ b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkitInterface.php @@ -7,13 +7,16 @@ namespace Drupal\system\Plugin; +use Drupal\Component\Plugin\PluginInspectionInterface; +use Drupal\Core\Image\ImageFile; + /** * 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 +35,7 @@ function settingsFormSubmit($form, &$form_state); /** * Scales an image to the specified size. * - * @param object $image + * @param \Drupal\Core\Image\ImageFile $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 +45,13 @@ function settingsFormSubmit($form, &$form_state); * * @return bool * TRUE or FALSE, based on success. - * - * @see image_resize() */ - function resize($image, $width, $height); + function resize(ImageFile $image, $width, $height); /** * Rotates an image the given number of degrees. * - * @param object $image + * @param \Drupal\Core\Image\ImageFile $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 +65,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(ImageFile $image, $degrees, $background = NULL); /** * Crops an image. * - * @param object $image + * @param \Drupal\Core\Image\ImageFile $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 +88,50 @@ function rotate($image, $degrees, $background = NULL); * * @see image_crop() */ - function crop($image, $x, $y, $width, $height); + function crop(ImageFile $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\ImageFile $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(ImageFile $image); /** * Creates an image resource from a file. * - * @param object $image + * @param \Drupal\Core\Image\ImageFile $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(ImageFile $image); /** * Writes an image resource to a destination file. * - * @param object $image + * @param \Drupal\Core\Image\ImageFile $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(ImageFile $image, $destination); /** * Gets details about an image. * - * @param object $image + * @param \Drupal\Core\Image\ImageFile $image * An image object. * * @return array @@ -151,7 +144,7 @@ function save($image, $destination); * * @see image_get_info() */ - function getInfo($image); + function getInfo(ImageFile $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..fb03c41 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitGdTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitGdTest.php @@ -7,6 +7,7 @@ namespace Drupal\system\Tests\Image; +use Drupal\Core\Image\ImageFile; use Drupal\simpletest\DrupalUnitTestBase; use Drupal\system\Plugin\ImageToolkitManager; @@ -79,15 +80,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(ImageFile $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)); } /** @@ -110,49 +111,49 @@ function testManipulations() { // Setup a list of tests to perform on each type. $operations = array( 'resize' => array( - 'function' => 'resize', + 'method' => 'resize', 'arguments' => array(20, 10), 'width' => 20, 'height' => 10, 'corners' => $default_corners, ), 'scale_x' => array( - 'function' => 'scale', + 'method' => 'scale', 'arguments' => array(20, NULL), 'width' => 20, 'height' => 10, 'corners' => $default_corners, ), 'scale_y' => array( - 'function' => 'scale', + 'method' => 'scale', 'arguments' => array(NULL, 10), 'width' => 20, 'height' => 10, 'corners' => $default_corners, ), 'upscale_x' => array( - 'function' => 'scale', + 'method' => 'scale', 'arguments' => array(80, NULL, TRUE), 'width' => 80, 'height' => 40, 'corners' => $default_corners, ), 'upscale_y' => array( - 'function' => 'scale', + 'method' => 'scale', 'arguments' => array(NULL, 40, TRUE), 'width' => 80, 'height' => 40, 'corners' => $default_corners, ), 'crop' => array( - 'function' => 'crop', + 'method' => 'crop', 'arguments' => array(12, 4, 16, 12), 'width' => 16, 'height' => 12, 'corners' => array_fill(0, 4, $this->white), ), 'scale_and_crop' => array( - 'function' => 'scale_and_crop', + 'method' => 'scaleAndCrop', 'arguments' => array(10, 8), 'width' => 10, 'height' => 8, @@ -164,28 +165,28 @@ function testManipulations() { if (function_exists('imagerotate')) { $operations += array( 'rotate_5' => array( - 'function' => 'rotate', + 'method' => 'rotate', 'arguments' => array(5, 0xFF00FF), // Fuchsia background. 'width' => 42, 'height' => 24, 'corners' => array_fill(0, 4, $this->fuchsia), ), 'rotate_90' => array( - 'function' => 'rotate', + 'method' => 'rotate', 'arguments' => array(90, 0xFF00FF), // Fuchsia background. 'width' => 20, 'height' => 40, 'corners' => array($this->transparent, $this->red, $this->green, $this->blue), ), 'rotate_transparent_5' => array( - 'function' => 'rotate', + 'method' => 'rotate', 'arguments' => array(5), 'width' => 42, 'height' => 24, 'corners' => array_fill(0, 4, $this->transparent), ), 'rotate_transparent_90' => array( - 'function' => 'rotate', + 'method' => 'rotate', 'arguments' => array(90), 'width' => 20, 'height' => 40, @@ -198,7 +199,7 @@ function testManipulations() { if (function_exists('imagefilter')) { $operations += array( 'desaturate' => array( - 'function' => 'desaturate', + 'method' => 'desaturate', 'arguments' => array(), 'height' => 20, 'width' => 40, @@ -219,17 +220,17 @@ function testManipulations() { 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 = new ImageFile(drupal_get_path('module', 'simpletest') . '/files/' . $file, $manager->createInstance('gd')); 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->get('extension') == '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['method']), $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->get('width') != $values['width'] || $image->get('height') != $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->get('extension')); $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->get('extension') != '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 24e10b0..0713e3b 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTest.php @@ -7,6 +7,7 @@ namespace Drupal\system\Tests\Image; +use Drupal\Core\Image\ImageFile; use Drupal\system\Plugin\ImageToolkitManager; /** @@ -37,9 +38,10 @@ function testGetAvailableToolkits() { * Test the image_load() function. */ function testLoad() { - $image = image_load($this->file, $this->toolkit); + $image = new ImageFile($this->file); + $image->setToolkit($this->toolkit)->getResource(); $this->assertTrue(is_object($image), 'Returned an object.'); - $this->assertEqual($this->toolkit, $image->toolkit, t('Image had toolkit set.')); + $this->assertEqual($this->toolkit->getPluginId(), $image->getToolkitId(), t('Image had toolkit set.')); $this->assertToolkitOperationsCalled(array('load', 'get_info')); } @@ -47,7 +49,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 +57,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 +71,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 +84,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 +100,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 +113,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 +128,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..f2f8c39 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTestBase.php +++ b/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTestBase.php @@ -7,6 +7,7 @@ namespace Drupal\system\Tests\Image; +use Drupal\Core\Image\ImageFile; use Drupal\simpletest\WebTestBase; use Drupal\system\Plugin\ImageToolkitManager; use stdClass; @@ -23,8 +24,19 @@ */ public static $modules = array('image_test'); + /** + * @var \Drupal\system\Plugin\ImageToolkitInterface + */ protected $toolkit; + + /** + * @var string + */ protected $file; + + /** + * @var \Drupal\Core\Image\ImageFile + */ protected $image; function setUp() { @@ -40,10 +52,9 @@ function setUp() { // 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; + $this->image = new ImageFile($this->file); + $this->image->setToolkit($this->toolkit); + $this->image->setInfo(image_get_info($this->file)); // Clear out any hook calls. $this->imageTestReset(); 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..8203b18 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\ImageFile; use Drupal\system\Plugin\ImageToolkitInterface; /** @@ -38,7 +39,7 @@ public function settingsFormSubmit($form, &$form_state) {} /** * Implements \Drupal\system\Plugin\ImageToolkitInterface::getInfo(). */ - public function getInfo($image) { + public function getInfo(ImageFile $image) { $this->logCall('get_info', array($image)); return array(); } @@ -46,7 +47,7 @@ public function getInfo($image) { /** * Implements \Drupal\system\Plugin\ImageToolkitInterface::load(). */ - public function load($image) { + public function load(ImageFile $image) { $this->logCall('load', array($image)); return $image; } @@ -54,7 +55,7 @@ public function load($image) { /** * Implements \Drupal\system\Plugin\ImageToolkitInterface::save(). */ - public function save($image, $destination) { + public function save(ImageFile $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. @@ -64,7 +65,7 @@ public function save($image, $destination) { /** * Implements \Drupal\system\Plugin\ImageToolkitInterface::crop(). */ - public function crop($image, $x, $y, $width, $height) { + public function crop(ImageFile $image, $x, $y, $width, $height) { $this->logCall('crop', array($image, $x, $y, $width, $height)); return TRUE; } @@ -72,7 +73,7 @@ public function crop($image, $x, $y, $width, $height) { /** * Implements \Drupal\system\Plugin\ImageToolkitInterface::resize(). */ - public function resize($image, $width, $height) { + public function resize(ImageFile $image, $width, $height) { $this->logCall('resize', array($image, $width, $height)); return TRUE; } @@ -80,7 +81,7 @@ public function resize($image, $width, $height) { /** * Implements \Drupal\system\Plugin\ImageToolkitInterface::rotate(). */ - public function rotate($image, $degrees, $background = NULL) { + public function rotate(ImageFile $image, $degrees, $background = NULL) { $this->logCall('rotate', array($image, $degrees, $background)); return TRUE; } @@ -88,7 +89,7 @@ public function rotate($image, $degrees, $background = NULL) { /** * Implements \Drupal\system\Plugin\ImageToolkitInterface::desaturate(). */ - public function desaturate($image) { + public function desaturate(ImageFile $image) { $this->logCall('desaturate', array($image)); return TRUE; }