diff --git a/core/lib/Drupal/Core/Image/Image.php b/core/lib/Drupal/Core/Image/Image.php
index e4c7876..b39dac3 100644
--- a/core/lib/Drupal/Core/Image/Image.php
+++ b/core/lib/Drupal/Core/Image/Image.php
@@ -195,6 +195,13 @@ public function scaleAndCrop($width, $height) {
   /**
    * {@inheritdoc}
    */
+  public function scaleAndCropWithAnchor($x, $y, $width, $height) {
+    return $this->apply('scale_and_crop', ['x' => $x, 'y' => $y, 'width' => $width, 'height' => $height]);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function scale($width, $height = NULL, $upscale = FALSE) {
     return $this->apply('scale', ['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 29d092a..529e2d1 100644
--- a/core/lib/Drupal/Core/Image/ImageInterface.php
+++ b/core/lib/Drupal/Core/Image/ImageInterface.php
@@ -170,6 +170,27 @@ public function scale($width, $height = NULL, $upscale = FALSE);
   public function scaleAndCrop($width, $height);
 
   /**
+   * Scales an image to the exact width and height given (with an anchor).
+   *
+   * This function achieves the target aspect ratio by cropping the original
+   * image according to the x and  y offsets.
+   *
+   * The resulting image always has the exact target dimensions.
+   * @param int $x
+   *   The starting x offset at which to start the crop, in pixels.
+   * @param int $y
+   *   The starting y offset at which to start the crop, in pixels.
+   * @param int $width
+   *   The target width, in pixels.
+   * @param int $height
+   *   The target height, in pixels.
+   *
+   * @return bool
+   *   TRUE on success, FALSE on failure.
+   */
+  public function scaleAndCropWithAnchor($x, $y, $width, $height);
+
+  /**
    * Instructs the toolkit to save the image in the format specified by the
    * extension.
    *
diff --git a/core/modules/image/image.admin.inc b/core/modules/image/image.admin.inc
index e43bd48..01989ae 100644
--- a/core/modules/image/image.admin.inc
+++ b/core/modules/image/image.admin.inc
@@ -132,3 +132,4 @@ function template_preprocess_image_anchor(&$variables) {
     ],
   ];
 }
+
diff --git a/core/modules/image/image.module b/core/modules/image/image.module
index 1c00e03..a41d768 100644
--- a/core/modules/image/image.module
+++ b/core/modules/image/image.module
@@ -126,6 +126,8 @@ function image_theme() {
       'variables' => [
         'style_name' => NULL,
         'uri' => NULL,
+        'x' => NULL,
+        'y' => NULL,
         'width' => NULL,
         'height' => NULL,
         'alt' => '',
@@ -152,6 +154,9 @@ function image_theme() {
     'image_crop_summary' => [
       'variables' => ['data' => NULL, 'effect' => []],
     ],
+    'image_scale_and_crop_summary' => array(
+      'variables' => ['data' => NULL, 'effect' => []],
+    ),
     'image_rotate_summary' => [
       'variables' => ['data' => NULL, 'effect' => []],
     ],
diff --git a/core/modules/image/src/Plugin/ImageEffect/ScaleAndCropImageEffect.php b/core/modules/image/src/Plugin/ImageEffect/ScaleAndCropImageEffect.php
index 57ea0b2..a873f4a 100644
--- a/core/modules/image/src/Plugin/ImageEffect/ScaleAndCropImageEffect.php
+++ b/core/modules/image/src/Plugin/ImageEffect/ScaleAndCropImageEffect.php
@@ -13,17 +13,38 @@
  *   description = @Translation("Scale and crop will maintain the aspect-ratio of the original image, then crop the larger dimension. This is most useful for creating perfectly square thumbnails without stretching the image.")
  * )
  */
-class ScaleAndCropImageEffect extends ResizeImageEffect {
+class ScaleAndCropImageEffect extends CropImageEffect {
 
   /**
    * {@inheritdoc}
    */
   public function applyEffect(ImageInterface $image) {
-    if (!$image->scaleAndCrop($this->configuration['width'], $this->configuration['height'])) {
+    $width = $this->configuration['width'];
+    $height = $this->configuration['height'];
+    $scale = max($width / $image->getWidth(), $height / $image->getHeight());
+
+    list($x, $y) = explode('-', $this->configuration['anchor']);
+    $x = image_filter_keyword($x, $image->getWidth() * $scale, $width);
+    $y = image_filter_keyword($y, $image->getHeight() * $scale, $height);
+
+    if (!$image->scaleAndCropWithAnchor($x, $y, $width, $height)) {
       $this->logger->error('Image scale and crop failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', ['%toolkit' => $image->getToolkitId(), '%path' => $image->getSource(), '%mimetype' => $image->getMimeType(), '%dimensions' => $image->getWidth() . 'x' . $image->getHeight()]);
       return FALSE;
     }
     return TRUE;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getSummary() {
+    $summary = array(
+      '#theme' => 'image_scale_and_crop_summary',
+      '#data' => $this->configuration,
+    );
+    $summary += parent::getSummary();
+
+    return $summary;
+  }
+
 }
diff --git a/core/modules/image/templates/image-scale-and-crop-summary.html.twig b/core/modules/image/templates/image-scale-and-crop-summary.html.twig
new file mode 100644
index 0000000..b120e3f
--- /dev/null
+++ b/core/modules/image/templates/image-scale-and-crop-summary.html.twig
@@ -0,0 +1,32 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a summary of an image scale and crop effect.
+ *
+ * Available variables:
+ * - data: The current configuration for this resize effect, including:
+ *   - width: The width of the resized image.
+ *   - height: The height of the resized image.
+ *   - anchor: The part of the image that will be retained after cropping.
+ *   - anchor_label: The translated label of the crop anchor.
+ * - effect: The effect information, including:
+ *   - id: The effect identifier.
+ *   - label: The effect name.
+ *   - description: The effect description.
+ *
+ * @ingroup themeable
+ */
+#}
+{% if data.width and data.height -%}
+  {{ data.width }}×{{ data.height }}
+{%- else -%}
+  {% if data.width %}
+    {% trans %}
+      width {{ data.width }}
+    {% endtrans %}
+  {% elseif data.height %}
+    {% trans %}
+      height {{ data.height }}
+    {% endtrans %}
+  {% endif %}
+{%- endif %}
diff --git a/core/modules/image/tests/src/Functional/ImageEffectsTest.php b/core/modules/image/tests/src/Functional/ImageEffectsTest.php
index 3207442..14ab353 100644
--- a/core/modules/image/tests/src/Functional/ImageEffectsTest.php
+++ b/core/modules/image/tests/src/Functional/ImageEffectsTest.php
@@ -111,8 +111,10 @@ public function testScaleAndCropEffect() {
 
     // Check the parameters.
     $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->assertEqual($calls['scaleAndCrop'][0][1], 0, 'X was computed and passed correctly');
+    $this->assertEqual($calls['scaleAndCrop'][0][2], 1, 'Y was computed and passed correctly');
+    $this->assertEqual($calls['scaleAndCrop'][0][3], 5, 'Width was computed and passed correctly');
+    $this->assertEqual($calls['scaleAndCrop'][0][4], 10, 'Height was computed and passed correctly');
   }
 
   /**
diff --git a/core/modules/system/src/Plugin/ImageToolkit/Operation/gd/ScaleAndCrop.php b/core/modules/system/src/Plugin/ImageToolkit/Operation/gd/ScaleAndCrop.php
index 510020f..2fcda58 100644
--- a/core/modules/system/src/Plugin/ImageToolkit/Operation/gd/ScaleAndCrop.php
+++ b/core/modules/system/src/Plugin/ImageToolkit/Operation/gd/ScaleAndCrop.php
@@ -38,8 +38,12 @@ protected function validateArguments(array $arguments) {
 
     $scaleFactor = max($arguments['width'] / $actualWidth, $arguments['height'] / $actualHeight);
 
-    $arguments['x'] = (int) round(($actualWidth * $scaleFactor - $arguments['width']) / 2);
-    $arguments['y'] = (int) round(($actualHeight * $scaleFactor - $arguments['height']) / 2);
+    $arguments['x'] = isset($arguments['x']) ?
+      (int) round($arguments['x']) :
+      (int) round(($actualWidth * $scaleFactor - $arguments['width']) / 2);
+    $arguments['y'] = isset($arguments['y']) ?
+      (int) round($arguments['y']) :
+      (int) round(($actualHeight * $scaleFactor - $arguments['height']) / 2);
     $arguments['resize'] = [
       'width' => (int) round($actualWidth * $scaleFactor),
       'height' => (int) round($actualHeight * $scaleFactor),
