diff --git a/core/lib/Drupal/Core/Image/Image.php b/core/lib/Drupal/Core/Image/Image.php
index 8c8aea2..fafb395 100644
--- a/core/lib/Drupal/Core/Image/Image.php
+++ b/core/lib/Drupal/Core/Image/Image.php
@@ -41,13 +41,6 @@ class Image implements ImageInterface {
   protected $fileSize;
 
   /**
-   * If this image object is valid.
-   *
-   * @var bool
-   */
-  protected $valid = FALSE;
-
-  /**
    * Constructs a new Image object.
    *
    * @param \Drupal\Core\ImageToolkit\ImageToolkitInterface $toolkit
@@ -69,7 +62,7 @@ public function __construct(ImageToolkitInterface $toolkit, $source = NULL) {
    * {@inheritdoc}
    */
   public function isValid() {
-    return $this->valid;
+    return $this->getToolkit()->isValid();
   }
 
   /**
@@ -157,10 +150,10 @@ public function save($destination = NULL) {
    *   image information is populated.
    */
   protected function parseFile() {
-    if ($this->valid = $this->getToolkit()->parseFile()) {
+    if ($this->getToolkit()->parseFile()) {
       $this->fileSize = filesize($this->source);
     }
-    return $this->valid;
+    return $this->isValid();
   }
 
   /**
diff --git a/core/lib/Drupal/Core/ImageToolkit/ImageToolkitInterface.php b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitInterface.php
index b50331a..a4a1f6f 100644
--- a/core/lib/Drupal/Core/ImageToolkit/ImageToolkitInterface.php
+++ b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitInterface.php
@@ -80,6 +80,15 @@ public function setImage(ImageInterface $image);
   public function getImage();
 
   /**
+   * Checks if the image is valid.
+   *
+   * @return bool
+   *   TRUE if the image toolkit is currently handling a valid image, FALSE
+   *   otherwise.
+   */
+  public function isValid();
+
+  /**
    * Writes an image resource to a destination file.
    *
    * @param string $destination
diff --git a/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php b/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php
index 1fd0c77..b88a220 100644
--- a/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php
+++ b/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php
@@ -36,6 +36,13 @@ class GDToolkit extends ImageToolkitBase {
   protected $type;
 
   /**
+   * Image information from a file, available prior to loading the GD resource.
+   *
+   * @var array
+   */
+  protected $preLoadInfo;
+
+  /**
    * Sets the GD image resource.
    *
    * @param resource $resource
@@ -44,6 +51,9 @@ class GDToolkit extends ImageToolkitBase {
    * @return $this
    */
   public function setResource($resource) {
+    if (isset($this->preLoadInfo)) {
+      unset($this->preLoadInfo);
+    }
     $this->resource = $resource;
     return $this;
   }
@@ -51,10 +61,13 @@ public function setResource($resource) {
   /**
    * Retrieves the GD image resource.
    *
-   * @return resource
-   *   The GD image resource.
+   * @return resource|null
+   *   The GD image resource, or NULL if not available.
    */
   public function getResource() {
+    if (!isset($this->resource)) {
+      $this->load();
+    }
     return $this->resource;
   }
 
@@ -90,18 +103,28 @@ public function settingsFormSubmit($form, FormStateInterface $form_state) {
    *   TRUE or FALSE, based on success.
    */
   protected function load() {
+    // Return immediately if the image file is not valid.
+    if (!$this->isValid()) {
+      return FALSE;
+    }
+
     $function = 'imagecreatefrom' . image_type_to_extension($this->getType(), FALSE);
     if (function_exists($function) && $resource = $function($this->getImage()->getSource())) {
-      $this->setResource($resource);
-      if (!imageistruecolor($resource)) {
+      if (imageistruecolor($resource)) {
+        $this->setResource($resource);
+        return TRUE;
+      }
+      else {
         // Convert indexed images to true color, so that filters work
         // correctly and don't result in unnecessary dither.
         $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);
+        if ($ret = (bool) $new_image) {
+          imagecopy($new_image, $resource, 0, 0, 0, 0, imagesx($resource), imagesy($resource));
+          imagedestroy($resource);
+          $this->setResource($new_image);
+        }
+        return $ret;
       }
-      return (bool) $this->getResource();
     }
     return FALSE;
   }
@@ -109,6 +132,13 @@ protected function load() {
   /**
    * {@inheritdoc}
    */
+  public function isValid() {
+    return isset($this->preLoadInfo) || isset($this->resource);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function save($destination) {
     $scheme = file_uri_scheme($destination);
     // Work around lack of stream wrapper support in imagejpeg() and imagepng().
@@ -152,8 +182,8 @@ public function parseFile() {
     $data = @getimagesize($this->getImage()->getSource());
     if ($data && in_array($data[2], static::supportedTypes())) {
       $this->setType($data[2]);
-      $this->load();
-      return (bool) $this->getResource();
+      $this->preLoadInfo = $data;
+      return TRUE;
     }
     return FALSE;
   }
@@ -216,14 +246,30 @@ public function createTmp($type, $width, $height) {
    * {@inheritdoc}
    */
   public function getWidth() {
-    return $this->getResource() ? imagesx($this->getResource()) : NULL;
+    if (isset($this->preLoadInfo)) {
+      return $this->preLoadInfo[0];
+    }
+    elseif ($res = $this->getResource()) {
+      return imagesx($res);
+    }
+    else {
+      return NULL;
+    }
   }
 
   /**
    * {@inheritdoc}
    */
   public function getHeight() {
-    return $this->getResource() ? imagesy($this->getResource()) : NULL;
+    if (isset($this->preLoadInfo)) {
+      return $this->preLoadInfo[1];
+    }
+    elseif ($res = $this->getResource()) {
+      return imagesy($res);
+    }
+    else {
+      return NULL;
+    }
   }
 
   /**
diff --git a/core/modules/system/src/Tests/Image/ToolkitTestBase.php b/core/modules/system/src/Tests/Image/ToolkitTestBase.php
index 91e9901..a04dbb3 100644
--- a/core/modules/system/src/Tests/Image/ToolkitTestBase.php
+++ b/core/modules/system/src/Tests/Image/ToolkitTestBase.php
@@ -68,7 +68,7 @@ protected function setUp() {
    */
   protected function getImage() {
     $image = $this->imageFactory->get($this->file, 'test');
-    $this->assertTrue($image->isValid(), 'Image was loaded.');
+    $this->assertTrue($image->isValid(), 'Image file was parsed.');
     return $image;
   }
 
diff --git a/core/modules/system/tests/modules/image_test/src/Plugin/ImageToolkit/TestToolkit.php b/core/modules/system/tests/modules/image_test/src/Plugin/ImageToolkit/TestToolkit.php
index 3c1ceec..509ec9c 100644
--- a/core/modules/system/tests/modules/image_test/src/Plugin/ImageToolkit/TestToolkit.php
+++ b/core/modules/system/tests/modules/image_test/src/Plugin/ImageToolkit/TestToolkit.php
@@ -70,6 +70,13 @@ public function settingsFormSubmit($form, FormStateInterface $form_state) {
   /**
    * {@inheritdoc}
    */
+  public function isValid() {
+    return isset($this->type);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function parseFile() {
     $this->logCall('parseFile', func_get_args());
     $data = @getimagesize($this->getImage()->getSource());
diff --git a/core/tests/Drupal/Tests/Core/Image/ImageTest.php b/core/tests/Drupal/Tests/Core/Image/ImageTest.php
index b8db186..fa91f28 100644
--- a/core/tests/Drupal/Tests/Core/Image/ImageTest.php
+++ b/core/tests/Drupal/Tests/Core/Image/ImageTest.php
@@ -64,7 +64,7 @@ protected function setUp() {
    */
   protected function getToolkitMock(array $stubs = array()) {
     $mock_builder = $this->getMockBuilder('Drupal\system\Plugin\ImageToolkit\GDToolkit');
-    $stubs += array('getPluginId', 'save');
+    $stubs = array_merge(array('getPluginId', 'save'), $stubs);
     return $mock_builder
       ->disableOriginalConstructor()
       ->setMethods($stubs)
@@ -93,19 +93,31 @@ protected function getToolkitOperationMock($class_name, ImageToolkitInterface $t
   /**
    * Get an image with a mocked toolkit, for testing.
    *
+   * @param bool $load_expected
+   *   (optional) Whether the load() method is expected to be called. Defaults
+   *   to TRUE.
    * @param array $stubs
    *   (optional) Array containing toolkit methods to be replaced with stubs.
    *
    * @return \Drupal\Core\Image\Image
    *   An image object.
    */
-  protected function getTestImage(array $stubs = array()) {
+  protected function getTestImage($load_expected = TRUE, array $stubs = array()) {
+    if (!$load_expected && !in_array('load', $stubs)) {
+      $stubs = array_merge(array('load'), $stubs);
+    }
+
     $this->toolkit = $this->getToolkitMock($stubs);
 
     $this->toolkit->expects($this->any())
       ->method('getPluginId')
       ->will($this->returnValue('gd'));
 
+    if (!$load_expected) {
+      $this->toolkit->expects($this->never())
+        ->method('load');
+    }
+
     $this->image = new Image($this->toolkit, $this->source);
   }
 
@@ -119,7 +131,7 @@ protected function getTestImage(array $stubs = array()) {
    *   An image object.
    */
   protected function getTestImageForOperation($class_name) {
-    $this->toolkit = $this->getToolkitMock(array('getToolkitOperation', 'getPluginId'));
+    $this->toolkit = $this->getToolkitMock(array('getToolkitOperation'));
     $this->toolkitOperation = $this->getToolkitOperationMock($class_name, $this->toolkit);
 
     $this->toolkit->expects($this->any())
@@ -137,7 +149,7 @@ protected function getTestImageForOperation($class_name) {
    * Tests \Drupal\Core\Image\Image::getHeight().
    */
   public function testGetHeight() {
-    $this->getTestImage();
+    $this->getTestImage(FALSE);
     $this->assertEquals(100, $this->image->getHeight());
   }
 
@@ -145,7 +157,7 @@ public function testGetHeight() {
    * Tests \Drupal\Core\Image\Image::getWidth().
    */
   public function testGetWidth() {
-    $this->getTestImage();
+    $this->getTestImage(FALSE);
     $this->assertEquals(88, $this->image->getWidth());
   }
 
@@ -153,7 +165,7 @@ public function testGetWidth() {
    * Tests \Drupal\Core\Image\Image::getFileSize
    */
   public function testGetFileSize() {
-    $this->getTestImage();
+    $this->getTestImage(FALSE);
     $this->assertEquals(3905, $this->image->getFileSize());
   }
 
@@ -161,7 +173,7 @@ public function testGetFileSize() {
    * Tests \Drupal\Core\Image\Image::getToolkit()->getType().
    */
   public function testGetType() {
-    $this->getTestImage();
+    $this->getTestImage(FALSE);
     $this->assertEquals(IMAGETYPE_PNG, $this->image->getToolkit()->getType());
   }
 
@@ -169,7 +181,7 @@ public function testGetType() {
    * Tests \Drupal\Core\Image\Image::getMimeType().
    */
   public function testGetMimeType() {
-    $this->getTestImage();
+    $this->getTestImage(FALSE);
     $this->assertEquals('image/png', $this->image->getMimeType());
   }
 
@@ -177,7 +189,7 @@ public function testGetMimeType() {
    * Tests \Drupal\Core\Image\Image::isValid().
    */
   public function testIsValid() {
-    $this->getTestImage();
+    $this->getTestImage(FALSE);
     $this->assertTrue($this->image->isValid());
     $this->assertTrue(is_readable($this->image->getSource()));
   }
@@ -186,7 +198,7 @@ public function testIsValid() {
    * Tests \Drupal\Core\Image\Image::getToolkitId().
    */
   public function testGetToolkitId() {
-    $this->getTestImage();
+    $this->getTestImage(FALSE);
     $this->assertEquals('gd', $this->image->getToolkitId());
   }
 
