diff --git a/core/lib/Drupal/Core/Image/Image.php b/core/lib/Drupal/Core/Image/Image.php index e170991..fe146ee 100644 --- a/core/lib/Drupal/Core/Image/Image.php +++ b/core/lib/Drupal/Core/Image/Image.php @@ -179,8 +179,8 @@ public function rotate($degrees, $background = NULL) { /** * {@inheritdoc} */ - public function scaleAndCrop($width, $height) { - return $this->apply('scale_and_crop', array('width' => $width, 'height' => $height)); + public function scaleAndCrop($width, $height, $upscale = TRUE) { + return $this->apply('scale_and_crop', array('width' => $width, 'height' => $height, 'upscale' => $upscale)); } /** diff --git a/core/lib/Drupal/Core/Image/ImageInterface.php b/core/lib/Drupal/Core/Image/ImageInterface.php index 02db478..63ad482 100644 --- a/core/lib/Drupal/Core/Image/ImageInterface.php +++ b/core/lib/Drupal/Core/Image/ImageInterface.php @@ -142,11 +142,14 @@ public function scale($width, $height = NULL, $upscale = FALSE); * 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. * * @return bool * TRUE on success, FALSE on failure. */ - public function scaleAndCrop($width, $height); + public function scaleAndCrop($width, $height, $upscale = TRUE); /** * Crops an image to a rectangle specified by the given dimensions. diff --git a/core/modules/image/config/schema/image.schema.yml b/core/modules/image/config/schema/image.schema.yml index 4f1fc79..2c8ca4f 100644 --- a/core/modules/image/config/schema/image.schema.yml +++ b/core/modules/image/config/schema/image.schema.yml @@ -58,6 +58,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.module b/core/modules/image/image.module index a6ce171..3209427 100644 --- a/core/modules/image/image.module +++ b/core/modules/image/image.module @@ -133,6 +133,10 @@ function image_theme() { 'variables' => array('data' => NULL, 'effect' => array()), 'template' => 'image-crop-summary', ), + 'image_scale_and_crop_summary' => array( + 'variables' => array('data' => NULL, 'effect' => array()), + 'template' => 'image-scale-and-crop-summary', + ), 'image_rotate_summary' => array( 'variables' => array('data' => NULL, 'effect' => array()), 'template' => 'image-rotate-summary', diff --git a/core/modules/image/src/Plugin/ImageEffect/ScaleAndCropImageEffect.php b/core/modules/image/src/Plugin/ImageEffect/ScaleAndCropImageEffect.php index ca9479f..31a004a 100644 --- a/core/modules/image/src/Plugin/ImageEffect/ScaleAndCropImageEffect.php +++ b/core/modules/image/src/Plugin/ImageEffect/ScaleAndCropImageEffect.php @@ -24,11 +24,74 @@ 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'])) { $this->logger->error('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())); 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() { + $summary = array( + '#theme' => 'image_scale_and_crop_summary', + '#data' => $this->configuration, + ); + $summary += parent::getSummary(); + return $summary; + } + + /** + * {@inheritdoc} + */ + public function defaultConfiguration() { + return parent::defaultConfiguration() + array( + 'upscale' => TRUE, + ); + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, array &$form_state) { + $form = parent::buildConfigurationForm($form, $form_state); + $form['upscale'] = array( + '#type' => 'checkbox', + '#default_value' => $this->configuration['upscale'], + '#title' => t('Allow Upscaling'), + '#description' => t('Let scale make images larger than their original size'), + ); + return $form; + } + + /** + * {@inheritdoc} + */ + public function submitConfigurationForm(array &$form, array &$form_state) { + parent::submitConfigurationForm($form, $form_state); + $this->configuration['upscale'] = $form_state['values']['upscale']; + } + } diff --git a/core/modules/image/src/Tests/ImageAdminStylesTest.php b/core/modules/image/src/Tests/ImageAdminStylesTest.php index d998883..a9093c0 100644 --- a/core/modules/image/src/Tests/ImageAdminStylesTest.php +++ b/core/modules/image/src/Tests/ImageAdminStylesTest.php @@ -80,6 +80,7 @@ function testStyle() { 'image_scale_and_crop' => array( 'data[width]' => 120, 'data[height]' => 121, + 'data[upscale]' => 1, ), 'image_crop' => array( 'data[width]' => 130, diff --git a/core/modules/image/src/Tests/ImageEffectsTest.php b/core/modules/image/src/Tests/ImageEffectsTest.php index 95fd952..40e99ff 100644 --- a/core/modules/image/src/Tests/ImageEffectsTest.php +++ b/core/modules/image/src/Tests/ImageEffectsTest.php @@ -55,10 +55,10 @@ function testResizeEffect() { * Test the image_scale_effect() function. */ function testScaleEffect() { - // @todo: need to test upscaling. $this->assertImageEffect('image_scale', array( 'width' => 10, 'height' => 10, + 'upscale' => TRUE, )); $this->assertToolkitOperationsCalled(array('scale')); @@ -66,6 +66,7 @@ function testScaleEffect() { $calls = $this->imageTestGetAllCalls(); $this->assertEqual($calls['scale'][0][0], 10, 'Width was passed correctly'); $this->assertEqual($calls['scale'][0][1], 10, 'Height was based off aspect ratio and passed correctly'); + $this->assertTrue($calls['scale'][0][2], 'Upscale was passed correctly'); } /** @@ -95,6 +96,7 @@ function testScaleAndCropEffect() { $this->assertImageEffect('image_scale_and_crop', array( 'width' => 5, 'height' => 10, + 'upscale' => TRUE, )); $this->assertToolkitOperationsCalled(array('scale_and_crop')); @@ -102,6 +104,7 @@ function testScaleAndCropEffect() { $calls = $this->imageTestGetAllCalls(); $this->assertEqual($calls['scale_and_crop'][0][0], 5, 'Width was computed and passed correctly'); $this->assertEqual($calls['scale_and_crop'][0][1], 10, 'Height was computed and passed correctly'); + $this->assertTrue($calls['scale_and_crop'][0][2], 'Upscale was passed correctly'); } /** diff --git a/core/modules/node/node.api.php b/core/modules/node/node.api.php index 6fb311c..4949f3e 100644 --- a/core/modules/node/node.api.php +++ b/core/modules/node/node.api.php @@ -204,7 +204,7 @@ function hook_node_access_records(\Drupal\node\NodeInterface $node) { * * A module may deny all access to a node by setting $grants to an empty array. * - * @param $grants + * @param array $grants * The $grants array returned by hook_node_access_records(). * @param \Drupal\node\NodeInterface $node * The node for which the grants were acquired. @@ -354,7 +354,7 @@ function hook_node_access(\Drupal\node\NodeInterface $node, $op, \Drupal\Core\Se * * @param \Drupal\node\NodeInterface $node * The node being displayed in a search result. - * @param $langcode + * @param object $langcode * Language code of result being displayed. * * @return array @@ -381,7 +381,7 @@ function hook_node_search_result(\Drupal\node\NodeInterface $node, $langcode) { * * @param \Drupal\node\NodeInterface $node * The node being indexed. - * @param $langcode + * @param object $langcode * Language code of the variant of the node being indexed. * * @return string @@ -414,9 +414,9 @@ function hook_node_update_index(\Drupal\node\NodeInterface $node, $langcode) { * * @param \Drupal\node\NodeInterface $node * The node being validated. - * @param $form + * @param array $form * The form being used to edit the node. - * @param $form_state + * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. * * @ingroup entity_crud @@ -441,9 +441,9 @@ function hook_node_validate(\Drupal\node\NodeInterface $node, $form, \Drupal\Cor * * @param \Drupal\node\NodeInterface $node * The node entity being updated in response to a form submission. - * @param $form + * @param array $form * The form being used to edit the node. - * @param $form_state + * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. * * @ingroup entity_crud