<?php
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\Plugin\Core\Entity\ImageStyle;
const IMAGE_STORAGE_NORMAL = 1;
const IMAGE_STORAGE_OVERRIDE = 2;
const IMAGE_STORAGE_DEFAULT = 4;
define('IMAGE_STORAGE_EDITABLE', IMAGE_STORAGE_NORMAL | IMAGE_STORAGE_OVERRIDE);
define('IMAGE_STORAGE_MODULE', IMAGE_STORAGE_OVERRIDE | IMAGE_STORAGE_DEFAULT);
define('IMAGE_DERIVATIVE_TOKEN', 'itok');
require_once __DIR__ . '/image.field.inc';
function image_help($path, $arg) {
switch ($path) {
case 'admin/help#image':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The Image module allows you to manipulate images on your website. It exposes a setting for using the <em>Image toolkit</em>, allows you to configure <em>Image styles</em> that can be used for resizing or adjusting images on display, and provides an <em>Image</em> field for attaching images to content. For more information, see the online handbook entry for <a href="@image">Image module</a>.', array(
'@image' => 'http://drupal.org/documentation/modules/image',
)) . '</p>';
$output .= '<h3>' . t('Uses') . '</h3>';
$output .= '<dl>';
$output .= '<dt>' . t('Manipulating images') . '</dt>';
$output .= '<dd>' . t('With the Image module you can scale, crop, resize, rotate and desaturate images without affecting the original image using <a href="@image">image styles</a>. When you change an image style, the module automatically refreshes all created images. Every image style must have a name, which will be used in the URL of the generated images. There are two common approaches to naming image styles (which you use will depend on how the image style is being applied):', array(
'@image' => url('admin/config/media/image-styles'),
));
$output .= '<ul><li>' . t('Based on where it will be used: eg. <em>profile-picture</em>') . '</li>';
$output .= '<li>' . t('Describing its appearance: eg. <em>square-85x85</em>') . '</li></ul>';
$output .= t('After you create an image style, you can add effects: crop, scale, resize, rotate, and desaturate (other contributed modules provide additional effects). For example, by combining effects as crop, scale, and desaturate, you can create square, grayscale thumbnails.') . '<dd>';
$output .= '<dt>' . t('Attaching images to content as fields') . '</dt>';
$output .= '<dd>' . t("Image module also allows you to attach images to content as fields. To add an image field to a <a href='@content-type'>content type</a>, go to the content type's <em>manage fields</em> page, and add a new field of type <em>Image</em>. Attaching images to content this way allows image styles to be applied and maintained, and also allows you more flexibility when theming.", array(
'@content-type' => url('admin/structure/types'),
)) . '</dd>';
$output .= '</dl>';
return $output;
case 'admin/config/media/image-styles':
return '<p>' . t('Image styles commonly provide thumbnail sizes by scaling and cropping images, but can also add various effects before an image is displayed. When an image is displayed with a style, a new file is created and the original image is left unchanged.') . '</p>';
case 'admin/config/media/image-styles/manage/%/add/%':
$effect = image_effect_definition_load($arg[7]);
return isset($effect['help']) ? '<p>' . $effect['help'] . '</p>' : NULL;
case 'admin/config/media/image-styles/manage/%/effects/%':
$effect = $arg[5] == 'add' ? image_effect_definition_load($arg[6]) : image_effect_load($arg[6], $arg[4]);
return isset($effect['help']) ? '<p>' . $effect['help'] . '</p>' : NULL;
}
}
function image_style_entity_uri(ImageStyle $style) {
return array(
'path' => 'admin/config/media/image-styles/manage/' . $style
->id(),
);
}
function image_menu() {
$items = array();
$directory_path = file_stream_wrapper_get_instance_by_scheme('public')
->getDirectoryPath();
$items[$directory_path . '/styles/%image_style'] = array(
'title' => 'Generate image style',
'page callback' => 'image_style_deliver',
'page arguments' => array(
count(explode('/', $directory_path)) + 1,
),
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
$items['system/files/styles/%image_style'] = array(
'title' => 'Generate image style',
'page callback' => 'image_style_deliver',
'page arguments' => array(
3,
),
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
$items['admin/config/media/image-styles'] = array(
'title' => 'Image styles',
'description' => 'Configure styles that can be used for resizing or adjusting images on display.',
'page callback' => 'image_style_list',
'access arguments' => array(
'administer image styles',
),
'file' => 'image.admin.inc',
);
$items['admin/config/media/image-styles/list'] = array(
'title' => 'List',
'description' => 'List the current image styles on the site.',
'page callback' => 'image_style_list',
'access arguments' => array(
'administer image styles',
),
'type' => MENU_DEFAULT_LOCAL_TASK,
'file' => 'image.admin.inc',
);
$items['admin/config/media/image-styles/add'] = array(
'title' => 'Add style',
'description' => 'Add a new image style.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'image_style_add_form',
),
'access arguments' => array(
'administer image styles',
),
'type' => MENU_LOCAL_ACTION,
'weight' => 2,
'file' => 'image.admin.inc',
);
$items['admin/config/media/image-styles/manage/%image_style'] = array(
'title' => 'Edit style',
'title callback' => 'entity_page_label',
'title arguments' => array(
5,
),
'description' => 'Configure an image style.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'image_style_form',
5,
),
'access arguments' => array(
'administer image styles',
),
'file' => 'image.admin.inc',
);
$items['admin/config/media/image-styles/manage/%image_style/edit'] = array(
'title' => 'Edit',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
$items['admin/config/media/image-styles/manage/%image_style/delete'] = array(
'title' => 'Delete',
'description' => 'Delete an image style.',
'type' => MENU_LOCAL_TASK,
'weight' => 10,
'route_name' => 'image_style_delete',
);
$items['admin/config/media/image-styles/manage/%image_style/effects/%image_effect'] = array(
'title' => 'Edit image effect',
'description' => 'Edit an existing effect within a style.',
'load arguments' => array(
5,
(string) IMAGE_STORAGE_EDITABLE,
),
'page callback' => 'drupal_get_form',
'page arguments' => array(
'image_effect_form',
5,
7,
),
'access arguments' => array(
'administer image styles',
),
'file' => 'image.admin.inc',
);
$items['admin/config/media/image-styles/manage/%image_style/effects/%image_effect/delete'] = array(
'title' => 'Delete image effect',
'description' => 'Delete an existing effect from a style.',
'route_name' => 'image_effect_delete',
);
$items['admin/config/media/image-styles/manage/%image_style/add/%image_effect_definition'] = array(
'title' => 'Add image effect',
'description' => 'Add a new effect to a style.',
'load arguments' => array(
5,
),
'page callback' => 'drupal_get_form',
'page arguments' => array(
'image_effect_form',
5,
7,
),
'access arguments' => array(
'administer image styles',
),
'file' => 'image.admin.inc',
);
return $items;
}
function image_theme() {
return array(
'image_style' => array(
'variables' => array(
'style_name' => NULL,
'uri' => NULL,
'width' => NULL,
'height' => NULL,
'alt' => '',
'title' => NULL,
'attributes' => array(),
),
),
'image_style_list' => array(
'variables' => array(
'styles' => NULL,
),
),
'image_style_effects' => array(
'render element' => 'form',
),
'image_style_preview' => array(
'variables' => array(
'style' => NULL,
),
),
'image_anchor' => array(
'render element' => 'element',
),
'image_resize_summary' => array(
'variables' => array(
'data' => NULL,
),
),
'image_scale_summary' => array(
'variables' => array(
'data' => NULL,
),
),
'image_crop_summary' => array(
'variables' => array(
'data' => NULL,
),
),
'image_rotate_summary' => array(
'variables' => array(
'data' => NULL,
),
),
'image_widget' => array(
'render element' => 'element',
),
'image_formatter' => array(
'variables' => array(
'item' => NULL,
'path' => NULL,
'image_style' => NULL,
),
),
);
}
function image_permission() {
return array(
'administer image styles' => array(
'title' => t('Administer image styles'),
'description' => t('Create and modify styles for generating image modifications such as thumbnails.'),
),
);
}
function image_form_system_file_system_settings_alter(&$form, &$form_state) {
$form['#submit'][] = 'image_system_file_system_settings_submit';
}
function image_system_file_system_settings_submit($form, &$form_state) {
if ($form['file_public_path']['#default_value'] !== $form_state['values']['file_public_path']) {
Drupal::state()
->set('menu_rebuild_needed', TRUE);
}
}
function image_file_download($uri) {
$path = file_uri_target($uri);
if (strpos($path, 'styles/') === 0) {
$args = explode('/', $path);
array_shift($args);
$style_name = array_shift($args);
array_shift($args);
$original_uri = file_uri_scheme($uri) . '://' . implode('/', $args);
if ($info = image_get_info($uri)) {
$headers = module_invoke_all('file_download', $original_uri);
if (!empty($headers) && !in_array(-1, $headers)) {
return array(
'Content-Type' => $info['mime_type'],
'Content-Length' => $info['file_size'],
);
}
}
return -1;
}
$files = entity_load_multiple_by_properties('file', array(
'uri' => $uri,
));
if (count($files)) {
$file = reset($files);
if ($file->status) {
return file_file_download($uri, 'image');
}
}
}
function image_file_move(File $file, File $source) {
image_path_flush($source->uri);
}
function image_file_predelete(File $file) {
image_path_flush($file->uri);
}
function image_field_delete_field($field) {
if ($field['type'] != 'image') {
return;
}
$fid = isset($field['settings']['default_image']['fids']) ? $field['settings']['default_image']['fids'] : $field['settings']['default_image'];
if ($fid && ($file = file_load($fid[0]))) {
file_usage()
->delete($file, 'image', 'default_image', $field['id']);
}
}
function image_field_update_field($field, $prior_field, $has_data) {
if ($field['type'] != 'image') {
return;
}
$fid_new = isset($field['settings']['default_image']['fids']) ? $field['settings']['default_image']['fids'] : $field['settings']['default_image'];
$fid_old = isset($prior_field['settings']['default_image']['fids']) ? $prior_field['settings']['default_image']['fids'] : $prior_field['settings']['default_image'];
$file_new = $fid_new ? file_load($fid_new) : FALSE;
if ($fid_new != $fid_old) {
if ($file_new) {
$file_new->status = FILE_STATUS_PERMANENT;
$file_new
->save();
file_usage()
->add($file_new, 'image', 'default_image', $field['uuid']);
}
if ($fid_old && ($file_old = file_load($fid_old[0]))) {
file_usage()
->delete($file_old, 'image', 'default_image', $field['uuid']);
}
}
if ($file_new && file_uri_scheme($file_new->uri) != $field['settings']['uri_scheme']) {
$directory = $field['settings']['uri_scheme'] . '://default_images/';
file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
file_move($file_new, $directory . $file_new->filename);
}
}
function image_field_delete_instance($instance) {
$field = field_read_field($instance['field_name']);
if ($field['type'] != 'image') {
return;
}
$fid = $instance['settings']['default_image'];
if (is_array($fid)) {
$fid = $fid['fid'];
}
if ($fid && ($file = file_load($fid))) {
file_usage()
->delete($file, 'image', 'default_image', $instance['id']);
}
}
function image_field_update_instance($instance, $prior_instance) {
$field = field_read_field($instance['field_name']);
if ($field['type'] != 'image') {
return;
}
$fid_new = $instance['settings']['default_image'];
if (isset($fid_new['fids'])) {
$fid_new = $fid_new['fids'];
}
$fid_old = $prior_instance['settings']['default_image'];
if (isset($fid_old['fids'])) {
$fid_old = $fid_old['fids'];
}
$file_new = $fid_new ? file_load($fid_new[0]) : FALSE;
if ($fid_new != $fid_old) {
if ($file_new) {
$file_new->status = FILE_STATUS_PERMANENT;
$file_new
->save();
file_usage()
->add($file_new, 'image', 'default_image', $instance['uuid']);
}
if ($fid_old && ($file_old = file_load($fid_old[0]))) {
file_usage()
->delete($file_old, 'image', 'default_image', $instance['uuid']);
}
}
if ($file_new && file_uri_scheme($file_new->uri) != $field['settings']['uri_scheme']) {
$directory = $field['settings']['uri_scheme'] . '://default_images/';
file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
file_move($file_new, $directory . $file_new->filename);
}
}
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);
}
}
}
function image_style_load($name) {
return entity_load('image_style', $name);
}
function image_style_options($include_empty = TRUE) {
$styles = entity_load_multiple('image_style');
$options = array();
if ($include_empty && !empty($styles)) {
$options[''] = t('- None -');
}
foreach ($styles as $name => $style) {
$options[$name] = $style
->label();
}
if (empty($options)) {
$options[''] = t('No defined styles');
}
return $options;
}
function image_style_deliver($style, $scheme) {
$args = func_get_args();
array_shift($args);
array_shift($args);
$target = implode('/', $args);
$valid = !empty($style) && file_stream_wrapper_valid_scheme($scheme);
if (!config('image.settings')
->get('allow_insecure_derivatives')) {
$valid = $valid && isset($_GET[IMAGE_DERIVATIVE_TOKEN]) && $_GET[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 ($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);
}
}
}
}
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);
}
$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) {
throw new ServiceUnavailableHttpException(3, t('Image generation in progress. Try again shortly.'));
}
}
$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);
}
}
function image_style_create_derivative($style, $source, $destination) {
$directory = drupal_dirname($destination);
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;
}
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;
}
}
}
}
function image_style_flush($style) {
$wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_WRITE_VISIBLE);
foreach ($wrappers as $wrapper => $wrapper_data) {
file_unmanaged_delete_recursive($wrapper . '://styles/' . $style
->id());
}
module_invoke_all('image_style_flush', $style);
field_info_cache_clear();
drupal_theme_rebuild();
if (module_exists('block')) {
cache('block')
->deleteAll();
}
cache('page')
->deleteAll();
}
function image_style_url($style_name, $path, $clean_urls = NULL) {
$uri = image_style_path($style_name, $path);
$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) {
$clean_urls = TRUE;
try {
$request = Drupal::request();
$clean_urls = $request->attributes
->get('clean_urls');
} catch (ServiceNotFoundException $e) {
}
}
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);
if ($token_query) {
$file_url .= (strpos($file_url, '?') !== FALSE ? '&' : '?') . drupal_http_build_query($token_query);
}
return $file_url;
}
function image_style_path_token($style_name, $uri) {
return substr(Crypt::hmacBase64($style_name . ':' . $uri, drupal_get_private_key() . drupal_get_hash_salt()), 0, 8);
}
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;
}
function image_effect_definitions() {
$language_interface = language(Language::TYPE_INTERFACE);
$langcode = $language_interface->langcode;
$effects =& drupal_static(__FUNCTION__);
if (!isset($effects)) {
if ($cache = cache()
->get("image_effects:{$langcode}")) {
$effects = $cache->data;
}
else {
$effects = array();
include_once __DIR__ . '/image.effects.inc';
foreach (module_implements('image_effect_info') as $module) {
foreach (module_invoke($module, 'image_effect_info') as $name => $effect) {
$effect['module'] = $module;
$effect['name'] = $name;
$effect['data'] = isset($effect['data']) ? $effect['data'] : array();
$effects[$name] = $effect;
}
}
uasort($effects, '_image_effect_definitions_sort');
drupal_alter('image_effect_info', $effects);
cache()
->set("image_effects:{$langcode}", $effects);
}
}
return $effects;
}
function image_effect_definition_load($effect) {
$definitions = image_effect_definitions();
return isset($definitions[$effect]) ? $definitions[$effect] : FALSE;
}
function image_effect_load($ieid, $style_name) {
if (($style = entity_load('image_style', $style_name)) && isset($style->effects[$ieid])) {
$effect = $style->effects[$ieid];
$definition = image_effect_definition_load($effect['name']);
$effect = array_merge($definition, $effect);
$effect['ieid'] = $ieid;
return $effect;
}
return FALSE;
}
function image_effect_save($style, &$effect) {
$effect = array_intersect_key($effect, array_flip(array(
'ieid',
'module',
'name',
'data',
'weight',
)));
if (empty($effect['ieid'])) {
$uuid = new Uuid();
$effect['ieid'] = $uuid
->generate();
}
$style->effects[$effect['ieid']] = $effect;
$style
->save();
image_style_flush($style);
}
function image_effect_delete($style, $effect) {
unset($style->effects[$effect['ieid']]);
$style
->save();
image_style_flush($style);
}
function image_effect_apply($image, $effect) {
module_load_include('inc', 'image', 'image.effects');
$function = $effect['effect callback'];
return $function($image, $effect['data']);
}
function theme_image_style($variables) {
$dimensions = array(
'width' => $variables['width'],
'height' => $variables['height'],
);
image_style_transform_dimensions($variables['style_name'], $dimensions);
$variables['width'] = $dimensions['width'];
$variables['height'] = $dimensions['height'];
$variables['attributes']['class'][] = 'image-style-' . drupal_html_class($variables['style_name']);
$variables['uri'] = image_style_url($variables['style_name'], $variables['uri']);
return theme('image', $variables);
}
function image_filter_keyword($value, $current_pixels, $new_pixels) {
switch ($value) {
case 'top':
case 'left':
return 0;
case 'bottom':
case 'right':
return $current_pixels - $new_pixels;
case 'center':
return $current_pixels / 2 - $new_pixels / 2;
}
return $value;
}
function _image_effect_definitions_sort($a, $b) {
return strcasecmp($a['name'], $b['name']);
}
function image_entity_presave(EntityInterface $entity, $type) {
$field = FALSE;
if ($entity instanceof FieldInstance) {
$field = $entity
->getField();
}
elseif ($entity instanceof Field) {
$field = $entity;
}
if ($field && $field->type == 'image' && is_array($entity->settings['default_image'])) {
if (!empty($entity->settings['default_image'][0])) {
$entity->settings['default_image'] = $entity->settings['default_image'][0];
}
else {
$entity->settings['default_image'] = 0;
}
}
}