diff --git a/core/lib/Drupal/Component/Utility/Image.php b/core/lib/Drupal/Component/Utility/Image.php index dd06806..8708473 100644 --- a/core/lib/Drupal/Component/Utility/Image.php +++ b/core/lib/Drupal/Component/Utility/Image.php @@ -60,5 +60,4 @@ public static function scaleDimensions(array &$dimensions, $width = NULL, $heigh $dimensions['height'] = $height; return TRUE; } - } diff --git a/core/lib/Drupal/Core/ImageToolkit/ImageToolkitInterface.php b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitInterface.php index a5f96f3..9783c8e 100644 --- a/core/lib/Drupal/Core/ImageToolkit/ImageToolkitInterface.php +++ b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitInterface.php @@ -192,11 +192,15 @@ public function scale(ImageInterface $image, $width = NULL, $height = NULL, $ups * The target width, in pixels. * @param int $height * The target height, in pixels. + * @param bool $upscale + * (optional) Boolean indicating that files smaller than the dimensions will + * be scaled up. This generally results in a low quality image. Defaults + * to TRUE. * * @return bool * TRUE on success, FALSE on failure. */ - public function scaleAndCrop(ImageInterface $image, $width, $height); + public function scaleAndCrop(ImageInterface $image, $width, $height, $upscale = TRUE); /** * Gets details about an image. diff --git a/core/modules/image/config/schema/image.schema.yml b/core/modules/image/config/schema/image.schema.yml index b0dfd56..a6662e4 100644 --- a/core/modules/image/config/schema/image.schema.yml +++ b/core/modules/image/config/schema/image.schema.yml @@ -66,6 +66,10 @@ image.effect.image_scale: image.effect.image_scale_and_crop: type: image_size label: 'Image scale and crop' + mapping: + upscale: + type: boolean + label: 'Upscale' image.settings: type: mapping diff --git a/core/modules/image/image.admin.inc b/core/modules/image/image.admin.inc index 9675e98..b2e5918 100644 --- a/core/modules/image/image.admin.inc +++ b/core/modules/image/image.admin.inc @@ -223,7 +223,7 @@ function theme_image_resize_summary($variables) { /** * Returns HTML for a summary of an image scale effect. * - * @param $variables + * @param array $variables * An associative array containing: * - data: The current configuration for this scale effect. * @@ -234,7 +234,24 @@ function theme_image_scale_summary($variables) { '#theme' => 'image_resize_summary', '#data' => $variables['data'], ); - return drupal_render($image_resize_summary) . ' ' . ($variables['data']['upscale'] ? '(' . t('upscaling allowed') . ')' : ''); + return drupal_render($image_resize_summary) . ($variables['data']['upscale'] ? ' (' . t('upscaling allowed') . ')' : ''); +} + +/** + * Returns HTML for a summary of an image scale and crop effect. + * + * @param $variables + * An associative array containing: + * - data: The current configuration for this scale and crop effect. + * + * @ingroup themeable + */ +function theme_image_scale_and_crop_summary($variables) { + $image_scale_summary = array( + '#theme' => 'image_scale_summary', + '#data' => $variables['data'], + ); + return drupal_render($image_scale_summary); } /** diff --git a/core/modules/image/image.module b/core/modules/image/image.module index 13aef89..c4a801a 100644 --- a/core/modules/image/image.module +++ b/core/modules/image/image.module @@ -174,6 +174,10 @@ function image_theme() { 'variables' => array('data' => NULL), 'file' => 'image.admin.inc', ), + 'image_scale_and_crop_summary' => array( + 'variables' => array('data' => NULL), + 'file' => 'image.admin.inc', + ), 'image_rotate_summary' => array( 'variables' => array('data' => NULL), 'file' => 'image.admin.inc', diff --git a/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/ScaleAndCropImageEffect.php b/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/ScaleAndCropImageEffect.php index 7fed9b1..4286ad4 100644 --- a/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/ScaleAndCropImageEffect.php +++ b/core/modules/image/lib/Drupal/image/Plugin/ImageEffect/ScaleAndCropImageEffect.php @@ -24,11 +24,63 @@ class ScaleAndCropImageEffect extends ResizeImageEffect { * {@inheritdoc} */ public function applyEffect(ImageInterface $image) { - if (!$image->scaleAndCrop($this->configuration['width'], $this->configuration['height'])) { + if (!$image->scaleAndCrop($this->configuration['width'], $this->configuration['height'], $this->configuration['upscale'])) { watchdog('image', 'Image scale and crop failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->getToolkitId(), '%path' => $image->getSource(), '%mimetype' => $image->getMimeType(), '%dimensions' => $image->getWidth() . 'x' . $image->getHeight()), WATCHDOG_ERROR); return FALSE; } return TRUE; } + /** + * {@inheritdoc} + */ + public function transformDimensions(array &$dimensions) { + $width = $this->configuration['width']; + $height = $this->configuration['height']; + $image_width = $dimensions['width']; + $image_height = $dimensions['height']; + $upscale = $this->configuration['upscale']; + $scale = max($width / $image_width, $height / $image_height); + if (!$upscale && $scale >= 1) { + // When upscale is false and scale > 1, image will have original dimensions. + return TRUE; + } + // The new image will have the exact dimensions defined for the effect. + $dimensions['width'] = $this->configuration['width']; + $dimensions['height'] = $this->configuration['height']; + } + + /** + * {@inheritdoc} + */ + public function getSummary() { + return array( + '#theme' => 'image_scale_and_crop_summary', + '#data' => $this->configuration, + ); + } + + /** + * {@inheritdoc} + */ + public function defaultConfiguration() { + return parent::defaultConfiguration() + array( + 'upscale' => TRUE, + ); + } + + /** + * {@inheritdoc} + */ + public function getForm() { + $form = parent::getForm(); + $form['upscale'] = array( + '#type' => 'checkbox', + '#default_value' => $this->configuration['upscale'], + '#title' => t('Allow Upscaling'), + '#description' => t('Choose whether to make images larger than their original size'), + ); + return $form; + } + } diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageEffectsTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageEffectsTest.php index 8afcb22..f3c02ce 100644 --- a/core/modules/image/lib/Drupal/image/Tests/ImageEffectsTest.php +++ b/core/modules/image/lib/Drupal/image/Tests/ImageEffectsTest.php @@ -109,6 +109,7 @@ function testScaleAndCropEffect() { $calls = $this->imageTestGetAllCalls(); $this->assertEqual($calls['scaleAndCrop'][0][1], 5, 'Width was computed and passed correctly'); $this->assertEqual($calls['scaleAndCrop'][0][2], 10, 'Height was computed and passed correctly'); + $this->assertTrue($calls['scaleAndCrop'][0][3], 'Upscale was passed correctly'); } /** diff --git a/core/modules/system/lib/Drupal/system/Plugin/ImageToolkit/GDToolkit.php b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkit/GDToolkit.php index e5c5528..fbac473 100644 --- a/core/modules/system/lib/Drupal/system/Plugin/ImageToolkit/GDToolkit.php +++ b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkit/GDToolkit.php @@ -184,10 +184,14 @@ public function scale(ImageInterface $image, $width = NULL, $height = NULL, $ups /** * {@inheritdoc} */ - public function scaleAndCrop(ImageInterface $image, $width, $height) { + public function scaleAndCrop(ImageInterface $image, $width, $height, $upscale = TRUE) { // @todo Dimensions computation will be moved into a dedicated functionality // in https://drupal.org/node/2108307. $scale = max($width / $image->getWidth(), $height / $image->getHeight()); + if (!$upscale && $scale >= 1) { + // When upscale is false and scale > 1, image will have original dimensions. + return TRUE; + } $x = ($image->getWidth() * $scale - $width) / 2; $y = ($image->getHeight() * $scale - $height) / 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 b9e0d32..292c611 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTest.php @@ -80,7 +80,7 @@ function testScale() { * Test the image_scale_and_crop() function. */ function testScaleAndCrop() { - $this->assertTrue($this->image->scaleAndCrop(5, 10), 'Function returned the expected value.'); + $this->assertTrue($this->image->scaleAndCrop(5, 10, FALSE), 'Function returned the expected value.'); $this->assertToolkitOperationsCalled(array('scaleAndCrop')); // Check the parameters. @@ -88,6 +88,7 @@ function testScaleAndCrop() { $this->assertEqual($calls['scaleAndCrop'][0][1], 5, 'Width was computed and passed correctly'); $this->assertEqual($calls['scaleAndCrop'][0][2], 10, 'Height was computed and passed correctly'); + $this->assertFalse($calls['scaleAndCrop'][0][3], 'Upscale was passed correctly'); } /** diff --git a/core/modules/system/tests/modules/image_test/lib/Drupal/image_test/Plugin/ImageToolkit/TestToolkit.php b/core/modules/system/tests/modules/image_test/lib/Drupal/image_test/Plugin/ImageToolkit/TestToolkit.php index 5d62a82..325fe9f 100644 --- a/core/modules/system/tests/modules/image_test/lib/Drupal/image_test/Plugin/ImageToolkit/TestToolkit.php +++ b/core/modules/system/tests/modules/image_test/lib/Drupal/image_test/Plugin/ImageToolkit/TestToolkit.php @@ -127,8 +127,8 @@ public function scale(ImageInterface $image, $width = NULL, $height = NULL, $ups /** * {@inheritdoc} */ - public function scaleAndCrop(ImageInterface $image, $width, $height) { - $this->logCall('scaleAndCrop', array($image, $width, $height)); + public function scaleAndCrop(ImageInterface $image, $width, $height, $upscale = TRUE) { + $this->logCall('scaleAndCrop', array($image, $width, $height, $upscale)); return TRUE; }