diff --git a/core/includes/image.inc b/core/includes/image.inc
index f0b91bf..34155fc 100644
--- a/core/includes/image.inc
+++ b/core/includes/image.inc
@@ -5,6 +5,8 @@
* API for manipulating images.
*/
+use Drupal\system\Plugin\ImageToolkitManager;
+
/**
* @defgroup image Image toolkits
* @{
@@ -39,15 +41,16 @@
* @return
* An array with the toolkit names as keys and the descriptions as values.
*/
-function image_get_available_toolkits() {
- // hook_image_toolkits returns an array of toolkit names.
- $toolkits = module_invoke_all('image_toolkits');
+function image_get_available_toolkits($key = NULL) {
+ // Use plugin system to get list of available toolkits.
+ $manager = new ImageToolkitManager();
+ $toolkits = $manager->getDefinitions();
$output = array();
- foreach ($toolkits as $name => $info) {
+ foreach ($toolkits as $id => $definition) {
// Only allow modules that aren't marked as unavailable.
- if ($info['available']) {
- $output[$name] = $info['title'];
+ if (call_user_func($definition['class'] . '::checkAvailable')) {
+ $output[$id] = $definition;
}
}
@@ -58,46 +61,32 @@ function image_get_available_toolkits() {
* Gets the name of the currently used toolkit.
*
* @return
- * String containing the name of the selected toolkit, or FALSE on error.
+ * Object of the default toolkit, or FALSE on error.
*/
-function image_get_toolkit() {
- static $toolkit;
+function image_get_toolkit($toolkit_id = NULL) {
+ static $toolkit = array();
+
+ if (empty($toolkit_id)) {
+ $toolkit_id = config('system.image')->get('toolkit');
+ }
- if (!isset($toolkit)) {
+ if (!isset($toolkit[$toolkit_id])) {
$toolkits = image_get_available_toolkits();
- $toolkit = variable_get('image_toolkit', 'gd');
- if (!isset($toolkits[$toolkit]) || !function_exists('image_' . $toolkit . '_load')) {
+
+ if (!isset($toolkits[$toolkit_id]) || !class_exists($toolkits[$toolkit_id]['class'])) {
// The selected toolkit isn't available so return the first one found. If
// none are available this will return FALSE.
reset($toolkits);
- $toolkit = key($toolkits);
+ $toolkit_id = key($toolkits);
}
- }
- return $toolkit;
-}
-
-/**
- * Invokes the given method using the currently selected toolkit.
- *
- * @param $method
- * A string containing the method to invoke.
- * @param $image
- * An image object returned by image_load().
- * @param $params
- * An optional array of parameters to pass to the toolkit method.
- *
- * @return
- * Mixed values (typically Boolean indicating successful operation).
- */
-function image_toolkit_invoke($method, stdClass $image, array $params = array()) {
- $function = 'image_' . $image->toolkit . '_' . $method;
- if (function_exists($function)) {
- array_unshift($params, $image);
- return call_user_func_array($function, $params);
+ if ($toolkit_id) {
+ $manager = new ImageToolkitManager();
+ $toolkit[$toolkit_id] = $manager->createInstance($toolkit_id);
+ }
}
- watchdog('image', 'The selected image handling toolkit %toolkit can not correctly process %function.', array('%toolkit' => $image->toolkit, '%function' => $function), WATCHDOG_ERROR);
- return FALSE;
+
+ return $toolkit[$toolkit_id];
}
/**
@@ -110,7 +99,7 @@ function image_toolkit_invoke($method, stdClass $image, array $params = array())
* @param $filepath
* String specifying the path of the image file.
* @param $toolkit
- * An optional image toolkit name to override the default.
+ * An optional image toolkit object to override the default.
*
* @return
* FALSE, if the file could not be found or is not an image. Otherwise, a
@@ -134,7 +123,7 @@ function image_get_info($filepath, $toolkit = FALSE) {
$image = new stdClass();
$image->source = $filepath;
$image->toolkit = $toolkit;
- $details = image_toolkit_invoke('get_info', $image);
+ $details = $toolkit->getInfo($image);
if (isset($details) && is_array($details)) {
$details['file_size'] = filesize($filepath);
}
@@ -280,7 +269,7 @@ function image_resize(stdClass $image, $width, $height) {
$width = (int) round($width);
$height = (int) round($height);
- return image_toolkit_invoke('resize', $image, array($width, $height));
+ return $image->toolkit->resize($image, $width, $height);
}
/**
@@ -304,7 +293,7 @@ function image_resize(stdClass $image, $width, $height) {
* @see image_gd_rotate()
*/
function image_rotate(stdClass $image, $degrees, $background = NULL) {
- return image_toolkit_invoke('rotate', $image, array($degrees, $background));
+ return $image->toolkit->rotate($image, $degrees, $background);
}
/**
@@ -336,7 +325,7 @@ function image_crop(stdClass $image, $x, $y, $width, $height) {
$width = (int) round($width);
$height = (int) round($height);
- return image_toolkit_invoke('crop', $image, array($x, $y, $width, $height));
+ return $image->toolkit->crop($image, $x, $y, $width, $height);
}
/**
@@ -352,7 +341,7 @@ function image_crop(stdClass $image, $x, $y, $width, $height) {
* @see image_gd_desaturate()
*/
function image_desaturate(stdClass $image) {
- return image_toolkit_invoke('desaturate', $image);
+ return $image->toolkit->desaturate($image);
}
/**
@@ -363,7 +352,7 @@ function image_desaturate(stdClass $image) {
* @param $file
* Path to an image file.
* @param $toolkit
- * An optional, image toolkit name to override the default.
+ * An optional, image toolkit object to override the default.
*
* @return
* An image object or FALSE if there was a problem loading the file. The
@@ -390,7 +379,7 @@ function image_load($file, $toolkit = FALSE) {
$image->info = image_get_info($file, $toolkit);
if (isset($image->info) && is_array($image->info)) {
$image->toolkit = $toolkit;
- if (image_toolkit_invoke('load', $image)) {
+ if ($toolkit->load($image)) {
return $image;
}
}
@@ -418,7 +407,7 @@ function image_save(stdClass $image, $destination = NULL) {
if (empty($destination)) {
$destination = $image->source;
}
- if ($return = image_toolkit_invoke('save', $image, array($destination))) {
+ 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);
diff --git a/core/modules/image/image.effects.inc b/core/modules/image/image.effects.inc
index 35a6a74..4f7379b 100644
--- a/core/modules/image/image.effects.inc
+++ b/core/modules/image/image.effects.inc
@@ -79,7 +79,7 @@ function image_image_effect_info() {
*/
function image_resize_effect(&$image, $data) {
if (!image_resize($image, $data['width'], $data['height'])) {
- watchdog('image', 'Image resize failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->toolkit, '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR);
+ watchdog('image', 'Image resize failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => get_class($image->toolkit), '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR);
return FALSE;
}
return TRUE;
@@ -130,7 +130,7 @@ function image_scale_effect(&$image, $data) {
);
if (!image_scale($image, $data['width'], $data['height'], $data['upscale'])) {
- watchdog('image', 'Image scale failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->toolkit, '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR);
+ watchdog('image', 'Image scale failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => get_class($image->toolkit), '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR);
return FALSE;
}
return TRUE;
@@ -184,7 +184,7 @@ function image_crop_effect(&$image, $data) {
$x = image_filter_keyword($x, $image->info['width'], $data['width']);
$y = image_filter_keyword($y, $image->info['height'], $data['height']);
if (!image_crop($image, $x, $y, $data['width'], $data['height'])) {
- watchdog('image', 'Image crop failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->toolkit, '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR);
+ watchdog('image', 'Image crop failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => get_class($image->toolkit), '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR);
return FALSE;
}
return TRUE;
@@ -206,7 +206,7 @@ function image_crop_effect(&$image, $data) {
*/
function image_scale_and_crop_effect(&$image, $data) {
if (!image_scale_and_crop($image, $data['width'], $data['height'])) {
- watchdog('image', 'Image scale and crop failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->toolkit, '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR);
+ watchdog('image', 'Image scale and crop failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => get_class($image->toolkit), '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR);
return FALSE;
}
return TRUE;
@@ -225,7 +225,7 @@ function image_scale_and_crop_effect(&$image, $data) {
*/
function image_desaturate_effect(&$image, $data) {
if (!image_desaturate($image)) {
- watchdog('image', 'Image desaturate failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->toolkit, '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR);
+ watchdog('image', 'Image desaturate failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => get_class($image->toolkit), '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR);
return FALSE;
}
return TRUE;
@@ -278,7 +278,7 @@ function image_rotate_effect(&$image, $data) {
}
if (!image_rotate($image, $data['degrees'], $data['bgcolor'])) {
- watchdog('image', 'Image rotate failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->toolkit, '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR);
+ watchdog('image', 'Image rotate failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => get_class($image->toolkit), '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR);
return FALSE;
}
return TRUE;
diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageEffectsTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageEffectsTest.php
index fb3269c..b7a5b67 100644
--- a/core/modules/image/lib/Drupal/image/Tests/ImageEffectsTest.php
+++ b/core/modules/image/lib/Drupal/image/Tests/ImageEffectsTest.php
@@ -20,7 +20,7 @@ class ImageEffectsTest extends ToolkitTestBase {
*
* @var array
*/
- public static $modules = array('image_test');
+ public static $modules = array('image_test', 'image');
public static function getInfo() {
return array(
diff --git a/core/modules/system/config/system.image.gd.yml b/core/modules/system/config/system.image.gd.yml
new file mode 100644
index 0000000..fbc379f
--- /dev/null
+++ b/core/modules/system/config/system.image.gd.yml
@@ -0,0 +1 @@
+jpeg_quality: '75'
diff --git a/core/modules/system/config/system.image.yml b/core/modules/system/config/system.image.yml
new file mode 100644
index 0000000..9a1688f
--- /dev/null
+++ b/core/modules/system/config/system.image.yml
@@ -0,0 +1 @@
+toolkit: gd
diff --git a/core/modules/system/image.gd.inc b/core/modules/system/image.gd.inc
deleted file mode 100644
index f6f12ae..0000000
--- a/core/modules/system/image.gd.inc
+++ /dev/null
@@ -1,367 +0,0 @@
- t('The GD toolkit is installed and working properly.')
- );
-
- $form['image_jpeg_quality'] = array(
- '#type' => 'number',
- '#title' => t('JPEG quality'),
- '#description' => t('Define the image quality for JPEG manipulations. Ranges from 0 to 100. Higher values mean better image quality but bigger files.'),
- '#min' => 0,
- '#max' => 100,
- '#default_value' => variable_get('image_jpeg_quality', 75),
- '#field_suffix' => t('%'),
- );
-
- return $form;
- }
- else {
- form_set_error('image_toolkit', t('The GD image toolkit requires that the GD module for PHP be installed and configured properly. For more information see PHP\'s image documentation.', array('@url' => 'http://php.net/image')));
- return FALSE;
- }
-}
-
-/**
- * Verify GD2 settings (that the right version is actually installed).
- *
- * @return
- * A boolean indicating if the GD toolkit is available on this machine.
- */
-function image_gd_check_settings() {
- if ($check = get_extension_funcs('gd')) {
- if (in_array('imagegd2', $check)) {
- // GD2 support is available.
- return TRUE;
- }
- }
- return FALSE;
-}
-
-/**
- * Scale an image to the specified size using GD.
- *
- * @param $image
- * An image object. The $image->resource, $image->info['width'], and
- * $image->info['height'] values will be modified by this call.
- * @param $width
- * The new width of the resized image, in pixels.
- * @param $height
- * The new height of the resized image, in pixels.
- * @return
- * TRUE or FALSE, based on success.
- *
- * @see image_resize()
- */
-function image_gd_resize(stdClass $image, $width, $height) {
- $res = image_gd_create_tmp($image, $width, $height);
-
- if (!imagecopyresampled($res, $image->resource, 0, 0, 0, 0, $width, $height, $image->info['width'], $image->info['height'])) {
- return FALSE;
- }
-
- imagedestroy($image->resource);
- // Update image object.
- $image->resource = $res;
- $image->info['width'] = $width;
- $image->info['height'] = $height;
- return TRUE;
-}
-
-/**
- * Rotate an image the given number of degrees.
- *
- * @param $image
- * An image object. The $image->resource, $image->info['width'], and
- * $image->info['height'] values will be modified by this call.
- * @param $degrees
- * The number of (clockwise) degrees to rotate the image.
- * @param $background
- * 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
- * TRUE or FALSE, based on success.
- *
- * @see image_rotate()
- */
-function image_gd_rotate(stdClass $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));
- return FALSE;
- }
-
- $width = $image->info['width'];
- $height = $image->info['height'];
-
- // Convert the hexadecimal background value to a color index value.
- if (isset($background)) {
- $rgb = array();
- for ($i = 16; $i >= 0; $i -= 8) {
- $rgb[] = (($background >> $i) & 0xFF);
- }
- $background = imagecolorallocatealpha($image->resource, $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);
-
- // If no transparent colors, use white.
- if ($background == 0) {
- $background = imagecolorallocatealpha($image->resource, 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 ($transparent_index != 0) {
- $transparent_gif_color = imagecolorsforindex($image->resource, $transparent_index);
- }
- }
-
- $image->resource = imagerotate($image->resource, 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);
- }
-
- $image->info['width'] = imagesx($image->resource);
- $image->info['height'] = imagesy($image->resource);
- return TRUE;
-}
-
-/**
- * Crop an image using the GD toolkit.
- *
- * @param $image
- * An image object. The $image->resource, $image->info['width'], and
- * $image->info['height'] values will be modified by this call.
- * @param $x
- * The starting x offset at which to start the crop, in pixels.
- * @param $y
- * The starting y offset at which to start the crop, in pixels.
- * @param $width
- * The width of the cropped area, in pixels.
- * @param $height
- * The height of the cropped area, in pixels.
- * @return
- * TRUE or FALSE, based on success.
- *
- * @see image_crop()
- */
-function image_gd_crop(stdClass $image, $x, $y, $width, $height) {
- $res = image_gd_create_tmp($image, $width, $height);
-
- if (!imagecopyresampled($res, $image->resource, 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;
- return TRUE;
-}
-
-/**
- * Convert an image resource to grayscale.
- *
- * Note that transparent GIFs loose transparency when desaturated.
- *
- * @param $image
- * An image object. The $image->resource value will be modified by this call.
- * @return
- * TRUE or FALSE, based on success.
- *
- * @see image_desaturate()
- */
-function image_gd_desaturate(stdClass $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));
- return FALSE;
- }
-
- return imagefilter($image->resource, IMG_FILTER_GRAYSCALE);
-}
-
-/**
- * GD helper function to create an image resource from a file.
- *
- * @param $image
- * An image object. The $image->resource value will populated by this call.
- * @return
- * TRUE or FALSE, based on success.
- *
- * @see image_load()
- */
-function image_gd_load(stdClass $image) {
- $extension = str_replace('jpg', 'jpeg', $image->info['extension']);
- $function = 'imagecreatefrom' . $extension;
- if (function_exists($function) && $image->resource = $function($image->source)) {
- if (!imageistruecolor($image->resource)) {
- // Convert indexed images to true color, so that filters work
- // correctly and don't result in unnecessary dither.
- $new_image = image_gd_create_tmp($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;
- }
- return (bool) $image->resource;
- }
-
- return FALSE;
-}
-
-/**
- * GD helper to write an image resource to a destination file.
- *
- * @param $image
- * An image object.
- * @param $destination
- * A string file URI or path where the image should be saved.
- * @return
- * TRUE or FALSE, based on success.
- *
- * @see image_save()
- */
-function image_gd_save(stdClass $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)) {
- // If destination is not local, save image to temporary local file.
- $local_wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_LOCAL);
- if (!isset($local_wrappers[$scheme])) {
- $permanent_destination = $destination;
- $destination = drupal_tempnam('temporary://', 'gd_');
- }
- // Convert stream wrapper URI to normal path.
- $destination = drupal_realpath($destination);
- }
-
- $extension = str_replace('jpg', 'jpeg', $image->info['extension']);
- $function = 'image' . $extension;
- if (!function_exists($function)) {
- return FALSE;
- }
- if ($extension == 'jpeg') {
- $success = $function($image->resource, $destination, variable_get('image_jpeg_quality', 75));
- }
- else {
- // Always save PNG images with full transparency.
- if ($extension == 'png') {
- imagealphablending($image->resource, FALSE);
- imagesavealpha($image->resource, TRUE);
- }
- $success = $function($image->resource, $destination);
- }
- // Move temporary local file to remote destination.
- if (isset($permanent_destination) && $success) {
- return (bool) file_unmanaged_move($destination, $permanent_destination, FILE_EXISTS_REPLACE);
- }
- return $success;
-}
-
-/**
- * Create a truecolor image preserving transparency from a provided image.
- *
- * @param $image
- * An image object.
- * @param $width
- * The new width of the new image, in pixels.
- * @param $height
- * The new height of the new image, in pixels.
- * @return
- * A GD image handle.
- */
-function image_gd_create_tmp(stdClass $image, $width, $height) {
- $res = imagecreatetruecolor($width, $height);
-
- if ($image->info['extension'] == 'gif') {
- // Grab transparent color index from image resource.
- $transparent = imagecolortransparent($image->resource);
-
- if ($transparent >= 0) {
- // The original must have a transparent color, allocate to the new image.
- $transparent_color = imagecolorsforindex($image->resource, $transparent);
- $transparent = imagecolorallocate($res, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']);
-
- // Flood with our new transparent color.
- imagefill($res, 0, 0, $transparent);
- imagecolortransparent($res, $transparent);
- }
- }
- elseif ($image->info['extension'] == 'png') {
- imagealphablending($res, FALSE);
- $transparency = imagecolorallocatealpha($res, 0, 0, 0, 127);
- imagefill($res, 0, 0, $transparency);
- imagealphablending($res, TRUE);
- imagesavealpha($res, TRUE);
- }
- else {
- imagefill($res, 0, 0, imagecolorallocate($res, 255, 255, 255));
- }
-
- return $res;
-}
-
-/**
- * Get details about an image.
- *
- * @param $image
- * An image object.
- * @return
- * 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').
- *
- * @see image_get_info()
- */
-function image_gd_get_info(stdClass $image) {
- $details = FALSE;
- $data = getimagesize($image->source);
-
- if (isset($data) && is_array($data)) {
- $extensions = array('1' => 'gif', '2' => 'jpg', '3' => 'png');
- $extension = isset($extensions[$data[2]]) ? $extensions[$data[2]] : '';
- $details = array(
- 'width' => $data[0],
- 'height' => $data[1],
- 'extension' => $extension,
- 'mime_type' => $data['mime'],
- );
- }
-
- return $details;
-}
-
-/**
- * @} End of "addtogroup image".
- */
diff --git a/core/modules/system/lib/Drupal/system/Plugin/ImageToolkitInterface.php b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkitInterface.php
new file mode 100644
index 0000000..2981f7a
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkitInterface.php
@@ -0,0 +1,156 @@
+resource, $image->info['width'], and
+ * $image->info['height'] values will be modified by this call.
+ * @param $width
+ * The new width of the resized image, in pixels.
+ * @param $height
+ * The new height of the resized image, in pixels.
+ * @return
+ * TRUE or FALSE, based on success.
+ *
+ * @see image_resize()
+ */
+ function resize(stdClass $image, $width, $height);
+
+ /**
+ * Rotate an image the given number of degrees.
+ *
+ * @param $image
+ * An image object. The $image->resource, $image->info['width'], and
+ * $image->info['height'] values will be modified by this call.
+ * @param $degrees
+ * The number of (clockwise) degrees to rotate the image.
+ * @param $background
+ * 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
+ * TRUE or FALSE, based on success.
+ *
+ * @see image_rotate()
+ */
+ function rotate(stdClass $image, $degrees, $background = NULL);
+
+ /**
+ * Crop an image.
+ *
+ * @param $image
+ * An image object. The $image->resource, $image->info['width'], and
+ * $image->info['height'] values will be modified by this call.
+ * @param $x
+ * The starting x offset at which to start the crop, in pixels.
+ * @param $y
+ * The starting y offset at which to start the crop, in pixels.
+ * @param $width
+ * The width of the cropped area, in pixels.
+ * @param $height
+ * The height of the cropped area, in pixels.
+ * @return
+ * TRUE or FALSE, based on success.
+ *
+ * @see image_crop()
+ */
+ function crop(stdClass $image, $x, $y, $width, $height);
+
+ /**
+ * Convert an image resource to grayscale.
+ *
+ * Note that transparent GIFs loose transparency when desaturated.
+ *
+ * @param $image
+ * An image object. The $image->resource value will be modified by this call.
+ * @return
+ * TRUE or FALSE, based on success.
+ *
+ * @see image_desaturate()
+ */
+ function desaturate(stdClass $image);
+
+ /**
+ * Create an image resource from a file.
+ *
+ * @param $image
+ * An image object. The $image->resource value will populated by this call.
+ * @return
+ * TRUE or FALSE, based on success.
+ *
+ * @see image_load()
+ */
+ function load(stdClass $image);
+
+ /**
+ * Write an image resource to a destination file.
+ *
+ * @param $image
+ * An image object.
+ * @param $destination
+ * A string file URI or path where the image should be saved.
+ * @return
+ * TRUE or FALSE, based on success.
+ *
+ * @see image_save()
+ */
+ function save(stdClass $image, $destination);
+
+ /**
+ * Get details about an image.
+ *
+ * @param $image
+ * An image object.
+ * @return
+ * 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').
+ *
+ * @see image_get_info()
+ */
+ function getInfo(stdClass $image);
+
+ /**
+ * Verify Image Toolkit is set up correctly.
+ *
+ * @return
+ * A boolean indicating if the GD toolkit is available on this machine.
+ */
+ static function checkAvailable();
+}
diff --git a/core/modules/system/lib/Drupal/system/Plugin/ImageToolkitManager.php b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkitManager.php
new file mode 100644
index 0000000..d801de0
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkitManager.php
@@ -0,0 +1,24 @@
+discovery = new HookDiscovery('image_toolkits');
+ $this->discovery = new AnnotatedClassDiscovery('system', 'imagetoolkit');
+ $this->factory = new DefaultFactory($this->discovery);
+ }
+}
diff --git a/core/modules/system/lib/Drupal/system/Plugin/system/imagetoolkit/GDToolkit.php b/core/modules/system/lib/Drupal/system/Plugin/system/imagetoolkit/GDToolkit.php
new file mode 100644
index 0000000..0a1b2af
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Plugin/system/imagetoolkit/GDToolkit.php
@@ -0,0 +1,301 @@
+checkAvailable()) {
+ $form['status'] = array(
+ '#markup' => t('The GD toolkit is installed and working properly.')
+ );
+
+ $form['image_jpeg_quality'] = array(
+ '#type' => 'number',
+ '#title' => t('JPEG quality'),
+ '#description' => t('Define the image quality for JPEG manipulations. Ranges from 0 to 100. Higher values mean better image quality but bigger files.'),
+ '#min' => 0,
+ '#max' => 100,
+ '#default_value' => config('system.image.gd')->get('jpeg_quality'),
+ '#field_suffix' => t('%'),
+ );
+ return $form;
+ }
+ else {
+ form_set_error('image_toolkit', t('The GD image toolkit requires that the GD module for PHP be installed and configured properly. For more information see PHP\'s image documentation.', array('@url' => 'http://php.net/image')));
+ return FALSE;
+ }
+ }
+
+ /**
+ * Implements Drupal\system\Plugin\ImageToolkitInterface::settingsFormSubmit().
+ */
+ function settingsFormSubmit($form, &$form_state) {
+ config('system.image.gd')
+ ->set('jpeg_quality', $form_state['values']['gd']['image_jpeg_quality'])
+ ->save();
+ }
+
+ /**
+ * Implements Drupal\system\Plugin\ImageToolkitInterface::resize().
+ */
+ function resize(stdClass $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'])) {
+ return FALSE;
+ }
+
+ imagedestroy($image->resource);
+ // Update image object.
+ $image->resource = $res;
+ $image->info['width'] = $width;
+ $image->info['height'] = $height;
+ return TRUE;
+ }
+
+ /**
+ * Implements Drupal\system\Plugin\ImageToolkitInterface::rotate().
+ */
+ function rotate(stdClass $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));
+ return FALSE;
+ }
+
+ $width = $image->info['width'];
+ $height = $image->info['height'];
+
+ // Convert the hexadecimal background value to a color index value.
+ if (isset($background)) {
+ $rgb = array();
+ for ($i = 16; $i >= 0; $i -= 8) {
+ $rgb[] = (($background >> $i) & 0xFF);
+ }
+ $background = imagecolorallocatealpha($image->resource, $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);
+
+ // If no transparent colors, use white.
+ if ($background == 0) {
+ $background = imagecolorallocatealpha($image->resource, 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 ($transparent_index != 0) {
+ $transparent_gif_color = imagecolorsforindex($image->resource, $transparent_index);
+ }
+ }
+
+ $image->resource = imagerotate($image->resource, 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);
+ }
+
+ $image->info['width'] = imagesx($image->resource);
+ $image->info['height'] = imagesy($image->resource);
+ return TRUE;
+ }
+
+ /**
+ * Implements Drupal\system\Plugin\ImageToolkitInterface::crop().
+ */
+ function crop(stdClass $image, $x, $y, $width, $height) {
+ $res = $this->createTmp($image, $width, $height);
+
+ if (!imagecopyresampled($res, $image->resource, 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;
+ return TRUE;
+ }
+
+ /**
+ * Implements Drupal\system\Plugin\ImageToolkitInterface::desaturate().
+ */
+ function desaturate(stdClass $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));
+ return FALSE;
+ }
+
+ return imagefilter($image->resource, IMG_FILTER_GRAYSCALE);
+ }
+
+ /**
+ * Implements Drupal\system\Plugin\ImageToolkitInterface::load().
+ */
+ function load(stdClass $image) {
+ $extension = str_replace('jpg', 'jpeg', $image->info['extension']);
+ $function = 'imagecreatefrom' . $extension;
+ if (function_exists($function) && $image->resource = $function($image->source)) {
+ if (!imageistruecolor($image->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;
+ }
+ return (bool) $image->resource;
+ }
+
+ return FALSE;
+ }
+
+ /**
+ * Implements Drupal\system\Plugin\ImageToolkitInterface::save().
+ */
+ function save(stdClass $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)) {
+ // If destination is not local, save image to temporary local file.
+ $local_wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_LOCAL);
+ if (!isset($local_wrappers[$scheme])) {
+ $permanent_destination = $destination;
+ $destination = drupal_tempnam('temporary://', 'gd_');
+ }
+ // Convert stream wrapper URI to normal path.
+ $destination = drupal_realpath($destination);
+ }
+
+ $extension = str_replace('jpg', 'jpeg', $image->info['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'));
+ }
+ else {
+ // Always save PNG images with full transparency.
+ if ($extension == 'png') {
+ imagealphablending($image->resource, FALSE);
+ imagesavealpha($image->resource, TRUE);
+ }
+ $success = $function($image->resource, $destination);
+ }
+ // Move temporary local file to remote destination.
+ if (isset($permanent_destination) && $success) {
+ return (bool) file_unmanaged_move($destination, $permanent_destination, FILE_EXISTS_REPLACE);
+ }
+ return $success;
+ }
+
+ /**
+ * Implements Drupal\system\Plugin\ImageToolkitInterface::getInfo().
+ */
+ function getInfo(stdClass $image) {
+ $details = FALSE;
+ $data = getimagesize($image->source);
+
+ if (isset($data) && is_array($data)) {
+ $extensions = array('1' => 'gif', '2' => 'jpg', '3' => 'png');
+ $extension = isset($extensions[$data[2]]) ? $extensions[$data[2]] : '';
+ $details = array(
+ 'width' => $data[0],
+ 'height' => $data[1],
+ 'extension' => $extension,
+ 'mime_type' => $data['mime'],
+ );
+ }
+
+ return $details;
+ }
+
+ /**
+ * Create a truecolor image preserving transparency from a provided image.
+ *
+ * @param $image
+ * An image object.
+ * @param $width
+ * The new width of the new image, in pixels.
+ * @param $height
+ * The new height of the new image, in pixels.
+ * @return
+ * A GD image handle.
+ */
+ function createTmp(stdClass $image, $width, $height) {
+ $res = imagecreatetruecolor($width, $height);
+
+ if ($image->info['extension'] == 'gif') {
+ // Grab transparent color index from image resource.
+ $transparent = imagecolortransparent($image->resource);
+
+ if ($transparent >= 0) {
+ // The original must have a transparent color, allocate to the new image.
+ $transparent_color = imagecolorsforindex($image->resource, $transparent);
+ $transparent = imagecolorallocate($res, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']);
+
+ // Flood with our new transparent color.
+ imagefill($res, 0, 0, $transparent);
+ imagecolortransparent($res, $transparent);
+ }
+ }
+ elseif ($image->info['extension'] == 'png') {
+ imagealphablending($res, FALSE);
+ $transparency = imagecolorallocatealpha($res, 0, 0, 0, 127);
+ imagefill($res, 0, 0, $transparency);
+ imagealphablending($res, TRUE);
+ imagesavealpha($res, TRUE);
+ }
+ else {
+ imagefill($res, 0, 0, imagecolorallocate($res, 255, 255, 255));
+ }
+
+ return $res;
+ }
+
+ /**
+ * Implements Drupal\system\Plugin\ImageToolkitInterface::checkAvailable().
+ */
+ public static function checkAvailable() {
+ if ($check = get_extension_funcs('gd')) {
+ if (in_array('imagegd2', $check)) {
+ // GD2 support is available.
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+}
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 611126d..f03a1e5 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitGdTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitGdTest.php
@@ -8,6 +8,7 @@
namespace Drupal\system\Tests\Image;
use Drupal\simpletest\WebTestBase;
+use Drupal\system\Plugin\ImageToolkitManager;
/**
* Test the core GD image manipulation functions.
@@ -35,8 +36,9 @@ class ToolkitGdTest extends WebTestBase {
}
protected function checkRequirements() {
- image_get_available_toolkits();
- if (!function_exists('image_gd_check_settings') || !image_gd_check_settings()) {
+ $manager = new ImageToolkitManager();
+ $definition = $manager->getDefinition('gd');
+ if (!call_user_func($definition['class'] . '::checkAvailable')) {
return array(
'Image manipulations for the GD toolkit cannot run because the GD toolkit is not available.',
);
@@ -204,7 +206,7 @@ class ToolkitGdTest extends WebTestBase {
foreach ($files as $file) {
foreach ($operations as $op => $values) {
// Load up a fresh image.
- $image = image_load(drupal_get_path('module', 'simpletest') . '/files/' . $file, 'gd');
+ $image = image_load(drupal_get_path('module', 'simpletest') . '/files/' . $file, image_get_toolkit('gd'));
if (!$image) {
$this->fail(t('Could not load image %file.', array('%file' => $file)));
continue 2;
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 091fc5a..c70719a 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTest.php
@@ -36,7 +36,7 @@ class ToolkitTest extends ToolkitTestBase {
function testLoad() {
$image = image_load($this->file, $this->toolkit);
$this->assertTrue(is_object($image), t('Returned an object.'));
- $this->assertEqual($this->toolkit, $image->toolkit, t('Image had toolkit set.'));
+ $this->assertEqual($this->toolkit, $image->toolkit);
$this->assertToolkitOperationsCalled(array('load', 'get_info'));
}
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 ac47080..d06938a 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTestBase.php
@@ -30,7 +30,7 @@ abstract class ToolkitTestBase extends WebTestBase {
parent::setUp();
// Use the image_test.module's test toolkit.
- $this->toolkit = 'test';
+ $this->toolkit = image_get_toolkit('test');
// Pick a file for testing.
$file = current($this->drupalGetTestFiles('image'));
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index 2bf4343..460cce1 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -5,6 +5,7 @@
* Admin page callbacks for the system module.
*/
+use Drupal\system\Plugin\ImageToolkitManager;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
@@ -1871,39 +1872,59 @@ function system_file_system_settings() {
* Form builder; Configure site image toolkit usage.
*
* @ingroup forms
- * @see system_settings_form()
+ * @see system_image_toolkit_settings_submit()
*/
-function system_image_toolkit_settings() {
+function system_image_toolkit_settings($form, &$form_state) {
+ $config = config('system.image');
+
$toolkits_available = image_get_available_toolkits();
- $current_toolkit = image_get_toolkit();
+ $current_toolkit = config('system.image')->get('toolkit');
- if (count($toolkits_available) == 0) {
- variable_del('image_toolkit');
- $form['image_toolkit_help'] = array(
- '#markup' => t("No image toolkits were detected. Drupal includes support for PHP's built-in image processing functions but they were not detected on this system. You should consult your system administrator to have them enabled, or try using a third party toolkit.", array('gd-link' => url('http://php.net/gd'))),
- );
- return $form;
+ $options = array();
+ foreach($toolkits_available as $id => $definition) {
+ $options[$id] = $definition['title'];
}
- if (count($toolkits_available) > 1) {
- $form['image_toolkit'] = array(
- '#type' => 'radios',
- '#title' => t('Select an image processing toolkit'),
- '#default_value' => variable_get('image_toolkit', $current_toolkit),
- '#options' => $toolkits_available
+ $form['image_toolkit'] = array(
+ '#type' => 'radios',
+ '#title' => t('Select an image processing toolkit'),
+ '#default_value' => $current_toolkit,
+ '#options' => $options,
+ );
+
+ // Get the toolkit settings forms.
+ $manager = new ImageToolkitManager();
+ foreach ($toolkits_available as $id => $definition) {
+ $toolkit = $manager->createInstance($id);
+ $form['image_toolkit_settings'][$id] = array(
+ '#type' => 'fieldset',
+ '#title' => t('@toolkit settings', array('@toolkit' => $definition['title'])),
+ '#collapsible' => TRUE,
+ '#collapsed' => ($id == $current_toolkit) ? FALSE : TRUE,
+ '#tree' => TRUE,
);
- }
- else {
- variable_set('image_toolkit', key($toolkits_available));
+ $form['image_toolkit_settings'][$id] += $toolkit->settingsForm();
}
- // Get the toolkit's settings form.
- $function = 'image_' . $current_toolkit . '_settings';
- if (function_exists($function)) {
- $form['image_toolkit_settings'] = $function();
- }
+ return system_config_form($form, $form_state);
+}
- return system_settings_form($form);
+/**
+ * Form submission handler for system_image_toolkit_settings().
+ */
+function system_image_toolkit_settings_submit($form, &$form_state) {
+ config('system.image')
+ ->set('toolkit', $form_state['values']['image_toolkit'])
+ ->save();
+
+ // Call the form submit handler for each of the toolkits.
+ // Get the toolkit settings forms.
+ $manager = new ImageToolkitManager();
+ $toolkits_available = image_get_available_toolkits();
+ foreach ($toolkits_available as $id => $definition) {
+ $toolkit = $manager->createInstance($id);
+ $toolkit->settingsFormSubmit($form, $form_state);
+ }
}
/**
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 486afba..4021e52 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -1884,6 +1884,19 @@ function system_update_8019() {
}
/**
+ * Moves image toolkit settings from variable to config.
+ *
+ * @ingroup config_upgrade
+ */
+function system_update_8020() {
+ update_variables_to_config('system.image', array(
+ 'image_toolkit' => 'toolkit',
+ ));
+ update_variables_to_config('system.image.gd', array(
+ 'image_jpeg_quality' => 'jpeg_quality',
+ ));
+}
+/**
* @} End of "defgroup updates-7.x-to-8.x".
* The next series of updates should start at 9000.
*/
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index f78f123..278bd4d 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -3836,19 +3836,6 @@ function theme_system_compact_link() {
}
/**
- * Implements hook_image_toolkits().
- */
-function system_image_toolkits() {
- include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'system') . '/' . 'image.gd.inc';
- return array(
- 'gd' => array(
- 'title' => t('GD2 image manipulation toolkit'),
- 'available' => function_exists('image_gd_check_settings') && image_gd_check_settings(),
- ),
- );
-}
-
-/**
* Attempts to get a file using drupal_http_request and to store it locally.
*
* @param $url
diff --git a/core/modules/system/tests/modules/image_test/image_test.module b/core/modules/system/tests/modules/image_test/image_test.module
index de640f0..c6291f2 100644
--- a/core/modules/system/tests/modules/image_test/image_test.module
+++ b/core/modules/system/tests/modules/image_test/image_test.module
@@ -6,22 +6,6 @@
*/
/**
- * Implements hook_image_toolkits().
- */
-function image_test_image_toolkits() {
- return array(
- 'test' => array(
- 'title' => t('A dummy toolkit that works'),
- 'available' => TRUE,
- ),
- 'broken' => array(
- 'title' => t('A dummy toolkit that is "broken"'),
- 'available' => FALSE,
- ),
- );
-}
-
-/**
* Reset/initialize the history of calls to the toolkit functions.
*
* @see image_test_get_all_calls()
diff --git a/core/modules/system/tests/modules/image_test/lib/Drupal/image_test/Plugin/system/imagetoolkit/BrokenToolkit.php b/core/modules/system/tests/modules/image_test/lib/Drupal/image_test/Plugin/system/imagetoolkit/BrokenToolkit.php
new file mode 100644
index 0000000..439191d
--- /dev/null
+++ b/core/modules/system/tests/modules/image_test/lib/Drupal/image_test/Plugin/system/imagetoolkit/BrokenToolkit.php
@@ -0,0 +1,29 @@
+_logCall('settings', array());
+ return array();
+ }
+
+ /**
+ * Implements Drupal\system\Plugin\ImageToolkitInterface::settingsFormSubmit().
+ */
+ function settingsFormSubmit($form, &$form_state) {}
+
+ /**
+ * Implements Drupal\system\Plugin\ImageToolkitInterface::getInfo().
+ */
+ function getInfo(stdClass $image) {
+ $this->_logCall('get_info', array($image));
+ return array();
+ }
+
+ /**
+ * Implements Drupal\system\Plugin\ImageToolkitInterface::load().
+ */
+ function load(stdClass $image) {
+ $this->_logCall('load', array($image));
+ return $image;
+ }
+
+ /**
+ * Implements Drupal\system\Plugin\ImageToolkitInterface::save().
+ */
+ function save(stdClass $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.
+ return FALSE;
+ }
+
+ /**
+ * Implements Drupal\system\Plugin\ImageToolkitInterface::crop().
+ */
+ function crop(stdClass $image, $x, $y, $width, $height) {
+ $this->_logCall('crop', array($image, $x, $y, $width, $height));
+ return TRUE;
+ }
+
+ /**
+ * Implements Drupal\system\Plugin\ImageToolkitInterface::resize().
+ */
+ function resize(stdClass $image, $width, $height) {
+ $this->_logCall('resize', array($image, $width, $height));
+ return TRUE;
+ }
+
+ /**
+ * Implements Drupal\system\Plugin\ImageToolkitInterface::rotate().
+ */
+ function rotate(stdClass $image, $degrees, $background = NULL) {
+ $this->_logCall('rotate', array($image, $degrees, $background));
+ return TRUE;
+ }
+
+ /**
+ * Implements Drupal\system\Plugin\ImageToolkitInterface::desaturate().
+ */
+ function desaturate(stdClass $image) {
+ $this->_logCall('desaturate', array($image));
+ return TRUE;
+ }
+
+ /**
+ * Store the values passed to a toolkit call.
+ *
+ * @param $op
+ * One of the image toolkit operations: 'get_info', 'load', 'save',
+ * 'settings', 'resize', 'rotate', 'crop', 'desaturate'.
+ * @param $args
+ * Values passed to hook.
+ *
+ * @see image_test_get_all_calls()
+ * @see image_test_reset()
+ */
+ function _logCall($op, $args) {
+ $results = variable_get('image_test_results', array());
+ $results[$op][] = $args;
+ variable_set('image_test_results', $results);
+ }
+
+ /**
+ * Implements Drupal\system\Plugin\ImageToolkitInterface::checkAvailable().
+ */
+ static function checkAvailable() {
+ return TRUE;
+ }
+}