diff --git a/core/modules/picture/lib/Drupal/picture/Entity/PictureMapping.php b/core/modules/picture/lib/Drupal/picture/Entity/PictureMapping.php
index 9c11628..cd1a470 100644
--- a/core/modules/picture/lib/Drupal/picture/Entity/PictureMapping.php
+++ b/core/modules/picture/lib/Drupal/picture/Entity/PictureMapping.php
@@ -176,4 +176,34 @@ public function hasMappings() {
     }
     return $mapping_found;
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMappings() {
+    $mappings = array();
+    foreach ($this->mappings as $breakpoint_name => $multipliers) {
+      // Make sure there are multipliers.
+      if (!empty($multipliers)) {
+        // Make sure that the breakpoint exists and is enabled.
+        // @todo add the following when breakpoint->status is added again:
+        // $picture_mapping->breakpointGroup->breakpoints[$breakpoint_name]->status
+        $breakpoint = $this->breakpointGroup->getBreakpointById($breakpoint_name);
+        if ($breakpoint) {
+          // Determine the enabled multipliers.
+          $multipliers = array_intersect_key($multipliers, $breakpoint->multipliers);
+          foreach ($multipliers as $multiplier => $image_style) {
+            // Make sure the multiplier still exists.
+            if (!empty($image_style)) {
+              if (!isset($mappings[$breakpoint_name])) {
+                $mappings[$breakpoint_name] = array();
+              }
+              $mappings[$breakpoint_name][$multiplier] = $image_style;
+            }
+          }
+        }
+      }
+    }
+    return $mappings;
+  }
 }
diff --git a/core/modules/picture/lib/Drupal/picture/PictureMappingInterface.php b/core/modules/picture/lib/Drupal/picture/PictureMappingInterface.php
index ca03918..70a2261 100644
--- a/core/modules/picture/lib/Drupal/picture/PictureMappingInterface.php
+++ b/core/modules/picture/lib/Drupal/picture/PictureMappingInterface.php
@@ -19,4 +19,9 @@
    */
   public function hasMappings();
 
+  /**
+   * Gets the breakpoints to image styles mappings.
+   */
+  public function getMappings();
+
 }
diff --git a/core/modules/picture/lib/Drupal/picture/Plugin/Field/FieldFormatter/PictureFormatter.php b/core/modules/picture/lib/Drupal/picture/Plugin/Field/FieldFormatter/PictureFormatter.php
index eb1864d..b7ea67e 100644
--- a/core/modules/picture/lib/Drupal/picture/Plugin/Field/FieldFormatter/PictureFormatter.php
+++ b/core/modules/picture/lib/Drupal/picture/Plugin/Field/FieldFormatter/PictureFormatter.php
@@ -124,39 +124,8 @@ public function viewElements(FieldItemListInterface $items) {
       $link_file = TRUE;
     }
 
-    $breakpoint_styles = array();
     $fallback_image_style = '';
 
-    $picture_mapping = entity_load('picture_mapping', $this->getSetting('picture_mapping'));
-    if ($picture_mapping) {
-      foreach ($picture_mapping->mappings as $breakpoint_name => $multipliers) {
-        // Make sure there are multipliers.
-        if (!empty($multipliers)) {
-          // Make sure that the breakpoint exists and is enabled.
-          // @todo add the following when breakpoint->status is added again:
-          // $picture_mapping->breakpointGroup->breakpoints[$breakpoint_name]->status
-          $breakpoint = $picture_mapping->breakpointGroup->getBreakpointById($breakpoint_name);
-          if ($breakpoint) {
-            // Determine the enabled multipliers.
-            $multipliers = array_intersect_key($multipliers, $breakpoint->multipliers);
-            foreach ($multipliers as $multiplier => $image_style) {
-              // Make sure the multiplier still exists.
-              if (!empty($image_style)) {
-                // First mapping found is used as fallback.
-                if (empty($fallback_image_style)) {
-                  $fallback_image_style = $image_style;
-                }
-                if (!isset($breakpoint_styles[$breakpoint_name])) {
-                  $breakpoint_styles[$breakpoint_name] = array();
-                }
-                $breakpoint_styles[$breakpoint_name][$multiplier] = $image_style;
-              }
-            }
-          }
-        }
-      }
-    }
-
     // Check if the user defined a custom fallback image style.
     if ($this->getSetting('fallback_image_style')) {
       $fallback_image_style = $this->getSetting('fallback_image_style');
@@ -170,17 +139,35 @@ public function viewElements(FieldItemListInterface $items) {
         );
       }
       $elements[$delta] = array(
-        '#theme' => 'picture_formatter',
-        '#attached' => array('library' => array(
-          array('picture', 'picturefill'),
-        )),
-        '#item' => $item,
-        '#image_style' => $fallback_image_style,
-        '#breakpoints' => $breakpoint_styles,
-        '#path' => isset($uri) ? $uri : '',
+        '#type' => 'picture',
+        '#fallback_image_style' => $fallback_image_style,
+        '#mapping_id' => $this->getSetting('picture_mapping'),
+        '#link_path' => isset($uri) ? $uri : '',
       );
+      $item_value = $item->getValue(TRUE);
+      if (isset($item_value['uri'])) {
+        $elements[$delta]['#uri'] = $item_value['uri'];
+      }
+      elseif (isset($item_value['entity'])) {
+        $elements[$delta]['#uri'] = $item_value['entity']->getFileUri();
+        $elements[$delta]['#entity'] = $item_value['entity'];
+      }
+      // Get the image dimensions.
+      $image = \Drupal::service('image.factory')->get($elements[$delta]['#uri']);
+      if ($image->isSupported()) {
+        $elements[$delta]['#width'] = $image->getWidth();
+        $elements[$delta]['#height'] = $image->getHeight();
+      }
+      else {
+        $elements[$delta]['#width'] = $elements[$delta]['#height'] = NULL;
+      }
+      if (isset($item_value['alt']) && drupal_strlen($item_value['alt']) != 0) {
+        $elements[$delta]['#attributes']['alt'] = $item_value['alt'];
+      }
+      if (isset($item_value['title']) && drupal_strlen($item_value['title']) != 0) {
+        $elements[$delta]['#attributes']['title'] = $item_value['title'];
+      }
     }
-
     return $elements;
   }
 }
diff --git a/core/modules/picture/lib/Drupal/picture/Tests/PictureFieldDisplayTest.php b/core/modules/picture/lib/Drupal/picture/Tests/PictureFieldDisplayTest.php
index 7c11a6f..0efa482 100644
--- a/core/modules/picture/lib/Drupal/picture/Tests/PictureFieldDisplayTest.php
+++ b/core/modules/picture/lib/Drupal/picture/Tests/PictureFieldDisplayTest.php
@@ -136,7 +136,10 @@ public function _testPictureFieldFormatters($scheme) {
     $display_options = array(
       'type' => 'picture',
       'module' => 'picture',
-      'settings' => array('image_link' => 'file'),
+      'settings' => array(
+        'image_link' => 'file',
+        'fallback_image_style' => 'large'
+      ),
     );
     $display = entity_get_display('node', 'article', 'default');
     $display->setComponent($field_name, $display_options)
@@ -148,9 +151,9 @@ public function _testPictureFieldFormatters($scheme) {
       '#width' => 40,
       '#height' => 20,
     );
-    $default_output = l($image, file_create_url($image_uri), array('html' => TRUE));
+    //$default_output = l($image, file_create_url($image_uri), array('html' => TRUE));
     $this->drupalGet('node/' . $nid);
-    $this->assertRaw($default_output, 'Image linked to file formatter displaying correctly on full node view.');
+    $this->assertRaw('<a href="' . file_create_url($image_uri) . '"><picture', 'Image linked to file formatter displaying correctly on full node view.');
     // Verify that the image can be downloaded.
     $this->assertEqual(file_get_contents($test_image->uri), $this->drupalGet(file_create_url($image_uri)), 'File was downloaded successfully.');
     if ($scheme == 'private') {
diff --git a/core/modules/picture/picture.module b/core/modules/picture/picture.module
index ae676c9..b9ff700 100644
--- a/core/modules/picture/picture.module
+++ b/core/modules/picture/picture.module
@@ -85,6 +85,22 @@ function picture_menu_link_defaults() {
 }
 
 /**
+ * Implements hook_element_info().
+ */
+function picture_element_info() {
+  $types = array();
+  $types['picture'] = array(
+    '#theme' => 'picture',
+    '#attached' => array(
+      'library' => array(
+        array('picture', 'picturefill'),
+      )
+    ),
+  );
+  return $types;
+}
+
+/**
  * Load one picture by its identifier.
  *
  * @param int $id
@@ -109,22 +125,13 @@ function picture_theme() {
   return array(
     'picture' => array(
       'variables' => array(
-        'style_name' => NULL,
+        'mapping_id' => NULL,
+        'link_path' => array(),
         'uri' => NULL,
+        'attributes' => array(),
+        'fallback_image_style' => NULL,
         'width' => NULL,
         'height' => NULL,
-        'alt' => '',
-        'title' => NULL,
-        'attributes' => array(),
-        'breakpoints' => array(),
-      ),
-    ),
-    'picture_formatter' => array(
-      'variables' => array(
-        'item' => NULL,
-        'path' => NULL,
-        'image_style' => NULL,
-        'breakpoints' => array(),
       ),
     ),
     'picture_source' => array(
@@ -139,69 +146,17 @@ function picture_theme() {
 }
 
 /**
- * Returns HTML for a picture field formatter.
- *
- * @param array $variables
- *   An associative array containing:
- *   - item: An ImageItem object.
- *   - image_style: An optional image style.
- *   - path: An optional array containing the link 'path' and link 'options'.
- *   - breakpoints: An array containing breakpoints.
- *
- * @ingroup themeable
- */
-function theme_picture_formatter($variables) {
-  $item = $variables['item'];
-  if (!isset($variables['breakpoints']) || empty($variables['breakpoints'])) {
-    $image_formatter = array(
-      '#theme' => 'image_formatter',
-      '#item' => $item,
-      '#image_style' => $variables['image_style'],
-      '#path' => $variables['path'],
-    );
-    return drupal_render($image_formatter);
-  }
-
-  $picture = array(
-    '#theme' => 'picture',
-    '#width' => $item->width,
-    '#height' => $item->height,
-    '#style_name' => $variables['image_style'],
-    '#breakpoints' => $variables['breakpoints'],
-  );
-  if (isset($item->uri)) {
-    $picture['#uri'] = $item->uri;
-  }
-  elseif ($entity = $item->entity) {
-    $picture['#uri'] = $entity->getFileUri();
-    $picture['#entity'] = $entity;
-  }
-  $picture['#alt'] = $item->alt;
-  if (drupal_strlen($item->title) != 0) {
-    $picture['#title'] = $item->title;
-  }
-  // @todo Add support for route names.
-  if (isset($variables['path']['path'])) {
-    $path = $variables['path']['path'];
-    $options = isset($variables['path']['options']) ? $variables['path']['options'] : array();
-    $options['html'] = TRUE;
-    return l($picture, $path, $options);
-  }
-
-  return drupal_render($picture);
-}
-
-/**
  * Returns HTML for a picture.
  *
  * @param $variables
  *   An associative array containing:
- *   - uri: Either the path of the image file (relative to base_path()) or a
- *     full URL.
+ *   - uri: The uri of the image.
  *   - width: The width of the image (if known).
  *   - height: The height of the image (if known).
- *   - alt: The alternative text for text-based browsers.
- *   - breakpoints: An array containing breakpoints.
+ *   - attributes: An array of HTML attributes (optional).
+ *   - mapping_id: The entity ID of the picture mapping.
+ *   - fallback_image_style: The name of the image style to use as fallback.
+ *   - link_path: The path to link the image to (optional).
  *
  * @ingroup themeable
  */
@@ -221,55 +176,62 @@ function theme_picture($variables) {
   $sources = array();
   $output = array();
 
-  // Fallback image, output as source with media query.
-  $sources[] = array(
-    'src' => entity_load('image_style', $variables['style_name'])->buildUrl($variables['uri']),
-    'dimensions' => picture_get_image_dimensions($variables),
-  );
+  $picture_mapping = entity_load('picture_mapping', $variables['mapping_id']);
+  $fallback_image_style = entity_load('image_style', $variables['fallback_image_style']);
 
   // All breakpoints and multipliers.
-  foreach ($variables['breakpoints'] as $breakpoint_name => $multipliers) {
-    $breakpoint = breakpoint_load($breakpoint_name);
-    if ($breakpoint) {
-      $new_sources = array();
-      foreach ($multipliers as $multiplier => $image_style) {
-        $new_source = $variables;
-        $new_source['style_name'] = $image_style;
-        $new_source['#multiplier'] = $multiplier;
-        $new_sources[] = $new_source;
-      }
+  if ($picture_mapping) {
+    foreach ($picture_mapping->getMappings() as $breakpoint_name => $multipliers) {
+      $breakpoint = breakpoint_load($breakpoint_name);
+      if ($breakpoint) {
+        $new_sources = array();
+        foreach ($multipliers as $multiplier => $image_style) {
+          if (!$fallback_image_style) {
+            // First image style will be the fallback if no default fallback is given.
+            $variables['fallback_image_style'] = $image_style;
+            $fallback_image_style = entity_load('image_style', $variables['fallback_image_style']);
+          }
 
-      // Only one image, use src.
-      if (count($new_sources) == 1) {
-        $sources[] = array(
-          'src' => entity_load('image_style', $new_sources[0]['style_name'])->buildUrl($new_sources[0]['uri']),
-          'dimensions' => picture_get_image_dimensions($new_sources[0]),
-          'media' => $breakpoint->mediaQuery,
-        );
-      }
-      else {
-        // Multiple images, use srcset.
-        $srcset = array();
-        foreach ($new_sources as $new_source) {
-          $srcset[] = entity_load('image_style', $new_source['style_name'])->buildUrl($new_source['uri']) . ' ' . $new_source['#multiplier'];
+          $new_source = $variables;
+          $new_source['image_style'] = $image_style;
+          $new_source['#multiplier'] = $multiplier;
+          $new_sources[] = $new_source;
+        }
+
+        // Only one image, use src.
+        if (count($new_sources) == 1) {
+          $sources[] = array(
+            'src' => entity_load('image_style', $new_sources[0]['image_style'])->buildUrl($new_sources[0]['uri']),
+            'dimensions' => picture_get_image_dimensions($new_sources[0]),
+            'media' => $breakpoint->mediaQuery,
+          );
+        }
+        else {
+          // Multiple images, use srcset.
+          $srcset = array();
+          foreach ($new_sources as $new_source) {
+            $srcset[] = entity_load('image_style', $new_source['image_style'])->buildUrl($new_source['uri']) . ' ' . $new_source['#multiplier'];
+          }
+          $sources[] = array(
+            'srcset' => implode(', ', $srcset),
+            'dimensions' => picture_get_image_dimensions($new_sources[0]),
+            'media' => $breakpoint->mediaQuery,
+          );
         }
-        $sources[] = array(
-          'srcset' => implode(', ', $srcset),
-          'dimensions' => picture_get_image_dimensions($new_sources[0]),
-          'media' => $breakpoint->mediaQuery,
-        );
       }
     }
   }
 
+  // Fallback image, output as source with media query.
+  $fallback_variables = $variables;
+  $fallback_variables['image_style'] = $variables['fallback_image_style'];
+  array_unshift($sources, array(
+    'src' => $fallback_image_style->buildUrl($variables['uri']),
+    'dimensions' => picture_get_image_dimensions($fallback_variables),
+  ));
+
   if (!empty($sources)) {
-    $attributes = array();
-    foreach (array('alt', 'title') as $key) {
-      if (isset($variables[$key])) {
-        $attributes[$key] = $variables[$key];
-      }
-    }
-    $output[] = '<picture' . new Attribute($attributes) . '>';
+    $output[] = '<picture' . new Attribute($variables['attributes']) . '>';
 
     // Add source tags to the output.
     foreach ($sources as $source) {
@@ -290,17 +252,32 @@ function theme_picture($variables) {
     // Output the fallback image.
     $image_style = array(
       '#theme' => 'image_style',
-      '#style_name' => $variables['style_name'],
+      '#style_name' => $variables['fallback_image_style'],
       '#width' => $variables['width'],
       '#height' => $variables['height'],
     );
-    foreach (array('uri', 'alt', 'title', 'attributes') as $key) {
-      if (isset($variables[$key])) {
-        $image_style["#$key"] = $variables[$key];
+    if (isset($variables['uri'])) {
+      $image_style['#uri'] = $variables['uri'];
+    }
+    if (isset($variables['attributes'])) {
+      if (isset($variables['attributes']['alt'])) {
+        $image_style['#alt'] = $variables['attributes']['alt'];
+        unset($variables['attributes']['alt']);
       }
+      if (isset($variables['attributes']['title'])) {
+        $image_style['#title'] = $variables['attributes']['title'];
+        unset($variables['attributes']['title']);
+      }
+      $image_style['#attributes'] = $variables['attributes'];
     }
     $output[] = '  <noscript>' . drupal_render($image_style) . '</noscript>';
     $output[] = '</picture>';
+    if (isset($variables['link_path']['path'])) {
+      $path = $variables['link_path']['path'];
+      $options = isset($variables['link_path']['options']) ? $variables['link_path']['options'] : array();
+      $options['html'] = TRUE;
+      return l(implode("\n", $output), $path, $options);
+    }
     return implode("\n", $output);
   }
 }
@@ -343,7 +320,7 @@ function theme_picture_source($variables) {
  *
  * @param $variables
  *   An associative array containing:
- *   - style_name: The name of the style to be used to alter the original image.
+ *   - image_style: Name of the style to be used to alter the original image.
  *   - width: The width of the source image (if known).
  *   - height: The height of the source image (if known).
  *
@@ -358,7 +335,7 @@ function picture_get_image_dimensions($variables) {
     'height' => $variables['height'],
   );
 
-  entity_load('image_style', $variables['style_name'])->transformDimensions($dimensions);
+  entity_load('image_style', $variables['image_style'])->transformDimensions($dimensions);
 
   return $dimensions;
 }
