diff --git a/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php b/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php
index 7b195cc..5619535 100644
--- a/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php
+++ b/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php
@@ -235,12 +235,21 @@ public function save($destination) {
       $success = $function($this->getResource(), $destination, $this->configFactory->get('system.image.gd')->get('jpeg_quality'));
     }
     else {
-      // Always save PNG images with full transparency.
-      if ($this->getType() == IMAGETYPE_PNG) {
+      // Always save alpha supporting images with alpha information.
+      $alpha_types = [IMAGETYPE_PNG];
+      if (static::isWebpSupported()) {
+        $alpha_types[] = IMAGETYPE_WEBP;
+      }
+      if (in_array($this->getType(), $alpha_types)) {
         imagealphablending($this->getResource(), FALSE);
         imagesavealpha($this->getResource(), TRUE);
       }
-      $success = $function($this->getResource(), $destination);
+      if ($function === 'imagewebp') {
+        $success = $function($this->getResource(), $destination, 100);
+      }
+      else {
+        $success = $function($this->getResource(), $destination);
+      }
     }
     // Move temporary local file to remote destination.
     if (isset($permanent_destination) && $success) {
@@ -440,7 +449,21 @@ public function extensionToImageType($extension) {
    *   IMAGETYPE_* constant (e.g. IMAGETYPE_JPEG, IMAGETYPE_PNG, etc.).
    */
   protected static function supportedTypes() {
-    return array(IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_GIF);
+    $supported_types = [IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_GIF];
+    if (static::isWebpSupported()) {
+      $supported_types[] = IMAGETYPE_WEBP;
+    }
+    return $supported_types;
+  }
+
+  /**
+   * Checks if WEBP images can be supported.
+   *
+   * @return bool
+   *   TRUE if WEBP images can be processed by GD, FALSE otherwise.
+   */
+  public static function isWebpSupported() {
+    return PHP_VERSION_ID >= 70100 && function_exists('imagewebp') ? TRUE : FALSE;
   }
 
 }
diff --git a/core/modules/system/src/Plugin/ImageToolkit/Operation/gd/CreateNew.php b/core/modules/system/src/Plugin/ImageToolkit/Operation/gd/CreateNew.php
index 0d1c5a6..7d63d2d 100644
--- a/core/modules/system/src/Plugin/ImageToolkit/Operation/gd/CreateNew.php
+++ b/core/modules/system/src/Plugin/ImageToolkit/Operation/gd/CreateNew.php
@@ -90,9 +90,13 @@ protected function execute(array $arguments) {
       return FALSE;
     }
 
+    // Handles IMAGETYPE_WEBP as it is missing before PHP 7.1.
+    $webp = $this->getToolkit()->isWebpSupported() ? IMAGETYPE_WEBP : -1;
+
     // Fill the resource with transparency as possible.
     switch ($type) {
       case IMAGETYPE_PNG:
+      case $webp:
         imagealphablending($res, FALSE);
         $transparency = imagecolorallocatealpha($res, 0, 0, 0, 127);
         imagefill($res, 0, 0, $transparency);
diff --git a/core/tests/Drupal/KernelTests/Core/Image/ToolkitGdTest.php b/core/tests/Drupal/KernelTests/Core/Image/ToolkitGdTest.php
index fe36c3d..4570104 100644
--- a/core/tests/Drupal/KernelTests/Core/Image/ToolkitGdTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Image/ToolkitGdTest.php
@@ -65,6 +65,23 @@ protected function checkRequirements() {
   }
 
   /**
+   * Builds a WebP format test image using GD primitives.
+   */
+  protected function buildWebpTestImage() {
+    $res = imagecreatetruecolor(40, 20);
+    $red = imagecolorallocatealpha($res, 255, 0, 0, 0);
+    $green = imagecolorallocatealpha($res, 0, 255, 0, 0);
+    $blue = imagecolorallocatealpha($res, 0, 0, 255, 0);
+    $yellow_transparent = imagecolorallocatealpha($res, 255, 255, 0, 127);
+    imagefilledrectangle($res, 0, 0, 19, 9, $red);
+    imagefilledrectangle($res, 20, 0, 39, 9, $green);
+    imagefilledrectangle($res, 20, 10, 39, 19, $blue);
+    imagefilledrectangle($res, 0, 10, 19, 19, $yellow_transparent);
+    imagesavealpha($res, TRUE);
+    imagewebp($res, Settings::get('file_public_path') . '/sourceimagetest/img-test.webp', 100);
+  }
+
+  /**
    * Function to compare two colors by RGBa.
    */
   function colorsAreEqual($color_a, $color_b) {
@@ -107,8 +124,14 @@ function testManipulations() {
     // Test that the image factory is set to use the GD toolkit.
     $this->assertEqual($this->imageFactory->getToolkitId(), 'gd', 'The image factory is set to use the \'gd\' image toolkit.');
 
+    // Get a blank Image object.
+    $image = $this->imageFactory->get();
+
     // Test the list of supported extensions.
     $expected_extensions = ['png', 'gif', 'jpeg', 'jpg', 'jpe'];
+    if ($image->getToolkit()->isWebpSupported()) {
+      $expected_extensions[] = 'webp';
+    }
     $supported_extensions = $this->imageFactory->getSupportedExtensions();
     $this->assertEqual($expected_extensions, array_intersect($expected_extensions, $supported_extensions));
 
@@ -121,7 +144,9 @@ function testManipulations() {
       'jpg' => IMAGETYPE_JPEG,
       'jpe' => IMAGETYPE_JPEG
     ];
-    $image = $this->imageFactory->get();
+    if ($image->getToolkit()->isWebpSupported()) {
+      $expected_image_types['webp'] = IMAGETYPE_WEBP;
+    }
     foreach ($expected_image_types as $extension => $expected_image_type) {
       $image_type = $image->getToolkit()->extensionToImageType($extension);
       $this->assertSame($expected_image_type, $image_type);
@@ -212,6 +237,17 @@ function testManipulations() {
         'corners' => $default_corners,
       ),
     );
+    if ($image->getToolkit()->isWebpSupported()) {
+      $operations += [
+        'convert_webp' => [
+          'function' => 'convert',
+          'width' => 40,
+          'height' => 20,
+          'arguments' => array('extension' => 'webp'),
+          'corners' => $default_corners,
+        ],
+      ];
+    }
 
     // Systems using non-bundled GD2 don't have imagerotate. Test if available.
     if (function_exists('imagerotate')) {
@@ -268,6 +304,17 @@ function testManipulations() {
       );
     }
 
+    // Prepare a directory with source test images.
+    $directory = Settings::get('file_public_path') . '/sourceimagetest';
+    file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
+    foreach ($files as $file) {
+      file_unmanaged_copy(drupal_get_path('module', 'simpletest') . '/files/' . $file, $directory, FILE_EXISTS_RENAME);
+    }
+    if ($image->getToolkit()->isWebpSupported()) {
+      $this->buildWebpTestImage();
+      $files[] = 'img-test.webp';
+    }
+
     // Prepare a directory for test file results.
     $directory = Settings::get('file_public_path') . '/imagetest';
     file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
@@ -275,7 +322,7 @@ function testManipulations() {
     foreach ($files as $file) {
       foreach ($operations as $op => $values) {
         // Load up a fresh image.
-        $image = $this->imageFactory->get(drupal_get_path('module', 'simpletest') . '/files/' . $file);
+        $image = $this->imageFactory->get(Settings::get('file_public_path') . '/sourceimagetest/' . $file);
         $toolkit = $image->getToolkit();
         if (!$image->isValid()) {
           $this->fail(SafeMarkup::format('Could not load image %file.', array('%file' => $file)));
@@ -323,6 +370,31 @@ function testManipulations() {
         // JPEG colors will always be messed up due to compression. So we skip
         // these tests if the original or the result is in jpeg format.
         if ($image->getToolkit()->getType() != IMAGETYPE_JPEG && $image_original_type != IMAGETYPE_JPEG) {
+
+          // WebP test adjustments.
+          // @todo address these in a more general way.
+          if ($file === 'img-test.webp') {
+            if (in_array($op, ['resize', 'scale_x', 'scale_y', 'upscale_x', 'upscale_y', 'convert_gif', 'convert_png', 'convert_webp'])) {
+              $values['corners'][0] = [255, 1, 0, 0];
+              $values['corners'][1] = [0, 255, 1, 0];
+              $values['corners'][3] = [0, 0, 0, 0];
+            }
+            if (in_array($op, ['crop', 'scale_and_crop'])) {
+              $values['corners'][0] = [255, 1, 0, 0];
+              $values['corners'][1] = [0, 255, 1, 0];
+              $values['corners'][2] = [0, 0, 255, 0];
+              $values['corners'][3] = [0, 0, 0, 0];
+            }
+            if (in_array($op, ['rotate_90', 'rotate_transparent_90'])) {
+              $values['corners'][0] = [0, 0, 0, 0];
+              $values['corners'][1] = [255, 1, 0, 0];
+              $values['corners'][2] = [0, 255, 1, 0];
+            }
+            if (in_array($op, ['desaturate'])) {
+              $values['corners'][3] = [0, 0, 0, 0];
+            }
+          }
+
           // Now check each of the corners to ensure color correctness.
           foreach ($values['corners'] as $key => $corner) {
             // The test gif that does not have transparency color set is a
@@ -364,8 +436,9 @@ function testManipulations() {
             // conversion. The convert operation cannot handle that correctly.
             if ($image->getToolkit()->getType() == $image_original_type || $corner != $this->transparent) {
               $correct_colors = $this->colorsAreEqual($color, $corner);
-              $this->assertTrue($correct_colors, SafeMarkup::format('Image %file object after %action action has the correct color placement at corner %corner.',
-                array('%file'   => $file, '%action' => $op, '%corner' => $key)));
+              $actual_color = implode(',', $color);
+              $expected_color = implode(',', $corner);
+              $this->assertTrue($correct_colors, "Color of image '{$file}' after '{$op}' operation at corner {$key} is ({$actual_color}), expected ({$expected_color}).");
             }
           }
         }
@@ -377,7 +450,11 @@ function testManipulations() {
     }
 
     // Test creation of image from scratch, and saving to storage.
-    foreach (array(IMAGETYPE_PNG, IMAGETYPE_GIF, IMAGETYPE_JPEG) as $type) {
+    $image_types = [IMAGETYPE_PNG, IMAGETYPE_GIF, IMAGETYPE_JPEG];
+    if ($image->getToolkit()->isWebpSupported()) {
+      $image_types[] = IMAGETYPE_WEBP;
+    }
+    foreach ($image_types as $type) {
       $image = $this->imageFactory->get();
       $image->createNew(50, 20, image_type_to_extension($type, FALSE), '#ffff00');
       $file = 'from_null' . image_type_to_extension($type);
