diff --git a/core/lib/Drupal/Core/Image/Image.php b/core/lib/Drupal/Core/Image/Image.php
index d1edb6e..5192701 100644
--- a/core/lib/Drupal/Core/Image/Image.php
+++ b/core/lib/Drupal/Core/Image/Image.php
@@ -20,11 +20,11 @@
 class Image implements ImageInterface {
 
   /**
-   * String specifying the path of the image file.
+   * Path of the image file.
    *
    * @var string
    */
-  protected $source;
+  protected $source = '';
 
   /**
    * An image toolkit object.
@@ -34,25 +34,18 @@ class Image implements ImageInterface {
   protected $toolkit;
 
   /**
-   * Image type represented by a PHP IMAGETYPE_* constant (e.g. IMAGETYPE_JPEG).
-   *
-   * @var int
-   */
-  protected $type;
-
-  /**
    * File size in bytes.
    *
    * @var int
    */
-  protected $fileSize = 0;
+  protected $fileSize;
 
   /**
-   * If this image file has been processed.
+   * If this image object is valid.
    *
    * @var bool
    */
-  protected $processed = FALSE;
+  protected $valid = FALSE;
 
   /**
    * Constructs a new Image object.
@@ -66,31 +59,21 @@ class Image implements ImageInterface {
   public function __construct(ImageToolkitInterface $toolkit, $source = NULL) {
     $this->toolkit = $toolkit;
     if ($source) {
-      $this->source = $source;
-      $this->processInfo();
+      $this->parseFile($source);
     }
   }
 
   /**
    * {@inheritdoc}
    */
-  public function isSupported() {
-    return in_array($this->getType(), $this->toolkit->supportedTypes());
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function isExisting() {
-    $this->processInfo();
-    return $this->processed;
+  public function isValid() {
+    return $this->valid;
   }
 
   /**
    * {@inheritdoc}
    */
   public function getHeight() {
-    $this->processInfo();
     return $this->toolkit->getHeight($this);
   }
 
@@ -98,7 +81,6 @@ public function getHeight() {
    * {@inheritdoc}
    */
   public function getWidth() {
-    $this->processInfo();
     return $this->toolkit->getWidth($this);
   }
 
@@ -106,32 +88,14 @@ public function getWidth() {
    * {@inheritdoc}
    */
   public function getFileSize() {
-    $this->processInfo();
     return $this->fileSize;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getType() {
-    $this->processInfo();
-    return $this->type;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function getMimeType() {
-    $this->processInfo();
-    return $this->type ? image_type_to_mime_type($this->type) : '';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setSource($source) {
-    $this->source = $source;
-    return $this;
+    return $this->toolkit->getMimeType($this);
   }
 
   /**
@@ -152,7 +116,6 @@ public function getToolkitId() {
    * {@inheritdoc}
    */
   public function getToolkit() {
-    $this->processInfo();
     return $this->toolkit;
   }
 
@@ -160,14 +123,17 @@ public function getToolkit() {
    * {@inheritdoc}
    */
   public function save($destination = NULL) {
-    if (empty($destination)) {
-      $destination = $this->getSource();
+    // Return immediately if the image is not valid.
+    if (!$this->isValid()) {
+      return FALSE;
     }
+
+    $destination = $destination ?: $this->getSource();
     if ($return = $this->toolkit->save($this, $destination)) {
       // Clear the cached file size and refresh the image information.
       clearstatcache(TRUE, $destination);
-      $this->setSource($destination);
-      $this->processInfo();
+      $this->fileSize = filesize($destination);
+      $this->source = $destination;
 
       // @todo Use File utility when https://drupal.org/node/2050759 is in.
       if ($this->chmod($destination)) {
@@ -178,33 +144,34 @@ public function save($destination = NULL) {
   }
 
   /**
-   * Prepares the image information.
+   * Determines if a file contains a valid image.
    *
    * Drupal supports GIF, JPG and PNG file formats when used with the GD
    * toolkit, and may support others, depending on which toolkits are
    * installed.
    *
+   * @param string $source
+   *   The path to an image file.
+   *
    * @return bool
    *   FALSE, if the file could not be found or is not an image. Otherwise, the
    *   image information is populated.
    */
-  protected function processInfo() {
-    if ($this->processed) {
-      return TRUE;
-    }
-
-    $destination = $this->getSource();
-    if (!is_file($destination) && !is_uploaded_file($destination)) {
+  protected function parseFile($source) {
+    // Check that file is valid.
+    if (!is_file($source) && !is_uploaded_file($source)) {
       return FALSE;
     }
 
-    if ($details = $this->toolkit->getInfo($this)) {
-      $this->type = $details['type'];
-      $this->fileSize = filesize($destination);
-
-      $this->processed = TRUE;
+    // Defer file parsing to toolkit.
+    if ($this->toolkit->parseFile($this, $source)) {
+      $this->fileSize = filesize($source);
+      $this->source = $source;
+      $this->valid = TRUE;
+      return TRUE;
     }
-    return TRUE;
+
+    return FALSE;
   }
 
   /**
@@ -227,22 +194,23 @@ protected function processInfo() {
    */
   public function __call($method, $arguments) {
     // @todo Temporary to avoid that legacy GD setResource(), getResource(),
-    //  hasResource() methods moved to GD toolkit in #2103621, and setWidth(),
-    //  setHeight() methods moved to ImageToolkitInterface in #2196067 get
+    //  hasResource() methods moved to GD toolkit in #2103621, setWidth(),
+    //  setHeight() methods moved to ImageToolkitInterface in #2196067,
+    //  getType() method moved to GDToolkit in #2211227 get
     //  invoked from this class anyway through the magic __call. Will be
-    //  removed through https://drupal.org/node/2110499, when
+    //  removed through https://drupal.org/node/2073759, when
     //  call_user_func_array() will be replaced by
     //  $this->toolkit->apply($name, $this, $arguments).
-    if (in_array($method, array('setResource', 'getResource', 'hasResource', 'setWidth', 'setHeight'))) {
-      throw new \BadMethodCallException();
+    if (in_array($method, array('setResource', 'getResource', 'hasResource', 'setWidth', 'setHeight', 'getType'))) {
+      throw new \BadMethodCallException($method);
     }
     if (is_callable(array($this->toolkit, $method))) {
-      // @todo In https://drupal.org/node/2110499, call_user_func_array() will
+      // @todo In https://drupal.org/node/2073759, call_user_func_array() will
       //   be replaced by $this->toolkit->apply($name, $this, $arguments).
       array_unshift($arguments, $this);
       return call_user_func_array(array($this->toolkit, $method), $arguments);
     }
-    throw new \BadMethodCallException();
+    throw new \BadMethodCallException($method);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Image/ImageFactory.php b/core/lib/Drupal/Core/Image/ImageFactory.php
index c7adf4c..ebd30b5 100644
--- a/core/lib/Drupal/Core/Image/ImageFactory.php
+++ b/core/lib/Drupal/Core/Image/ImageFactory.php
@@ -90,4 +90,23 @@ public function get($source = NULL, $toolkit_id = NULL) {
     $toolkit_id = $toolkit_id ?: $this->toolkitId;
     return new Image($this->toolkitManager->createInstance($toolkit_id), $source);
   }
+
+  /**
+   * Returns the image file extensions supported by the toolkit.
+   *
+   * @param string|null $toolkit_id
+   *   (optional) The ID of the image toolkit to use for checking, or NULL
+   *   to use the current toolkit.
+   *
+   * @return array
+   *   An array of supported image file extensions (e.g. png/jpeg/gif).
+   *
+   * @see \Drupal\Core\ImageToolkit\ImageToolkitInterface::getSupportedExtensions()
+   */
+  public function getSupportedExtensions($toolkit_id = NULL) {
+    $toolkit_id = $toolkit_id ?: $this->toolkitId;
+    $definition = $this->toolkitManager->getDefinition($toolkit_id);
+    return call_user_func($definition['class'] . '::getSupportedExtensions');
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Image/ImageInterface.php b/core/lib/Drupal/Core/Image/ImageInterface.php
index 7e0e1a5..efbd540 100644
--- a/core/lib/Drupal/Core/Image/ImageInterface.php
+++ b/core/lib/Drupal/Core/Image/ImageInterface.php
@@ -13,20 +13,12 @@
 interface ImageInterface {
 
   /**
-   * Checks if the image format is supported.
+   * Checks if the image is valid.
    *
    * @return bool
-   *   Returns TRUE if the image format is supported by the toolkit.
+   *   TRUE if the image object contains a valid image, FALSE otherwise.
    */
-  public function isSupported();
-
-  /**
-   * Checks if the image is existing.
-   *
-   * @return bool
-   *   TRUE if the image exists and is a valid image, FALSE otherwise.
-   */
-  public function isExisting();
+  public function isValid();
 
   /**
    * Returns the height of the image.
@@ -47,21 +39,12 @@ public function getWidth();
   /**
    * Returns the size of the image file.
    *
-   * @return int
-   *   The size of the file in bytes, or 0 if the file is invalid.
+   * @return int|null
+   *   The size of the file in bytes, or NULL if the image is invalid.
    */
   public function getFileSize();
 
   /**
-   * Returns the type of the image.
-   *
-   * @return int
-   *   The image type represented by a PHP IMAGETYPE_* constant (e.g.
-   *   IMAGETYPE_JPEG).
-   */
-  public function getType();
-
-  /**
    * Returns the MIME type of the image file.
    *
    * @return string
@@ -71,21 +54,11 @@ public function getType();
   public function getMimeType();
 
   /**
-   * Sets the source path of the image file.
-   *
-   * @param string $source
-   *   A string specifying the path of the image file.
-   *
-   * @return self
-   *   Returns this image file.
-   */
-  public function setSource($source);
-
-  /**
    * Retrieves the source path of the image file.
    *
    * @return string
-   *   The source path of the image file.
+   *   The source path of the image file. An empty string if the source is
+   *   not set or the image is invalid.
    */
   public function getSource();
 
diff --git a/core/lib/Drupal/Core/ImageToolkit/ImageToolkitInterface.php b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitInterface.php
index 177057b..7fbcede 100644
--- a/core/lib/Drupal/Core/ImageToolkit/ImageToolkitInterface.php
+++ b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitInterface.php
@@ -185,19 +185,17 @@ public function scale(ImageInterface $image, $width = NULL, $height = NULL, $ups
   public function scaleAndCrop(ImageInterface $image, $width, $height);
 
   /**
-   * Gets details about an image.
+   * Determines if a file contains a valid image.
    *
    * @param \Drupal\Core\Image\ImageInterface $image
    *   An image object.
+   * @param string $source
+   *   A string file URI or path where the image should be found.
    *
-   * @return array
-   *   If the file could not be found or is not an image, an empty array;
-   *   otherwise, a keyed array containing information about the image:
-   *   - "type": Image type represented as an IMAGETYPE_* constant.
-   *
-   * @see \Drupal\Core\Image\ImageInterface::processInfo()
+   * @return bool
+   *   TRUE if the file could be found and is an image, FALSE otherwise.
    */
-  public function getInfo(ImageInterface $image);
+  public function parseFile(ImageInterface $image, $source);
 
   /**
    * Returns the height of the image.
@@ -222,6 +220,18 @@ public function getHeight(ImageInterface $image);
   public function getWidth(ImageInterface $image);
 
   /**
+   * Returns the MIME type of the image file.
+   *
+   * @param \Drupal\Core\Image\ImageInterface $image
+   *   An image object.
+   *
+   * @return string
+   *   The MIME type of the image file, or an empty string if the image is
+   *   invalid.
+   */
+  public function getMimeType(ImageInterface $image);
+
+  /**
    * Gets toolkit requirements in a format suitable for hook_requirements().
    *
    * @return array
@@ -244,12 +254,11 @@ public function getRequirements();
   public static function isAvailable();
 
   /**
-   * Returns a list of image types supported by the toolkit.
+   * Returns a list of image file extensions supported by the toolkit.
    *
    * @return array
-   *   An array of available image types. An image type is represented by a PHP
-   *   IMAGETYPE_* constant (e.g. IMAGETYPE_JPEG, IMAGETYPE_PNG, etc.).
+   *   An array of supported image file extensions (e.g. png/jpeg/gif).
    */
-  public static function supportedTypes();
+  public static function getSupportedExtensions();
 
 }
diff --git a/core/modules/file/file.module b/core/modules/file/file.module
index 9fb3c60..607618e 100644
--- a/core/modules/file/file.module
+++ b/core/modules/file/file.module
@@ -396,7 +396,7 @@ function file_validate_size(File $file, $file_limit = 0, $user_limit = 0) {
 }
 
 /**
- * Checks that the file is recognized by Image::getInfo() as an image.
+ * Checks that the file is recognized as a valid image.
  *
  * @param \Drupal\file\File $file
  *   A file entity.
@@ -409,13 +409,11 @@ function file_validate_size(File $file, $file_limit = 0, $user_limit = 0) {
 function file_validate_is_image(File $file) {
   $errors = array();
 
-  $image = \Drupal::service('image.factory')->get($file->getFileUri());
-  if (!$image->isSupported()) {
-    $extensions = array();
-    foreach ($image->getToolkit()->supportedTypes() as $image_type) {
-      $extensions[] = Unicode::strtoupper(image_type_to_extension($image_type));
-    }
-    $errors[] = t('Image type not supported. Allowed types: @types.', array('@types' => implode(', ', $extensions)));
+  $image_factory = \Drupal::service('image.factory');
+  $image = $image_factory->get($file->getFileUri());
+  if (!$image->isValid()) {
+    $supported_extensions = $image_factory->getSupportedExtensions();
+    $errors[] = t('Image type not supported. Allowed types: %types', array('%types' => implode(' ', $supported_extensions)));
   }
 
   return $errors;
@@ -450,21 +448,19 @@ function file_validate_image_resolution(File $file, $maximum_dimensions = 0, $mi
   // Check first that the file is an image.
   $image_factory = \Drupal::service('image.factory');
   $image = $image_factory->get($file->getFileUri());
-  if ($image->isSupported()) {
+  if ($image->isValid()) {
     if ($maximum_dimensions) {
       // Check that it is smaller than the given dimensions.
       list($width, $height) = explode('x', $maximum_dimensions);
       if ($image->getWidth() > $width || $image->getHeight() > $height) {
         // Try to resize the image to fit the dimensions.
-        $image = $image_factory->get($file->getFileUri());
-        if ($image->isExisting()) {
-          $image->scale($width, $height);
+        if ($image->scale($width, $height)) {
           $image->save();
           $file->filesize = $image->getFileSize();
           drupal_set_message(t('The image was resized to fit within the maximum allowed dimensions of %dimensions pixels.', array('%dimensions' => $maximum_dimensions)));
         }
         else {
-          $errors[] = t('The image is too large; the maximum dimensions are %dimensions pixels.', array('%dimensions' => $maximum_dimensions));
+          $errors[] = t('The image exceeds the maximum allowed dimensions and an attempt to resize it failed.');
         }
       }
     }
diff --git a/core/modules/file/lib/Drupal/file/Tests/ValidatorTest.php b/core/modules/file/lib/Drupal/file/Tests/ValidatorTest.php
index b7d9bf4..d7f3af3 100644
--- a/core/modules/file/lib/Drupal/file/Tests/ValidatorTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/ValidatorTest.php
@@ -91,6 +91,12 @@ function testFileValidateImageResolution() {
       $this->assertTrue($image->getWidth() <= 10, 'Image scaled to correct width.', 'File');
       $this->assertTrue($image->getHeight() <= 5, 'Image scaled to correct height.', 'File');
 
+      // Once again, now with negative width and height to force an error.
+      copy('core/misc/druplicon.png', 'temporary://druplicon.png');
+      $this->image->setFileUri('temporary://druplicon.png');
+      $errors = file_validate_image_resolution($this->image, '-10x-5');
+      $this->assertEqual(count($errors), 1, 'An error reported for an oversized image that can not be scaled down.', 'File');
+
       drupal_unlink('temporary://druplicon.png');
     }
     else {
diff --git a/core/modules/image/image.module b/core/modules/image/image.module
index 61b30b9..7f1ff65 100644
--- a/core/modules/image/image.module
+++ b/core/modules/image/image.module
@@ -187,7 +187,7 @@ function image_file_download($uri) {
 
     // Check that the file exists and is an image.
     $image = \Drupal::service('image.factory')->get($uri);
-    if ($image->isSupported()) {
+    if ($image->isValid()) {
       // Check the permissions of the original to grant access to this image.
       $headers = \Drupal::moduleHandler()->invokeAll('file_download', array($original_uri));
       // Confirm there's at least one module granting access and none denying access.
diff --git a/core/modules/image/lib/Drupal/image/Entity/ImageStyle.php b/core/modules/image/lib/Drupal/image/Entity/ImageStyle.php
index d6e7d2a..5d39106 100644
--- a/core/modules/image/lib/Drupal/image/Entity/ImageStyle.php
+++ b/core/modules/image/lib/Drupal/image/Entity/ImageStyle.php
@@ -282,7 +282,7 @@ public function createDerivative($original_uri, $derivative_uri) {
     }
 
     $image = \Drupal::service('image.factory')->get($original_uri);
-    if (!$image->isExisting()) {
+    if (!$image->isValid()) {
       return FALSE;
     }
 
diff --git a/core/modules/image/lib/Drupal/image/Plugin/Field/FieldType/ImageItem.php b/core/modules/image/lib/Drupal/image/Plugin/Field/FieldType/ImageItem.php
index 249933e..f94c51d 100644
--- a/core/modules/image/lib/Drupal/image/Plugin/Field/FieldType/ImageItem.php
+++ b/core/modules/image/lib/Drupal/image/Plugin/Field/FieldType/ImageItem.php
@@ -303,7 +303,7 @@ public function preSave() {
     // Determine the dimensions if necessary.
     if (empty($width) || empty($height)) {
       $image = \Drupal::service('image.factory')->get($this->entity->getFileUri());
-      if ($image->isSupported()) {
+      if ($image->isValid()) {
         $this->width = $image->getWidth();
         $this->height =$image->getHeight();
       }
diff --git a/core/modules/image/lib/Drupal/image/Plugin/Field/FieldWidget/ImageWidget.php b/core/modules/image/lib/Drupal/image/Plugin/Field/FieldWidget/ImageWidget.php
index 26d4dea..439a183 100644
--- a/core/modules/image/lib/Drupal/image/Plugin/Field/FieldWidget/ImageWidget.php
+++ b/core/modules/image/lib/Drupal/image/Plugin/Field/FieldWidget/ImageWidget.php
@@ -166,7 +166,7 @@ public static function process($element, &$form_state, $form) {
       }
       else {
         $image = \Drupal::service('image.factory')->get($file->getFileUri());
-        if ($image->isExisting()) {
+        if ($image->isValid()) {
           $variables['width'] = $image->getWidth();
           $variables['height'] = $image->getHeight();
         }
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 e067014..6dd91cc 100644
--- a/core/modules/system/lib/Drupal/system/Plugin/ImageToolkit/GDToolkit.php
+++ b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkit/GDToolkit.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\system\Plugin\ImageToolkit;
 
+use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Image\ImageInterface;
 use Drupal\Core\ImageToolkit\ImageToolkitBase;
 use Drupal\Component\Utility\Image as ImageUtility;
@@ -29,6 +30,13 @@ class GDToolkit extends ImageToolkitBase {
   protected $resource;
 
   /**
+   * Image type represented by a PHP IMAGETYPE_* constant (e.g. IMAGETYPE_JPEG).
+   *
+   * @var int
+   */
+  protected $type;
+
+  /**
    * Sets the GD image resource.
    *
    * @param resource $resource
@@ -86,7 +94,11 @@ public function resize(ImageInterface $image, $width, $height) {
     $width = (int) round($width);
     $height = (int) round($height);
 
-    $res = $this->createTmp($image->getType(), $width, $height);
+    if ($width <= 0 || $height <= 0) {
+      return FALSE;
+    }
+
+    $res = $this->createTmp($this->getType(), $width, $height);
 
     if (!imagecopyresampled($res, $this->getResource(), 0, 0, 0, 0, $width, $height, $this->getWidth($image), $this->getHeight($image))) {
       return FALSE;
@@ -129,7 +141,7 @@ public function rotate(ImageInterface $image, $degrees, $background = NULL) {
 
     // 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->getType() == IMAGETYPE_GIF) {
+    if ($this->getType() == IMAGETYPE_GIF) {
       $transparent_index = imagecolortransparent($this->getResource());
       if ($transparent_index != 0) {
         $transparent_gif_color = imagecolorsforindex($this->getResource(), $transparent_index);
@@ -159,7 +171,11 @@ public function crop(ImageInterface $image, $x, $y, $width, $height) {
     $width = (int) round($width);
     $height = (int) round($height);
 
-    $res = $this->createTmp($image->getType(), $width, $height);
+    if ($width <= 0 || $height <= 0) {
+      return FALSE;
+    }
+
+    $res = $this->createTmp($this->getType(), $width, $height);
 
     if (!imagecopyresampled($res, $this->getResource(), 0, 0, $x, $y, $width, $height, $width, $height)) {
       return FALSE;
@@ -221,31 +237,28 @@ public function scaleAndCrop(ImageInterface $image, $width, $height) {
   }
 
   /**
-   * Creates a resource from a file.
+   * Loads a GD resource from a file.
    *
    * @param string $source
    *   String specifying the path of the image file.
-   * @param array $details
-   *   An array of image details.
    *
    * @return bool
    *   TRUE or FALSE, based on success.
    */
-  protected function load($source, array $details) {
-    $function = 'imagecreatefrom' . image_type_to_extension($details['type'], FALSE);
+  protected function load($source) {
+    $function = 'imagecreatefrom' . image_type_to_extension($this->getType(), FALSE);
     if (function_exists($function) && $resource = $function($source)) {
       $this->setResource($resource);
       if (!imageistruecolor($resource)) {
         // Convert indexed images to true color, so that filters work
         // correctly and don't result in unnecessary dither.
-        $new_image = $this->createTmp($details['type'], imagesx($resource), imagesy($resource));
+        $new_image = $this->createTmp($this->getType(), imagesx($resource), imagesy($resource));
         imagecopy($new_image, $resource, 0, 0, 0, 0, imagesx($resource), imagesy($resource));
         imagedestroy($resource);
         $this->setResource($new_image);
       }
       return (bool) $this->getResource();
     }
-
     return FALSE;
   }
 
@@ -266,16 +279,16 @@ public function save(ImageInterface $image, $destination) {
       $destination = drupal_realpath($destination);
     }
 
-    $function = 'image' . image_type_to_extension($image->getType(), FALSE);
+    $function = 'image' . image_type_to_extension($this->getType(), FALSE);
     if (!function_exists($function)) {
       return FALSE;
     }
-    if ($image->getType() == IMAGETYPE_JPEG) {
+    if ($this->getType() == IMAGETYPE_JPEG) {
       $success = $function($this->getResource(), $destination, \Drupal::config('system.image.gd')->get('jpeg_quality'));
     }
     else {
       // Always save PNG images with full transparency.
-      if ($image->getType() == IMAGETYPE_PNG) {
+      if ($this->getType() == IMAGETYPE_PNG) {
         imagealphablending($this->getResource(), FALSE);
         imagesavealpha($this->getResource(), TRUE);
       }
@@ -291,15 +304,14 @@ public function save(ImageInterface $image, $destination) {
   /**
    * {@inheritdoc}
    */
-  public function getInfo(ImageInterface $image) {
-    $details = array();
-    $data = getimagesize($image->getSource());
-
-    if (isset($data) && is_array($data) && in_array($data[2], static::supportedTypes())) {
-      $details['type'] = $data[2];
-      $this->load($image->getSource(), $details);
+  public function parseFile(ImageInterface $image, $source) {
+    $data = getimagesize($source);
+    if ($data && is_array($data) && in_array($data[2], static::supportedTypes())) {
+      $this->setType($data[2]);
+      $this->load($source, $this->getType());
+      return (bool) $this->getResource();
     }
-    return $details;
+    return FALSE;
   }
 
   /**
@@ -362,6 +374,40 @@ public function getHeight(ImageInterface $image) {
   }
 
   /**
+   * Gets the PHP type of the image.
+   *
+   * @return int
+   *   The image type represented by a PHP IMAGETYPE_* constant (e.g.
+   *   IMAGETYPE_JPEG).
+   */
+  public function getType() {
+    return $this->type;
+  }
+
+  /**
+   * Sets the PHP type of the image.
+   *
+   * @param int $type
+   *   The image type represented by a PHP IMAGETYPE_* constant (e.g.
+   *   IMAGETYPE_JPEG).
+   *
+   * @return this
+   */
+  public function setType($type) {
+    if (in_array($type, static::supportedTypes())) {
+      $this->type = $type;
+    }
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMimeType(ImageInterface $image) {
+    return $this->getType() ? image_type_to_mime_type($this->getType()) : '';
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function getRequirements() {
@@ -393,7 +439,22 @@ public static function isAvailable() {
   /**
    * {@inheritdoc}
    */
-  public static function supportedTypes() {
+  public static function getSupportedExtensions() {
+    $extensions = array();
+    foreach (static::supportedTypes() as $image_type) {
+      $extensions[] = Unicode::strtolower(image_type_to_extension($image_type, FALSE));
+    }
+    return $extensions;
+  }
+
+  /**
+   * Returns a list of image types supported by the toolkit.
+   *
+   * @return array
+   *   An array of available image types. An image type is represented by a PHP
+   *   IMAGETYPE_* constant (e.g. IMAGETYPE_JPEG, IMAGETYPE_PNG, etc.).
+   */
+  protected static function supportedTypes() {
     return array(IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_GIF);
   }
 }
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 4c9a668..c26a750 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitGdTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitGdTest.php
@@ -247,7 +247,7 @@ function testManipulations() {
         $image_truecolor = imageistruecolor($toolkit->getResource());
         $this->assertTrue($image_truecolor, String::format('Image %file after load is a truecolor image.', array('%file' => $file)));
 
-        if ($image->getType() == IMAGETYPE_GIF) {
+        if ($image->getToolkit()->getType() == IMAGETYPE_GIF) {
           if ($op == 'desaturate') {
             // Transparent GIFs and the imagefilter function don't work together.
             $values['corners'][3][3] = 0;
@@ -274,13 +274,13 @@ function testManipulations() {
 
         $directory = $this->public_files_directory .'/imagetest';
         file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
-        $image->save($directory . '/' . $op . image_type_to_extension($image->getType()));
+        $image->save($directory . '/' . $op . image_type_to_extension($image->getToolkit()->getType()));
 
         $this->assertTrue($correct_dimensions_real, String::format('Image %file after %action action has proper dimensions.', array('%file' => $file, '%action' => $op)));
         $this->assertTrue($correct_dimensions_object, String::format('Image %file object after %action action is reporting the proper height and width values.', array('%file' => $file, '%action' => $op)));
 
         // JPEG colors will always be messed up due to compression.
-        if ($image->getType() != IMAGETYPE_JPEG) {
+        if ($image->getToolkit()->getType() != IMAGETYPE_JPEG) {
           // Now check each of the corners to ensure color correctness.
           foreach ($values['corners'] as $key => $corner) {
             // Get the location of the corner.
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 34376ba..dc60eca 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTest.php
@@ -38,7 +38,7 @@ function testLoad() {
     $image = $this->getImage();
     $this->assertTrue(is_object($image), 'Returned an object.');
     $this->assertEqual($image->getToolkitId(), 'test', 'Image had toolkit set.');
-    $this->assertToolkitOperationsCalled(array('load', 'get_info'));
+    $this->assertToolkitOperationsCalled(array('parseFile'));
   }
 
   /**
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 846e6e5..c8b04e1 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTestBase.php
@@ -68,7 +68,7 @@ function setUp() {
    */
   protected function getImage() {
     $image = $this->imageFactory->get($this->file, 'test');
-    $this->assertTrue($image->isExisting(), 'Image was loaded.');
+    $this->assertTrue($image->isValid(), 'Image was loaded.');
     return $image;
   }
 
@@ -109,7 +109,7 @@ function assertToolkitOperationsCalled(array $expected) {
   function imageTestReset() {
     // Keep track of calls to these operations
     $results = array(
-      'load' => array(),
+      'parseFile' => array(),
       'save' => array(),
       'settings' => array(),
       'resize' => array(),
@@ -124,9 +124,9 @@ function imageTestReset() {
    * Gets an array of calls to the test toolkit.
    *
    * @return array
-   *   An array keyed by operation name ('load', 'save', 'settings', 'resize',
-   *   'rotate', 'crop', 'desaturate') with values being arrays of parameters
-   *   passed to each call.
+   *   An array keyed by operation name ('parseFile', 'save', 'settings',
+   *   'resize', 'rotate', 'crop', 'desaturate') with values being arrays of
+   *   parameters passed to each call.
    */
   function imageTestGetAllCalls() {
     return \Drupal::state()->get('image_test.results') ?: array();
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 11fa771..74e08b0 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
@@ -7,6 +7,7 @@
 
 namespace Drupal\image_test\Plugin\ImageToolkit;
 
+use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Image\ImageInterface;
 use Drupal\Core\ImageToolkit\ImageToolkitBase;
 
@@ -21,6 +22,13 @@
 class TestToolkit extends ImageToolkitBase {
 
   /**
+   * Image type represented by a PHP IMAGETYPE_* constant (e.g. IMAGETYPE_JPEG).
+   *
+   * @var int
+   */
+  protected $type;
+
+  /**
    * The width of the image.
    *
    * @var int
@@ -62,35 +70,16 @@ public function settingsFormSubmit($form, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function getInfo(ImageInterface $image) {
-    $this->logCall('get_info', array($image));
-
-    $details = array();
-    $data = getimagesize($image->getSource());
-
-    if (isset($data) && is_array($data) && in_array($data[2], static::supportedTypes())) {
-      $details['type'] = $data[2];
+  public function parseFile(ImageInterface $image, $source) {
+    $this->logCall('parseFile', array($image));
+    $data = getimagesize($source);
+    if ($data && is_array($data) && in_array($data[2], static::supportedTypes())) {
+      $this->setType($data[2]);
       $this->width = $data[0];
       $this->height = $data[1];
-      $this->load($image->getSource(), $details);
+      return TRUE;
     }
-    return $details;
-  }
-
-  /**
-   * Mimick loading the image from a file.
-   *
-   * @param string $source
-   *   String specifying the path of the image file.
-   * @param array $details
-   *   An array of image details.
-   *
-   * @return bool
-   *   TRUE or FALSE, based on success.
-   */
-  protected function load($source, array $details) {
-    $this->logCall('load', array($source, $details));
-    return TRUE;
+    return FALSE;
   }
 
   /**
@@ -155,8 +144,8 @@ public function scaleAndCrop(ImageInterface $image, $width, $height) {
    * Stores the values passed to a toolkit call.
    *
    * @param string $op
-   *   One of the image toolkit operations: 'get_info', 'load', 'save',
-   *   'settings', 'resize', 'rotate', 'crop', 'desaturate'.
+   *   One of the image toolkit operations: 'parseFile', 'save', 'settings',
+   *   'resize', 'rotate', 'crop', 'desaturate'.
    * @param array $args
    *   Values passed to hook.
    *
@@ -184,6 +173,40 @@ public function getHeight(ImageInterface $image) {
   }
 
   /**
+   * Returns the type of the image.
+   *
+   * @return int
+   *   The image type represented by a PHP IMAGETYPE_* constant (e.g.
+   *   IMAGETYPE_JPEG).
+   */
+  public function getType() {
+    return $this->type;
+  }
+
+  /**
+   * Sets the PHP type of the image.
+   *
+   * @param int $type
+   *   The image type represented by a PHP IMAGETYPE_* constant (e.g.
+   *   IMAGETYPE_JPEG).
+   *
+   * @return this
+   */
+  public function setType($type) {
+    if (in_array($type, static::supportedTypes())) {
+      $this->type = $type;
+    }
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMimeType(ImageInterface $image) {
+    return $this->getType() ? image_type_to_mime_type($this->getType()) : '';
+  }
+
+  /**
    * {@inheritdoc}
    */
   public static function isAvailable() {
@@ -193,7 +216,22 @@ public static function isAvailable() {
   /**
    * {@inheritdoc}
    */
-  public static function supportedTypes() {
+  public static function getSupportedExtensions() {
+    $extensions = array();
+    foreach (static::supportedTypes() as $image_type) {
+      $extensions[] = Unicode::strtolower(image_type_to_extension($image_type, FALSE));
+    }
+    return $extensions;
+  }
+
+  /**
+   * Returns a list of image types supported by the toolkit.
+   *
+   * @return array
+   *   An array of available image types. An image type is represented by a PHP
+   *   IMAGETYPE_* constant (e.g. IMAGETYPE_JPEG, IMAGETYPE_PNG, etc.).
+   */
+  protected static function supportedTypes() {
     return array(IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_GIF);
   }
 
diff --git a/core/tests/Drupal/Tests/Core/Image/ImageTest.php b/core/tests/Drupal/Tests/Core/Image/ImageTest.php
index ea3fc1d..e2542ed 100644
--- a/core/tests/Drupal/Tests/Core/Image/ImageTest.php
+++ b/core/tests/Drupal/Tests/Core/Image/ImageTest.php
@@ -88,10 +88,10 @@ public function testGetFileSize() {
   }
 
   /**
-   * Tests \Drupal\Core\Image\Image::getType().
+   * Tests \Drupal\Core\Image\Image::getToolkit()->getType().
    */
   public function testGetType() {
-    $this->assertEquals($this->image->getType(), IMAGETYPE_PNG);
+    $this->assertEquals($this->image->getToolkit()->getType(), IMAGETYPE_PNG);
   }
 
   /**
@@ -102,23 +102,14 @@ public function testGetMimeType() {
   }
 
   /**
-   * Tests \Drupal\Core\Image\Image::isExisting().
+   * Tests \Drupal\Core\Image\Image::isValid().
    */
-  public function testIsExisting() {
-    $this->assertTrue($this->image->isExisting());
+  public function testIsValid() {
+    $this->assertTrue($this->image->isValid());
     $this->assertTrue(is_readable($this->image->getSource()));
   }
 
   /**
-   * Tests \Drupal\Core\Image\Image::setSource().
-   */
-  public function testSetSource() {
-    $source = __DIR__ . '/../../../../../misc/grippie.png';
-    $this->image->setSource($source);
-    $this->assertEquals($this->image->getSource(), $source);
-  }
-
-  /**
    * Tests \Drupal\Core\Image\Image::getToolkitId().
    */
   public function testGetToolkitId() {
@@ -172,13 +163,14 @@ public function testChmodFails() {
   }
 
   /**
-   * Tests \Drupal\Core\Image\Image::processInfo().
+   * Tests \Drupal\Core\Image\Image::parseFile().
    */
-  public function testProcessInfoFails() {
+  public function testParseFileFails() {
     $toolkit = $this->getToolkitMock();
     $image = new Image($toolkit, 'magic-foobars.png');
 
-    $this->assertFalse($image->isExisting());
+    $this->assertFalse($image->isValid());
+    $this->assertFalse($image->save());
   }
 
   /**
