Issue #2027423 by claudiu.cristea, tim.plunkett, andypost: Make image style system flexible.

8.0.x
Alex Pott 2013-07-08 23:37:04 +01:00
parent 176fbe7c71
commit 27f8cd4cd6
18 changed files with 474 additions and 394 deletions

View File

@ -608,7 +608,7 @@ function theme_image_style_effects($variables) {
*
* @param $variables
* An associative array containing:
* - style: The image style array being previewed.
* - style: \Drupal\image\ImageStyleInterface image style being previewed.
*
* @ingroup themeable
*/
@ -634,9 +634,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 = image_style_path($style->id(), $original_path);
$preview_file = $style->buildUri($original_path);
if (!file_exists($preview_file)) {
image_style_create_derivative($style, $original_path, $preview_file);
$style->createDerivative($original_path, $preview_file);
}
$preview_image = image_get_info($preview_file);
if ($preview_image['width'] > $preview_image['height']) {

View File

@ -74,8 +74,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\Plugin\Core\Entity\ImageStyle $style
* The image style array that is being flushed.
* @param \Drupal\image\ImageStyleInterface $style
* The image style object that is being flushed.
*/
function hook_image_style_flush($style) {
// Empty cached data that contains information about the style.

View File

@ -9,13 +9,9 @@ use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Language\Language;
use Drupal\field\Plugin\Core\Entity\Field;
use Drupal\field\Plugin\Core\Entity\FieldInstance;
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\ImageStyleInterface;
use Drupal\image\Plugin\Core\Entity\ImageStyle;
use Drupal\field\FieldInterface;
use Drupal\field\FieldInstanceInterface;
@ -357,10 +353,7 @@ function image_file_predelete(File $file) {
function image_path_flush($path) {
$styles = entity_load_multiple('image_style');
foreach ($styles as $style) {
$image_path = image_style_path($style->id(), $path);
if (file_exists($image_path)) {
file_unmanaged_delete($image_path);
}
$style->flush($path);
}
}
@ -403,304 +396,23 @@ function image_style_options($include_empty = TRUE) {
*
* After generating an image, transfer it to the requesting agent.
*
* @param $style
* The image style
* @param \Drupal\image\ImageStyleInterface $style
* The image style.
* @param string $scheme
* The scheme name of the original image file stream wrapper ('public',
* 'private', 'temporary', etc.).
*
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse|\Symfony\Component\HttpFoundation\Response
* The image to be delivered.
*
* @todo Remove this wrapper in https://drupal.org/node/1987712.
*/
function image_style_deliver($style, $scheme) {
function image_style_deliver(ImageStyleInterface $style, $scheme) {
$args = func_get_args();
array_shift($args);
array_shift($args);
// Remove $style and $scheme from the arguments.
unset($args[0], $args[1]);
$target = implode('/', $args);
// 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 = image_load($derivative_uri);
$uri = $image->source;
$headers = 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);
}
}
/**
* 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->effects,
* 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;
}
if (!$image = image_load($source)) {
return FALSE;
}
if (!empty($style->effects)) {
foreach ($style->effects as $effect) {
image_effect_apply($image, $effect);
}
}
if (!image_save($image, $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) {
module_load_include('inc', 'image', 'image.effects');
$style = entity_load('image_style', $style_name);
if (!empty($style->effects)) {
foreach ($style->effects as $effect) {
if (isset($effect['dimensions passthrough'])) {
continue;
}
if (isset($effect['dimensions callback'])) {
$effect['dimensions callback']($dimensions, $effect['data']);
}
else {
$dimensions['width'] = $dimensions['height'] = NULL;
}
}
}
}
/**
* Flushes cached media for a style.
*
* @param $style
* An image style array.
*/
function image_style_flush($style) {
// Delete the style directory in each registered wrapper.
$wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_WRITE_VISIBLE);
foreach ($wrappers as $wrapper => $wrapper_data) {
file_unmanaged_delete_recursive($wrapper . '://styles/' . $style->id());
}
// Let other modules update as necessary on flush.
module_invoke_all('image_style_flush', $style);
// Clear field caches so that formatters may be added for this style.
field_info_cache_clear();
drupal_theme_rebuild();
// Clear page caches when flushing.
if (module_exists('block')) {
cache('block')->deleteAll();
}
cache('page')->deleteAll();
}
/**
* 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 <img> 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;
return $style->deliver($scheme, $target);
}
/**
@ -835,10 +547,6 @@ function image_effect_save($style, &$effect) {
}
$style->effects[$effect['ieid']] = $effect;
$style->save();
// Flush all derivatives that exist for this style, so they are regenerated
// with the new or updated effect.
image_style_flush($style);
}
/**
@ -852,7 +560,6 @@ function image_effect_save($style, &$effect) {
function image_effect_delete($style, $effect) {
unset($style->effects[$effect['ieid']]);
$style->save();
image_style_flush($style);
}
/**
@ -892,13 +599,17 @@ function image_effect_apply($image, $effect) {
* @ingroup themeable
*/
function theme_image_style($variables) {
// @todo Image style loading will be moved outside theme in
// https://drupal.org/node/2029649
$style = entity_load('image_style', $variables['style_name']);
// Determine the dimensions of the styled image.
$dimensions = array(
'width' => $variables['width'],
'height' => $variables['height'],
);
image_style_transform_dimensions($variables['style_name'], $dimensions);
$style->transformDimensions($dimensions);
// Add in the image style name as an HTML class.
$variables['attributes']['class'][] = 'image-style-' . drupal_html_class($variables['style_name']);
@ -908,7 +619,7 @@ function theme_image_style($variables) {
'#width' => $dimensions['width'],
'#height' => $dimensions['height'],
'#attributes' => $variables['attributes'],
'#uri' => image_style_url($variables['style_name'], $variables['uri']),
'#uri' => $style->buildUrl($variables['uri']),
);
if (isset($variables['alt'])) {

View File

@ -2,7 +2,7 @@
/**
* @file
* Contains \Drupal\image\Plugin\Core\Entity\ImageStyleInterface.
* Contains \Drupal\image\ImageStyleInterface.
*/
namespace Drupal\image;
@ -14,4 +14,99 @@ use Drupal\Core\Config\Entity\ConfigEntityInterface;
*/
interface ImageStyleInterface extends ConfigEntityInterface {
/**
* Delivers 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 <img> 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.
*/
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);
}

View File

@ -12,6 +12,13 @@ use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation;
use Drupal\Core\Entity\EntityStorageControllerInterface;
use Drupal\image\ImageStyleInterface;
use Drupal\Component\Utility\Crypt;
use Drupal\Component\Utility\Url;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
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.
@ -68,7 +75,7 @@ class ImageStyle extends ConfigEntityBase implements ImageStyleInterface {
/**
* The array of image effects for this image style.
*
* @var string
* @var array
*/
public $effects;
@ -83,11 +90,17 @@ class ImageStyle extends ConfigEntityBase implements ImageStyleInterface {
* {@inheritdoc}
*/
public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) {
if ($update && !empty($this->original) && $this->id() !== $this->original->id()) {
// The old image style name needs flushing after a rename.
image_style_flush($this->original);
// Update field instance settings if necessary.
static::replaceImageStyle($this);
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();
}
}
}
@ -97,7 +110,7 @@ class ImageStyle extends ConfigEntityBase implements ImageStyleInterface {
public static function postDelete(EntityStorageControllerInterface $storage_controller, array $entities) {
foreach ($entities as $style) {
// Flush cached media for the deleted style.
image_style_flush($style);
$style->flush();
// Check whether field instance settings need to be updated.
// In case no replacement style was specified, all image fields that are
// using the deleted style are left in a broken state.
@ -112,10 +125,10 @@ class ImageStyle extends ConfigEntityBase implements ImageStyleInterface {
/**
* Update field instance settings if the image style name is changed.
*
* @param \Drupal\image\Plugin\Core\Entity\ImageStyle $style
* @param \Drupal\image\ImageStyleInterface $style
* The image style.
*/
protected static function replaceImageStyle(ImageStyle $style) {
protected static function replaceImageStyle(ImageStyleInterface $style) {
if ($style->id() != $style->getOriginalID()) {
$instances = field_read_instances();
// Loop through all fields searching for image fields.
@ -148,4 +161,252 @@ class ImageStyle extends ConfigEntityBase implements ImageStyleInterface {
}
}
/**
* {@inheritdoc}
*/
public function deliver($scheme, $target) {
$original_uri = $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 &= isset($image_derivative_token) && $image_derivative_token === $this->getPathToken($original_uri);
}
if (!$valid) {
throw new AccessDeniedHttpException();
}
$derivative_uri = $this->buildUri($original_uri);
$headers = 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();
}
}
}
// 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 += 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);
}
}
/**
* {@inheritdoc}
*/
public function buildUri($uri) {
$scheme = file_uri_scheme($uri);
if ($scheme) {
$path = file_uri_target($uri);
}
else {
$path = $uri;
$scheme = file_default_scheme();
}
return $scheme . '://styles/' . $this->id() . '/' . $scheme . '/' . $path;
}
/**
* {@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;
}
/**
* {@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;
}
// Delete the style directory in each registered wrapper.
$wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_WRITE_VISIBLE);
foreach ($wrappers as $wrapper => $wrapper_data) {
file_unmanaged_delete_recursive($wrapper . '://styles/' . $this->id());
}
// Let other modules update as necessary on flush.
\Drupal::moduleHandler()->invokeAll('image_style_flush', array($this));
// Clear field caches so that formatters may be added for this style.
field_info_cache_clear();
drupal_theme_rebuild();
// Clear page caches when flushing.
if (\Drupal::moduleHandler()->moduleExists('block')) {
cache('block')->deleteAll();
}
cache('page')->deleteAll();
}
/**
* {@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;
}
if (!empty($this->effects)) {
foreach ($this->effects as $effect) {
image_effect_apply($image, $effect);
}
}
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) {
module_load_include('inc', 'image', 'image.effects');
if (!empty($this->effects)) {
foreach ($this->effects as $effect) {
if (isset($effect['dimensions passthrough'])) {
continue;
}
if (isset($effect['dimensions callback'])) {
$effect['dimensions callback']($dimensions, $effect['data']);
}
else {
$dimensions['width'] = $dimensions['height'] = NULL;
}
}
}
}
/**
* 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);
}
}

View File

@ -39,8 +39,9 @@ class FileMoveTest extends ToolkitTestBase {
// Create derivative image.
$styles = entity_load_multiple('image_style');
$style = image_style_load(key($styles));
$derivative_uri = image_style_path($style->id(), $file->getFileUri());
image_style_create_derivative($style, $file->getFileUri(), $derivative_uri);
$original_uri = $file->getFileUri();
$derivative_uri = $style->buildUri($original_uri);
$style->createDerivative($original_uri, $derivative_uri);
// Check if derivative image exists.
$this->assertTrue(file_exists($derivative_uri), 'Make sure derivative image is generated successfully.');

View File

@ -7,7 +7,7 @@
namespace Drupal\image\Tests;
use Drupal\Core\Language\Language;
use Drupal\image\ImageStyleInterface;
/**
* Tests creation, deletion, and editing of image styles and effects.
@ -25,7 +25,7 @@ class ImageAdminStylesTest extends ImageFieldTestBase {
/**
* Given an image style, generate an image.
*/
function createSampleImage($style) {
function createSampleImage(ImageStyleInterface $style) {
static $file_path;
// First, we need to make sure we have an image in our testing
@ -36,13 +36,13 @@ class ImageAdminStylesTest extends ImageFieldTestBase {
$file_path = file_unmanaged_copy($file->uri);
}
return image_style_url($style->id(), $file_path) ? $file_path : FALSE;
return $style->buildUrl($file_path) ? $file_path : FALSE;
}
/**
* Count the number of images currently create for a style.
*/
function getImageCount($style) {
function getImageCount(ImageStyleInterface $style) {
return count(file_scan_directory('public://styles/' . $style->id(), '/.*/'));
}
@ -271,9 +271,13 @@ class ImageAdminStylesTest extends ImageFieldTestBase {
$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(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)));
$this->assertRaw($style->buildUrl($original_uri), 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));
@ -285,7 +289,10 @@ class ImageAdminStylesTest extends ImageFieldTestBase {
$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);
$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.');
// 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.');
// Delete the style and choose a replacement style.
$edit = array(
@ -295,8 +302,9 @@ class ImageAdminStylesTest extends ImageFieldTestBase {
$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(image_style_url('thumbnail', file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id'])->getFileUri()), 'Image displayed using style replacement style.');
$this->assertRaw($replacement_style->buildUrl($original_uri), 'Image displayed using style replacement style.');
}
/**
@ -360,9 +368,13 @@ class ImageAdminStylesTest extends ImageFieldTestBase {
$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(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)));
$this->assertRaw($style->buildUrl($original_uri), 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');
@ -374,4 +386,5 @@ class ImageAdminStylesTest extends ImageFieldTestBase {
$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.');
}
}

View File

@ -44,7 +44,7 @@ class ImageDimensionsTest extends WebTestBase {
$style = entity_create('image_style', array('name' => 'test', 'label' => 'Test'));
$style->save();
$generated_uri = 'public://styles/test/public/'. drupal_basename($original_uri);
$url = image_style_url('test', $original_uri);
$url = $style->buildUrl($original_uri);
$variables = array(
'style_name' => 'test',

View File

@ -112,7 +112,7 @@ class ImageFieldDisplayTest extends ImageFieldTestBase {
// Ensure the derivative image is generated so we do not have to deal with
// image style callback paths.
$this->drupalGet(image_style_url('thumbnail', $image_uri));
$this->drupalGet(entity_load('image_style', 'thumbnail')->buildUrl($image_uri));
$image_info['uri'] = $image_uri;
$image_info['width'] = 100;
$image_info['height'] = 50;
@ -124,7 +124,7 @@ class ImageFieldDisplayTest extends ImageFieldTestBase {
if ($scheme == 'private') {
// Log out and try to access the file.
$this->drupalLogout();
$this->drupalGet(image_style_url('thumbnail', $image_uri));
$this->drupalGet(entity_load('image_style', 'thumbnail')->buildUrl($image_uri));
$this->assertResponse('403', 'Access denied to image style thumbnail as anonymous user.');
}
}

View File

@ -15,11 +15,11 @@ use Drupal\simpletest\WebTestBase;
*
* image.effects.inc:
* image_style_generate()
* image_style_create_derivative()
* \Drupal\image\ImageStyleInterface::createDerivative()
*
* image.module:
* image_style_options()
* image_style_flush()
* \Drupal\image\ImageStyleInterface::flush()
* image_effect_definition_load()
* image_effect_load()
* image_effect_save()

View File

@ -34,8 +34,8 @@ class ImageStyleFlushTest extends ImageFieldTestBase {
// 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 = image_style_path($style->id(), $source_uri);
$derivative = image_style_create_derivative($style, $source_uri, $derivative_uri);
$derivative_uri = $style->buildUri($source_uri);
$derivative = $style->createDerivative($source_uri, $derivative_uri);
return $derivative ? $derivative_uri : FALSE;
}

View File

@ -22,9 +22,10 @@ class ImageStylesPathAndUrlTest extends WebTestBase {
*/
public static $modules = array('image', 'image_module_test');
protected $style_name;
protected $image_info;
protected $image_filepath;
/**
* @var \Drupal\image\ImageStyleInterface
*/
protected $style;
public static function getInfo() {
return array(
@ -37,58 +38,57 @@ class ImageStylesPathAndUrlTest extends WebTestBase {
function setUp() {
parent::setUp();
$this->style_name = 'style_foo';
$style = entity_create('image_style', array('name' => $this->style_name, 'label' => $this->randomString()));
$style->save();
$this->style = entity_create('image_style', array('name' => 'style_foo', 'label' => $this->randomString()));
$this->style->save();
}
/**
* Test image_style_path().
* Tests \Drupal\image\ImageStyleInterface::buildUri().
*/
function testImageStylePath() {
$scheme = 'public';
$actual = image_style_path($this->style_name, "$scheme://foo/bar.gif");
$expected = "$scheme://styles/" . $this->style_name . "/$scheme/foo/bar.gif";
$actual = $this->style->buildUri("$scheme://foo/bar.gif");
$expected = "$scheme://styles/" . $this->style->id() . "/$scheme/foo/bar.gif";
$this->assertEqual($actual, $expected, 'Got the path for a file URI.');
$actual = image_style_path($this->style_name, 'foo/bar.gif');
$expected = "$scheme://styles/" . $this->style_name . "/$scheme/foo/bar.gif";
$actual = $this->style->buildUri('foo/bar.gif');
$expected = "$scheme://styles/" . $this->style->id() . "/$scheme/foo/bar.gif";
$this->assertEqual($actual, $expected, 'Got the path for a relative file path.');
}
/**
* Test image_style_url() with a file using the "public://" scheme.
* Tests an image style URL using the "public://" scheme.
*/
function testImageStyleUrlAndPathPublic() {
$this->_testImageStyleUrlAndPath('public');
$this->doImageStyleUrlAndPathTests('public');
}
/**
* Test image_style_url() with a file using the "private://" scheme.
* Tests an image style URL using the "private://" scheme.
*/
function testImageStyleUrlAndPathPrivate() {
$this->_testImageStyleUrlAndPath('private');
$this->doImageStyleUrlAndPathTests('private');
}
/**
* Test image_style_url() with the "public://" scheme and unclean URLs.
* Tests an image style URL with the "public://" scheme and unclean URLs.
*/
function testImageStylUrlAndPathPublicUnclean() {
$this->_testImageStyleUrlAndPath('public', FALSE);
function testImageStyleUrlAndPathPublicUnclean() {
$this->doImageStyleUrlAndPathTests('public', FALSE);
}
/**
* Test image_style_url() with the "private://" schema and unclean URLs.
* Tests an image style URL with the "private://" schema and unclean URLs.
*/
function testImageStyleUrlAndPathPrivateUnclean() {
$this->_testImageStyleUrlAndPath('private', FALSE);
$this->doImageStyleUrlAndPathTests('private', FALSE);
}
/**
* Tests image_style_url() with a file URL that has an extra slash in it.
* Tests an image style URL with a file URL that has an extra slash in it.
*/
function testImageStyleUrlExtraSlash() {
$this->_testImageStyleUrlAndPath('public', TRUE, TRUE);
$this->doImageStyleUrlAndPathTests('public', TRUE, TRUE);
}
/**
@ -96,30 +96,29 @@ class ImageStylesPathAndUrlTest extends WebTestBase {
*/
function testImageStyleUrlForMissingSourceImage() {
$non_existent_uri = 'public://foo.png';
$generated_url = image_style_url($this->style_name, $non_existent_uri);
$generated_url = $this->style->buildUrl($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 image_style_url().
* Tests building an image style URL.
*/
function _testImageStyleUrlAndPath($scheme, $clean_url = TRUE, $extra_slash = FALSE) {
$request = $this->prepareRequestForGenerator($clean_url);
function doImageStyleUrlAndPathTests($scheme, $clean_url = TRUE, $extra_slash = FALSE) {
$this->prepareRequestForGenerator($clean_url);
// Make the default scheme neither "public" nor "private" to verify the
// functions work for other than the default scheme.
config('system.file')->set('default_scheme', 'temporary')->save();
// Create the directories for the styles.
$directory = $scheme . '://styles/' . $this->style_name;
$directory = $scheme . '://styles/' . $this->style->id();
$status = file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
$this->assertNotIdentical(FALSE, $status, 'Created the directory for the generated images for the test style.');
// Create a working copy of the file.
$files = $this->drupalGetTestFiles('image');
$file = array_shift($files);
$image_info = image_get_info($file->uri);
$original_uri = file_unmanaged_copy($file->uri, $scheme . '://', FILE_EXISTS_RENAME);
// Let the image_module_test module know about this file, so it can claim
// ownership in hook_file_download().
@ -127,9 +126,9 @@ class ImageStylesPathAndUrlTest extends WebTestBase {
$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 = image_style_path($this->style_name, $original_uri);
$generated_uri = $this->style->buildUri($original_uri);
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
$generate_url = image_style_url($this->style_name, $original_uri, $clean_url);
$generate_url = $this->style->buildUrl($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
@ -137,7 +136,7 @@ class ImageStylesPathAndUrlTest extends WebTestBase {
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 = image_style_url($this->style_name, $modified_uri, $clean_url);
$generate_url = $this->style->buildUrl($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.');
@ -162,8 +161,8 @@ class ImageStylesPathAndUrlTest extends WebTestBase {
$this->assertNotEqual(strpos($this->drupalGetHeader('Cache-Control'), 'no-cache'), FALSE, 'Cache-Control header contains \'no-cache\' to prevent caching.');
$this->assertEqual($this->drupalGetHeader('X-Image-Owned-By'), 'image_module_test', 'Expected custom header has been added.');
// Make sure that a second request to the already existing derivate works
// too.
// Make sure that a second request to the already existing derivative
// works too.
$this->drupalGet($generate_url);
$this->assertResponse(200, 'Image was generated at the URL.');
@ -177,9 +176,9 @@ class ImageStylesPathAndUrlTest extends WebTestBase {
// 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_name . '/' . $scheme . '/'. drupal_basename($original_uri_noaccess);
$generated_uri_noaccess = $scheme . '://styles/' . $this->style->id() . '/' . $scheme . '/'. drupal_basename($original_uri_noaccess);
$this->assertFalse(file_exists($generated_uri_noaccess), 'Generated file does not exist.');
$generate_url_noaccess = image_style_url($this->style_name, $original_uri_noaccess);
$generate_url_noaccess = $this->style->buildUrl($original_uri_noaccess);
$this->drupalGet($generate_url_noaccess);
$this->assertResponse(403, 'Confirmed that access is denied for the private image style.');
@ -206,7 +205,6 @@ class ImageStylesPathAndUrlTest extends WebTestBase {
// Create another working copy of the file.
$files = $this->drupalGetTestFiles('image');
$file = array_shift($files);
$image_info = image_get_info($file->uri);
$original_uri = file_unmanaged_copy($file->uri, $scheme . '://', FILE_EXISTS_RENAME);
// Let the image_module_test module know about this file, so it can claim
// ownership in hook_file_download().
@ -216,12 +214,12 @@ class ImageStylesPathAndUrlTest extends WebTestBase {
// 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 = image_style_path($this->style_name, $original_uri);
$generated_uri = $this->style->buildUri($original_uri);
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
$generate_url = image_style_url($this->style_name, $original_uri, $clean_url);
$generate_url = $this->style->buildUrl($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.');
}
}

View File

@ -41,7 +41,7 @@ class ImageThemeFunctionTest extends WebTestBase {
// Create a style.
$style = entity_create('image_style', array('name' => 'test', 'label' => 'Test'));
$style->save();
$url = image_style_url('test', $original_uri);
$url = $style->buildUrl($original_uri);
// Test using theme_image_formatter() without an image title, alt text, or
// link options.
@ -84,7 +84,7 @@ class ImageThemeFunctionTest extends WebTestBase {
// Create a style.
$style = entity_create('image_style', array('name' => 'image_test', 'label' => 'Test'));
$style->save();
$url = image_style_url('image_test', $original_uri);
$url = $style->buildUrl($original_uri);
$path = $this->randomName();
$element = array(

View File

@ -182,7 +182,8 @@ class PictureFieldDisplayTest extends ImageFieldTestBase {
$display->setComponent($field_name, $display_options)
->save();
$this->drupalGet(image_style_url('large', $image_uri));
$large_style = entity_load('image_style', 'large');
$this->drupalGet($large_style->buildUrl($image_uri));
$image_info['uri'] = $image_uri;
$image_info['width'] = 480;
$image_info['height'] = 240;
@ -194,7 +195,7 @@ class PictureFieldDisplayTest extends ImageFieldTestBase {
if ($scheme == 'private') {
// Log out and try to access the file.
$this->drupalLogout();
$this->drupalGet(image_style_url('large', $image_uri));
$this->drupalGet($large_style->buildUrl($image_uri));
$this->assertResponse('403', 'Access denied to image style thumbnail as anonymous user.');
}
}

View File

@ -225,7 +225,7 @@ function theme_picture($variables) {
// Fallback image, output as source with media query.
$sources[] = array(
'src' => image_style_url($variables['style_name'], $variables['uri']),
'src' => entity_load('image_style', $variables['style_name'])->buildUrl($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' => image_style_url($new_sources[0]['style_name'], $new_sources[0]['uri']),
'src' => entity_load('image_style', $new_sources[0]['style_name'])->buildUrl($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[] = image_style_url($new_source['style_name'], $new_source['uri']) . ' ' . $new_source['#multiplier'];
$srcset[] = entity_load('image_style', $new_source['style_name'])->buildUrl($new_source['uri']) . ' ' . $new_source['#multiplier'];
}
$sources[] = array(
'srcset' => implode(', ', $srcset),
@ -338,7 +338,7 @@ function picture_get_image_dimensions($variables) {
'height' => $variables['height'],
);
image_style_transform_dimensions($variables['style_name'], $dimensions);
entity_load('image_style', $variables['style_name'])->transformDimensions($dimensions);
return $dimensions;
}

View File

@ -101,7 +101,7 @@ class ImageFieldAttributesTest extends ImageFieldTestBase {
// Construct the node and image URIs for testing.
$node_uri = url('node/' . $this->node->id(), array('absolute' => TRUE));
$image_uri = image_style_url('medium', $this->file->getFileUri());
$image_uri = entity_load('image_style', 'medium')->buildUrl($this->file->getFileUri());
// Test relations from node to image.
$expected_value = array(

View File

@ -85,7 +85,7 @@ class StandardProfileTest extends WebTestBase {
// Set URIs.
// Image.
$image_file = file_load($this->article->get('field_image')->offsetGet(0)->get('target_id')->getValue());
$this->imageUri = image_style_url('large', $image_file->getFileUri());
$this->imageUri = entity_load('image_style', 'large')->buildUrl($image_file->getFileUri());
// Term.
$term_uri_info = $this->term->uri();
$this->termUri = url($term_uri_info['path'], array('absolute' => TRUE));
@ -164,7 +164,7 @@ class StandardProfileTest extends WebTestBase {
// @todo Once the image points to the original instead of the processed
// image, move this to testArticleProperties().
$image_file = file_load($this->article->get('field_image')->offsetGet(0)->get('target_id')->getValue());
$image_uri = image_style_url('medium', $image_file->getFileUri());
$image_uri = entity_load('image_style', 'medium')->buildUrl($image_file->getFileUri());
$expected_value = array(
'type' => 'uri',
'value' => $image_uri,

View File

@ -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'] = image_style_url($element[$delta]['#image_style'], $item['entity']->getFileUri());
$variables['item_attributes'][$delta]['resource'] = entity_load('image_style', $element[$delta]['#image_style'])->buildUrl($item['entity']->getFileUri());
}
else {
$variables['item_attributes'][$delta]['resource'] = file_create_url($item['entity']->getFileUri());