From 81b87f93f302c9166186348e6339cec63f871fc6 Mon Sep 17 00:00:00 2001
From: Gabor Hojtsy <gabor@hojtsy.hu>
Date: Fri, 16 Jun 2017 20:11:58 +0200
Subject: [PATCH] =?UTF-8?q?Issue=20#2831937=20by=20mtodor,=20seanB,=20Wim?=
 =?UTF-8?q?=20Leers,=20phenaproxima,=20l0ke,=20webflo,=20tedbow,=20G=C3=A1?=
 =?UTF-8?q?bor=20Hojtsy,=20slashrsm,=20naveenvalecha,=20mondrake,=20oriol?=
 =?UTF-8?q?=5Fe9g,=20dawehner,=20vijaycs85:=20Add=20"Image"=20MediaSource?=
 =?UTF-8?q?=20plugin?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ...ntity_form_display.media.image.default.yml |  46 +++++
 ...ntity_view_display.media.image.default.yml |  51 ++++++
 ...ld.field.media.image.field_media_image.yml |  40 +++++
 .../field.storage.media.field_media_file.yml  |   2 +-
 .../field.storage.media.field_media_image.yml |  32 ++++
 .../media/config/install/media.type.file.yml  |   2 +-
 .../media/config/install/media.type.image.yml |  12 ++
 .../media/config/schema/media.schema.yml      |   4 +
 .../media/images/icons/no-thumbnail.png       |   4 +
 .../media/src/Plugin/media/Source/Image.php   | 160 ++++++++++++++++++
 .../media/tests/fixtures/example_1.jpeg       |  51 ++++++
 .../media/tests/fixtures/example_2.jpeg       |  51 ++++++
 .../src/Functional/MediaRevisionTest.php      |  41 +++++
 .../src/Functional/MediaUiFunctionalTest.php  |   1 +
 .../MediaSourceImageTest.php                  |  79 +++++++++
 .../MediaSourceTestBase.php                   |  14 +-
 .../MediaUiJavascriptTest.php                 |   1 +
 .../tests/src/Kernel/MediaSourceFileTest.php  |   1 +
 18 files changed, 589 insertions(+), 3 deletions(-)
 create mode 100644 core/modules/media/config/install/core.entity_form_display.media.image.default.yml
 create mode 100644 core/modules/media/config/install/core.entity_view_display.media.image.default.yml
 create mode 100644 core/modules/media/config/install/field.field.media.image.field_media_image.yml
 create mode 100644 core/modules/media/config/install/field.storage.media.field_media_image.yml
 create mode 100644 core/modules/media/config/install/media.type.image.yml
 create mode 100644 core/modules/media/images/icons/no-thumbnail.png
 create mode 100644 core/modules/media/src/Plugin/media/Source/Image.php
 create mode 100644 core/modules/media/tests/fixtures/example_1.jpeg
 create mode 100644 core/modules/media/tests/fixtures/example_2.jpeg
 create mode 100644 core/modules/media/tests/src/FunctionalJavascript/MediaSourceImageTest.php

diff --git a/core/modules/media/config/install/core.entity_form_display.media.image.default.yml b/core/modules/media/config/install/core.entity_form_display.media.image.default.yml
new file mode 100644
index 000000000000..7806770ef98f
--- /dev/null
+++ b/core/modules/media/config/install/core.entity_form_display.media.image.default.yml
@@ -0,0 +1,46 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.field.media.image.field_media_image
+    - image.style.thumbnail
+    - media.type.image
+  module:
+    - image
+id: media.image.default
+targetEntityType: media
+bundle: image
+mode: default
+content:
+  created:
+    type: datetime_timestamp
+    weight: 10
+    region: content
+    settings: {  }
+    third_party_settings: {  }
+  field_media_image:
+    settings:
+      progress_indicator: throbber
+      preview_image_style: thumbnail
+    third_party_settings: {  }
+    type: image_image
+    weight: 26
+    region: content
+  name:
+    type: string_textfield
+    weight: -5
+    region: content
+    settings:
+      size: 60
+      placeholder: ''
+    third_party_settings: {  }
+  uid:
+    type: entity_reference_autocomplete
+    weight: 5
+    settings:
+      match_operator: CONTAINS
+      size: 60
+      placeholder: ''
+    region: content
+    third_party_settings: {  }
+hidden: {  }
diff --git a/core/modules/media/config/install/core.entity_view_display.media.image.default.yml b/core/modules/media/config/install/core.entity_view_display.media.image.default.yml
new file mode 100644
index 000000000000..e541d7f784e3
--- /dev/null
+++ b/core/modules/media/config/install/core.entity_view_display.media.image.default.yml
@@ -0,0 +1,51 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.field.media.image.field_media_image
+    - image.style.thumbnail
+    - media.type.image
+  module:
+    - image
+    - user
+id: media.image.default
+targetEntityType: media
+bundle: image
+mode: default
+content:
+  created:
+    label: hidden
+    type: timestamp
+    weight: 0
+    region: content
+    settings:
+      date_format: medium
+      custom_date_format: ''
+      timezone: ''
+    third_party_settings: {  }
+  field_media_image:
+    label: above
+    settings:
+      image_style: ''
+      image_link: ''
+    third_party_settings: {  }
+    type: image
+    weight: 6
+    region: content
+  thumbnail:
+    type: image
+    weight: 5
+    label: hidden
+    settings:
+      image_style: thumbnail
+      image_link: ''
+    region: content
+    third_party_settings: {  }
+  uid:
+    label: hidden
+    type: author
+    weight: 0
+    region: content
+    settings: {  }
+    third_party_settings: {  }
+hidden: {  }
diff --git a/core/modules/media/config/install/field.field.media.image.field_media_image.yml b/core/modules/media/config/install/field.field.media.image.field_media_image.yml
new file mode 100644
index 000000000000..f6a62cc5958e
--- /dev/null
+++ b/core/modules/media/config/install/field.field.media.image.field_media_image.yml
@@ -0,0 +1,40 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.storage.media.field_media_image
+    - media.type.image
+  enforced:
+    module:
+      - media
+  module:
+    - image
+id: media.image.field_media_image
+field_name: field_media_image
+entity_type: media
+bundle: image
+label: Image
+description: ''
+required: true
+translatable: true
+default_value: {  }
+default_value_callback: ''
+settings:
+  alt_field: true
+  alt_field_required: true
+  title_field: false
+  title_field_required: false
+  max_resolution: ''
+  min_resolution: ''
+  default_image:
+    uuid: null
+    alt: ''
+    title: ''
+    width: null
+    height: null
+  file_directory: '[date:custom:Y]-[date:custom:m]'
+  file_extensions: 'png gif jpg jpeg'
+  max_filesize: ''
+  handler: 'default:file'
+  handler_settings: {  }
+field_type: image
diff --git a/core/modules/media/config/install/field.storage.media.field_media_file.yml b/core/modules/media/config/install/field.storage.media.field_media_file.yml
index c251e1166664..344abd17617d 100644
--- a/core/modules/media/config/install/field.storage.media.field_media_file.yml
+++ b/core/modules/media/config/install/field.storage.media.field_media_file.yml
@@ -20,6 +20,6 @@ module: file
 locked: true
 cardinality: 1
 translatable: true
-indexes: { }
+indexes: {  }
 persist_with_no_fields: false
 custom_storage: false
diff --git a/core/modules/media/config/install/field.storage.media.field_media_image.yml b/core/modules/media/config/install/field.storage.media.field_media_image.yml
new file mode 100644
index 000000000000..155db1173e22
--- /dev/null
+++ b/core/modules/media/config/install/field.storage.media.field_media_image.yml
@@ -0,0 +1,32 @@
+langcode: en
+status: true
+dependencies:
+  enforced:
+    module:
+      - media
+  module:
+    - file
+    - image
+    - media
+id: media.field_media_image
+field_name: field_media_image
+entity_type: media
+type: image
+settings:
+  default_image:
+    uuid: null
+    alt: ''
+    title: ''
+    width: null
+    height: null
+  target_type: file
+  display_field: false
+  display_default: false
+  uri_scheme: public
+module: image
+locked: true
+cardinality: 1
+translatable: true
+indexes: {  }
+persist_with_no_fields: false
+custom_storage: false
diff --git a/core/modules/media/config/install/media.type.file.yml b/core/modules/media/config/install/media.type.file.yml
index af0abc271684..a716fc1852af 100644
--- a/core/modules/media/config/install/media.type.file.yml
+++ b/core/modules/media/config/install/media.type.file.yml
@@ -9,4 +9,4 @@ queue_thumbnail_downloads: false
 new_revision: true
 source_configuration:
   source_field: field_media_file
-field_map: { }
+field_map: {  }
diff --git a/core/modules/media/config/install/media.type.image.yml b/core/modules/media/config/install/media.type.image.yml
new file mode 100644
index 000000000000..9527f625fc59
--- /dev/null
+++ b/core/modules/media/config/install/media.type.image.yml
@@ -0,0 +1,12 @@
+langcode: en
+status: true
+dependencies: {  }
+id: image
+label: Image
+description: "Use local images for reusable media."
+source: image
+queue_thumbnail_downloads: false
+new_revision: true
+source_configuration:
+  source_field: field_media_image
+field_map: {  }
diff --git a/core/modules/media/config/schema/media.schema.yml b/core/modules/media/config/schema/media.schema.yml
index 69740f75ee2b..dad518985a7c 100644
--- a/core/modules/media/config/schema/media.schema.yml
+++ b/core/modules/media/config/schema/media.schema.yml
@@ -48,6 +48,10 @@ media.source.file:
   type: media.source.field_aware
   label: '"File" media source configuration'
 
+media.source.image:
+  type: media.source.field_aware
+  label: '"Image" media source configuration'
+
 media.source.field_aware:
   type: mapping
   mapping:
diff --git a/core/modules/media/images/icons/no-thumbnail.png b/core/modules/media/images/icons/no-thumbnail.png
new file mode 100644
index 000000000000..496a18479e6e
--- /dev/null
+++ b/core/modules/media/images/icons/no-thumbnail.png
@@ -0,0 +1,4 @@
+‰PNG
+
+���
IHDR���´���´����¦Yî��ûIDATxíÛ‡Ã@Åñûþß pË`A
+\@R° À‚9@×£w²ÿ�˜å§^²ÛÙöãbX Aƒ
ú¬
4hРAƒ
4hРAƒ
4hРAƒ
4hРAƒ
:?ßV~u}ý<VþGô-ÞÖž^mS­Û9蘛¾Í×WßP]Ðt<4 èÈtiZ'´Ä­ñ@k@,дÄ�­=АÕ-IÕ-¹» 5 h
ˆZbÖ€x 5 h
ˆZâÖ€x 7
ˆ:&
ˆºt–€ Kº´µ: gY9õ®£,|ô]ÆÍÉàí±%Å—èýE÷½£ëýØ#غhœ—è½Jœ‡Ý£'éÏýêUÚ
&Leî%úG‹9•0@³:–¶utLvŸ´\Ú^FtmÆÙ-ßWVt¬òÒ3@ËÁt¨&èh¦W´ŒFtìIÏèØÚ%Å-C´› cÔýÜíúÂç& &/ e?_Lбè~nw`2T—ÃuvAë~‡q6AÇ*ç óóXµ;ãç÷ßüè›ÿ€
4hРAƒ
4hРAƒ
4hРAƒ
4hРAƒ
4hРp]n!Á����IEND®B`‚
\ No newline at end of file
diff --git a/core/modules/media/src/Plugin/media/Source/Image.php b/core/modules/media/src/Plugin/media/Source/Image.php
new file mode 100644
index 000000000000..46f6782c742d
--- /dev/null
+++ b/core/modules/media/src/Plugin/media/Source/Image.php
@@ -0,0 +1,160 @@
+<?php
+
+namespace Drupal\media\Plugin\media\Source;
+
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Entity\EntityFieldManagerInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Field\FieldTypePluginManagerInterface;
+use Drupal\Core\File\FileSystem;
+use Drupal\Core\Image\ImageFactory;
+use Drupal\media\MediaInterface;
+use Drupal\media\MediaTypeInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Image entity media source.
+ *
+ * @see \Drupal\Core\Image\ImageInterface
+ *
+ * @MediaSource(
+ *   id = "image",
+ *   label = @Translation("Image"),
+ *   description = @Translation("Use local images for reusable media."),
+ *   allowed_field_types = {"image"},
+ *   default_thumbnail_filename = "no-thumbnail.png"
+ * )
+ */
+class Image extends File {
+
+  /**
+   * Key for "image width" metadata attribute.
+   *
+   * @var string
+   */
+  const METADATA_ATTRIBUTE_WIDTH = 'width';
+
+  /**
+   * Key for "image height" metadata attribute.
+   *
+   * @var string
+   */
+  const METADATA_ATTRIBUTE_HEIGHT = 'height';
+
+  /**
+   * The image factory service.
+   *
+   * @var \Drupal\Core\Image\ImageFactory
+   */
+  protected $imageFactory;
+
+  /**
+   * The file system service.
+   *
+   * @var \Drupal\Core\File\FileSystem
+   */
+  protected $fileSystem;
+
+  /**
+   * Constructs a new class instance.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   Entity type manager service.
+   * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
+   *   Entity field manager service.
+   * @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
+   *   The field type plugin manager service.
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The config factory service.
+   * @param \Drupal\Core\Image\ImageFactory $image_factory
+   *   The image factory.
+   * @param \Drupal\Core\File\FileSystem $file_system
+   *   The file system service.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, FieldTypePluginManagerInterface $field_type_manager, ConfigFactoryInterface $config_factory, ImageFactory $image_factory, FileSystem $file_system) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $entity_field_manager, $field_type_manager, $config_factory);
+
+    $this->imageFactory = $image_factory;
+    $this->fileSystem = $file_system;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('entity_type.manager'),
+      $container->get('entity_field.manager'),
+      $container->get('plugin.manager.field.field_type'),
+      $container->get('config.factory'),
+      $container->get('image.factory'),
+      $container->get('file_system')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMetadataAttributes() {
+    $attributes = parent::getMetadataAttributes();
+
+    $attributes += [
+      static::METADATA_ATTRIBUTE_WIDTH => $this->t('Width'),
+      static::METADATA_ATTRIBUTE_HEIGHT => $this->t('Height'),
+    ];
+
+    return $attributes;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMetadata(MediaInterface $media, $name) {
+    // Get the file and image data.
+    /** @var \Drupal\file\FileInterface $file */
+    $file = $media->get($this->configuration['source_field'])->entity;
+    // If the source field is not required, it may be empty.
+    if (!$file) {
+      return parent::getMetadata($media, $name);
+    }
+
+    $uri = $file->getFileUri();
+    $image = $this->imageFactory->get($uri);
+    switch ($name) {
+      case static::METADATA_ATTRIBUTE_WIDTH:
+        return $image->getWidth() ?: NULL;
+
+      case static::METADATA_ATTRIBUTE_HEIGHT:
+        return $image->getHeight() ?: NULL;
+
+      case 'thumbnail_uri':
+        return $uri;
+    }
+
+    return parent::getMetadata($media, $name);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function createSourceField(MediaTypeInterface $type) {
+    /** @var \Drupal\field\FieldConfigInterface $field */
+    $field = parent::createSourceField($type);
+
+    // Reset the field to its default settings so that we don't inherit the
+    // settings from the parent class' source field.
+    $settings = $this->fieldTypeManager->getDefaultFieldSettings($field->getType());
+
+    return $field->set('settings', $settings);
+  }
+
+}
diff --git a/core/modules/media/tests/fixtures/example_1.jpeg b/core/modules/media/tests/fixtures/example_1.jpeg
new file mode 100644
index 000000000000..e04cde60ca8f
--- /dev/null
+++ b/core/modules/media/tests/fixtures/example_1.jpeg
@@ -0,0 +1,51 @@
+ÿØÿà�JFIF��H�H��ÿáˆExif��MM�*�����������b�������x�������€(��������������‡i�������ˆˆ%����������Drupal EXIF Camera 1�����H������H����‚š��������������öˆ'�����������0210�������þ’
+������ �����0100 ����ÿÿ�����������������2014:08:28 06:52:00����7���������N����������P�����E����������h�������4�����������`—��ó���
�����������Ə��ÆÿáÍhttp://ns.adobe.com/xap/1.0/�<?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?>
+<x:xmpmeta xmlns:x='adobe:ns:meta/'>
+<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
+
+ <rdf:Description xmlns:exif='http://ns.adobe.com/exif/1.0/'>
+  <exif:Model>Drupal EXIF Camera</exif:Model>
+  <exif:XResolution>72</exif:XResolution>
+  <exif:YResolution>72</exif:YResolution>
+  <exif:ResolutionUnit>Inch</exif:ResolutionUnit>
+  <exif:YCbCrPositioning>Centered</exif:YCbCrPositioning>
+  <exif:ExifVersion>Exif Version 2.1</exif:ExifVersion>
+  <exif:FlashPixVersion>FlashPix Version 1.0</exif:FlashPixVersion>
+  <exif:ColorSpace>Uncalibrated</exif:ColorSpace>
+  <exif:InteroperabilityIndex>N</exif:InteroperabilityIndex>
+  <exif:InteroperabilityVersion>52, 30, 32.751</exif:InteroperabilityVersion>
+  <exif:GPSLongitudeRef>E</exif:GPSLongitudeRef>
+  <exif:GPSLongitude>13, 22, 25.5432</exif:GPSLongitude>
+ </rdf:Description>
+
+</rdf:RDF>
+</x:xmpmeta>
+<?xpacket end='r'?>
+ÿÛ�C�
+
+
+

ÿÛ�C		

ÿÂ��Y�È�ÿÄ�������������ÿÄ������������ÿÚ����õH�N«žÁ´�������‰ùÅéÆ‹Ù`:Q&ÜY­Œ ������9nZþüÆlê(-§Ïpûã“Ÿ{“'¸·h´à�����ß\¸Râ@o3uv‡'ƒßÛËô‹N¦ô�����¾‡%Wiñú}c�ÇïÊ­±0ÿ�E‡ØÓÃ-©%•–óª»À���+»Œý[}˜ˆ[Ð��Òå/ÂO¯°¿I„^fdp,ëüƆ§^_¿?³ê}:ΞQ]gYh2óZ‹ÝÞ]ëËÌÕ‹E¦€Þgøý£D­hfôú¯)¶åÉ‹Kê±0Ùq,LîªGdþ²æuœ•ÖÛV·Ù­N¼®¬–Ú#kOŸŸHξWþ+èT×çÏס±_Dó¶Ûç;|ät!Ϊ´ø¯Nüûêrˆvb=Þ%qkMtQé#}£vøw€]ç¡v”’Hxzy³súl_¾i-v·tv¯¥\Ž–ç.Ыj]Î]º$ØÔ:o,o>maÓ_Øô×ð[
+È”êü¼JàØYÔ·Òî���+콟C¨��!’ày³W‹áK?«ºÚüõ­ûùÜ‹2ÿ�Îj¶ �����Uæ½²ªŒË…½Ë¤òºÖQÂX���������������ÿÄ�'���������� 6@03PÿÚ��öH}júÎr5fKlÓ\m‹5ó
ŒqŠ…ôìYìq´ûŽÐhc¥²ºi8Ǻ7çµýç}¶ÙF¬à¯zÉÉetÏöc4
+B/¡»¾îô¶¥ŸÞ,’Œ(‹âšÊ
©Ô%àURÒþ:š•´sZªíºy<™Ù–À. ~Œ¼ÉŸÕR`¢ú=
ÊÓ^Ó%#Ϗ?™»1ZÓwF’Ðhš?;3Z•#.Kéõ£ý¼Ö“Ö8#æú¿‘s;œq—WB»/å(]i€CºIø
=ôÑã*@/.ß&{¨£'ñýÌé)MtZQ5ÙXnæ5Pø©𛇤¦µJ‹£‰‘Úí·fKÊ»s®ó}í%e®g"d!?‚„i¬®qIp÷‹„Ãkůh¤UÃ衈>=ðÛÖ„ºNý6º:·©Ç~£óÆJ)anjZÓYp{³YgP“MšR‹\Qéø;5v‘ÑÀ¯A©*>2”mÇ ûY­”C þèÊ[¨~(ÖSHlÆ"ðüÎÙµ¢¡kÖ¦ü%r²-ïÐç ?@öÃMÁ i ¸¨«Ÿ¦7™ÜD–œÆ$lúSCˆî`†Yt4ñt7¬ˆ7:<Jÿ�—ÿÄ�=�	�������!1AQ"#2aq± @‘Áð05¡Ñ$34BPRcáÿÚ�?õ(4øi{°÷ûAQPèýxUÖF•Ð€0	¨7¢Ð
ÈÖ8ÓZ34¬}‘JËãAëU\.ŽŒ¶–²âŠ•ÈÛ‹iYÐp5n»ú§õ+ÏØœXm%j¡!´':Žº›yÇ Í-jpæQ×êl«\Ã!¼‹ía¿I)JYNýt·œs¶¬}xNógR®KŒþbrã~Ñ«óÿ�•ì̵dد¼f饗Íro:ñáW¥f˜¡Ã]¤Q䎬ì¥]Õö‡°ß¾­M¡P‘˜qó5v`D’Ö¬uûêåq}¥6YVIu?r—(þèQÀcF|´ÂÒt³á°p«[ÎHŒtâjï:DgÂVîú¸ÜD$�5¨Ð›sXÒ'<5yU²èd«B÷k¹\ù§VÞµyW=ºeÒëÃÃW•[.|ó«sR‡çPÿ�>*ùÕé8LW~–Ûišs«R7+C(lyÔ‹LWö')î©–÷¡ž–´ñ¤5½UÔ·zNêL·4†JÚÔEEX@=†ýõhþI¿™«ê¤%p«Â4Ji³¹"¡¶–£ $n«êqŠãúÕ‘@ÄÁ5|PT°à*êAœBö)rŒ»)Ü‚ëÕìÌ>XÔ¬='×lÌ>‘JSs=™Â¡þ,|Uó«û—LJ%µ!	áË!æšG\uTgàz	À÷ýjä34SÇWÆ€À`*ñéI@dc…"Õ	ѧ<GëPìÊCši'õ¶®ð”êTÊqwS))m)<)ö!²ÒöUº|E8wiwK§•ãããWQÀƒÝä)ÈwÇDÑ%;°?XU²ÒXV™þÖáWKY—ÖµÚó¦áÜœê	!>:ª5²Còôâ6Th2¸iÔžŽ'†üiöS!²Úö‘
qÜ(5mŸÍ‘¡{fêô”Oóó©}Ìy¬ÃM)Y‰Ü>tàŒëJS]
ÜjÈ hßøÓKÓõƒ³»õû©v•È“§
+á÷¢"RpVÚ‘ØçŽFbµ!±•ÌÀÑ´Éî®fÛ_Æsܝf¡Û	9ßÙ¶{CNÛ#¹¯<+ШܺE™¡ÚQ4ÌVXì'ûgÿÄ�:�	�������!"1A#2Qq 0@a¡45R‘±Ááð$3PcÑÿÚ�?õQDq}ã(Oz°æ4Û*<UR° áÎÎÃN°ãÎ{ Më=¶&¡ASʺ©)GBЗUŠ›†–»F¸{’RV¬¢‹(åeEÃ-¼å%!ÉõqºÌŽÜp†Š>T–ÐŽèõå7®Ú“Ñ
+[$^Ö¯Bÿ�³åûÔœ9ØÃ?íôãuŒÞ:ÂÅ£]jåÐúrº¡ñ¬¼ºÄ¤ÊUòÕ†ºd0RæÞU.%aÑr
©˜˜Ô‘:ã™z`nå¿Î±Ãå
•†ÄeöJœMÍê#)D“dŠ1` ä6¿OÃU®Yß_vº¬éì¿ŸïSàumôwjOÕßrJÃ
⧢táeNÕ\É7+4Î#!žw‹5¹Cw…)~'K{­í5{ªt%Îu$ÝåyÖ
Þ]b_J_ó•a)`¨ó5†¯Q.,sQ©*.<¢¯Â
¤øV,’$ßÄV2ǹñ¬;è—O´¬×ÞãMæ8iöM1~¡Ùñ±è	¿Æ¤ý]÷'ô¬îóGÏ¢rŠ¤®ý,´ãªìªC3t÷•qÐÆǼ6þMÍëÔu(ºmK•‡(çVÓåR±0´i0,+
–Ë
”¸«m§RÉÓªaaÄr¡6”_LÄ[ÓҏXq´0|é¹0_Ý�*§â!äé5 OêÝ›ßÊ—&;P>Tüö]ŠS›x=1…ÂÒ
+Þ°ý)—TÊÉåLÈKÈ>ºµZã]BOÙü©œ/›Æ®åô£§(ÿ�å$ÈmÀ—7©˜~sŸÂœFˆÉÏŸ²ˆ¡†4Š}„i*Œ«ŽÌ–ßAèvKŒ9¼‹§á^’bºÓŽiyáR±�Ft¹â)¼Eôs½zU\ÓGp÷@§d:÷|ÿ�ŒÿÄ�C�			�������!1"AQaq2B‘ #@¡±ÁÑá0RSTbrs‚²$3P’“£ÂðÿÚ��?ð36S(ê¬2ïÚ­wTÓÍäõ&€kÝkwõŠ~¼rÇ^P‰t7a–@$×2a,L¤ÌËŒˆ:i÷Åež#4d¡æòD¤Ç—Ôlk߸o‹É“|ºÔ#°Žnóè‚ÛfÒÎB–³U+™+BŠœB’hD&Z}^0à‡ò
+Ü|‰Ç×ÕN­»rÓë]5nà ·/—¢
+ÖJ”uŸroªÔÃ=U֏‡ËJ$Ð|¯PöÇŒqJÜO†ÄØ®‚ê 5§XîæeA›ëÂ{T¤c"?»ð‹šÔ•ø”ýŸÑ¬é­–öWU7Dçå§ôÈæZUršô‰?¼¯dJÚm*­¬ÇÚ0Û’Âè(�OeUÕª•vé·˜K”²pG&´êYNjCv‰÷Eúž)™WD”
+ÒÍi”!ç×xáQÆ”×n]ë´‚©dja! 90çU'!¼Åúêoç!T	Y /û+¯ŒXS*Ç$韺¥mÜèú ²ð™H®(Aüw½J‰Þ)ý˜¸á-Ë Ð‘šŽÁS&צÑï0hÐaÍJkFQã¶NN§/„Q0*–däŽÚ½Ðëòh-8È´E¢B†¸äýì…wãy^È“üߨÃM'†ñâbA“›r©GtK!´Ñ6„2xÜD�3C„JSŠ’ÒRxÔŸl).“v›�ð¤$"–)…œ©	¸¥Ž’Œ¶á_Ma]&—wéµ\©‡2n)w~ ›9S?Ž÷©Q/6ŠÓtxŒG·»šL#"‹^sÎzjÐV¿6¸ñå¼œ+»Ni†Ó×x\§Š´G®Ú€K&Y«Ò‚k¤®ËwŒ´2ᇦÔû¡ÕƒjÀ5©ÚL4¹f/P¡6€Æ§i†R¬”�Gš—th,S„(JÞžÛ¥xÀ›å(«vj¥ðâND zyg_v_°[^¯d	©º_£c<c¤KÑ3�P¤öþ0%T·šcªm¹¢!ÀÉèÈtÑ´õvçmlR^õÅ[´œi®–^²WÍ:Œ9/0‹ ÐÓ(³AWC¨âEiéŸãWº
+9=¢Ò»ì™îX™\ìÃø¢]¥ãO´up‡Ý”Jä¦Y¢®Ü] ±Za[”Tl'¨õ*xLÒR¤Ê7üB…jÈ«†¡Äîù#8—Д’6|€´n¦ÔtAÝsMYرŠUÀó"æ},ò…tš�vSþ1“'}äZåPmJú¼¦šÎíЗùA*eŒÃ'¬®; % %#�¯#-º„¸ƒšV*Zl9-¹µ`{ãC”l§b™¯ûGŽœy†}ñj^Y)sé’»ÏòÏÿÄ�)�������!1AQaq‘¡ð @±ÁÑ0ñPÿÚ��?!ú	…åÐG}KFë6ûef¸U‚”"P!/ƒž!i84WM;"äj¶žf­›e±6³¾
+~–òUûãí
/2]á¶$žFTñ€…xdÜÔœ]~Jòpjf‚WÑD±‰ŠsáÈÒ<#³‡~ÆtaÃ)`9T;Ô{‰î³b$c»•¡#¸(ûk.4ú’”™Ç-œîØ/&Yû$±Mæ_{hðàxúìfÖ·y4�—”l`/;Ö¥t¬„—Ÿ'èê�f8ÝÉÊ¥%A<ï?^ø9ôSm¨ù+ç6¥¿´£fŒ(½€.Ì
n¯Æ“¹´P�8MÚËGȳBÅÕDI,Vb—û†”æçòœ"Œ¡ú(p'‚%ÄÓVÝ5Î^ô
+jñQtÛ¾˜æ„mÊwFÏ
+`1‹ò2�ít4àÔº¢ÎßÉâ¤rÈ5ü;¸ü×6ïW÷~ì:ߊH•a^©Â·üP¿¢Õ|æÔöÔˆðš"LjóWUEÕ%�ÂŒRUå«+ŸñýÅ)Vm
%qhè:�FÒ%-¤öÅ"qº™2Êž"&ˆÒ¤@ç¦â=�ŠK纒>‚¼»êÎbÁžà«e
+ãÑ@Yþ'ðLž¸Ž)LÀx™È¥Ã2éҐ ýG,¬ßO}*�‡i¤Eè_à1Ó e+DèÞ›Û>3¤&~f´6MLÊë~k8ÊéTÌ@œ"Š³À¸„µ[ôÿ�‚Ÿ@½-É¥Ø1›‘¡Yܸ
ѱTÁûåbh»SJfbmû
4}X.N•,~¹”M³ŠJÍ6%ñBV‹¾(ò]àwþ#@ßÍÎòIÔ“æä`Q%Þµ5ÎÊb9�»—K‘Ü1"l×ø
+@3‘Á­%�¬|ÌÛ<zDFB‹¾®6ì*>mžåZB`yzIµû”}S†ýg¿J=â�0Ù‹—z£Éõ—Ø,vŠ4ïæ	g…÷¥Ä]ìI£ÿ�3ÿÚ������’G$’I$’I$’rµ’I$’I$’*³îI$’I$’)Sl‰$’I$’DÛmï%òI$’L›m»æ×Ú%5¤Šs¹ÚÄo{‚BjNdûéú„r¦˜ŸrI$É$‘¿„–I$’I$’A–ÒI$’I$’I$’I$’I$’OÿÄ�*�������!1AQaq‘¡±Áð@Ñ 0áPñÿÚ�?þɘâDvÜÏã¨ҍ;ý]çqV~6ÝXUënô¡“®þýj©ÔÏâX+ܯ̊yvÐí¿-öŒR¦•ëþnù^š)_K
Jt‹AÓô}ÿ�	x±÷Ö–\.ñÆ„î´A¹Îžzöƒ­)”¿€ªJ6’%÷7ë¿à¦ÐÜí[ö£a-¼¿šI؁èæ³JUÚf"#‡z´‚ElŽü!Äÿ�bµˆãHÖ7§C@ôŸŸç+¡§‡9jõ¾Â u@ÐÄ-ÓlUšÐBÊî:SYËqÎÄ¢ë$_	ñ5*o‡€*Oabäj;P¢ÀÝø-7½ª]=áý@†DÑÖÖv58˜¤ßž]ï1]·37ÑÐM°76MNæ±÷{Uè^ñà‘pÊì|½-µŠœ‚óe¢×³Ó”óVÚLwÙáì´ëèPOÕú:ߍhcC9Q5α¶u6{W­ö;2”õU({Òå†òR œAî’½V˜F
+ù£å¸f®&‰ë+ì”Í`ö}Ú #aˆÒ8Úˆ—¼û“A3pœaÄDñPDUÚ‰In#WÝíUb[/säðÃBíßWÅ"ѼñýšÎ´ñwÙñáäü4Eˆ©´“7ÆéF”{k¤¨˜I%—tæ÷\ºT],‹Êê›Ð;¨V+-ž£zikí$ÆËJ!±eYž|Ë­,ƆšºÐé=Úu¡ñCã•Äí33„ÂB6‹ï¥ô‚H¨,,̓›‘h-Ú‡×8neLãŠYlΙÔҏëøö¬±ž¦‰V†Ü‹¤è›k9ãkSìý*qûÍ—Ê€,»ñºÓ€Ç˜LVL‚bÎçÙÈm,c.νêP5kúEŽ¬éýIÎb3`>?£Oò°1¢aðŠ­[´kŽ½
+»ÔûÖ8ã¹DŠ4jzþ¨?
@ÈïKA>_”ÉsȤçÊÝ`!ß/›ÿ�3ÿÄ�*��������!1AQaq‘¡±ÁÑð@á 0ñPÿÚ�?þ
+×n™„ä_oDZB5éó§xcRNRúZÁÊôÑ$ÉÁá¥O/‡'ñ/ÖÁ‹÷=i¤à×7Ÿ±Îq¢…÷ü:ÚˆD"Lš%¿œÌù<~ìv°^Xß}eýeCÛúó†ðÆÍu‚@ÌYÏÞjú'óÕÃŽ^„Ö)Ç™HÊ…â3Ó.'ûý™ƒe³9Êt¡yš½ãÛùÀCЏÉy®Ü÷©®0ÁÙKÄ…S˜™ëŠTÀNR˜F‰Rµ<˜“¿mî³›&gNU�¾›Ôy„b–ƒDÖ³P5Ð÷ӝB1¡»ÌÓ4Þ9Nc™–¦ù]:
1_^FÙVĦtÍÊ­RU¯ˆé¹£Éßíz4SºûúÀ5}¯IãB
+pµÝñïUȃŠÇ–¦ýb„µx¶GύéÓ’Ì°¢yª»sÞ¼o
+´1c€õž”Xa¥šYvlr£ŇQù¤Y<{S­IÂÈÐ@7Kœ¡à¤›+¯8Îs½48³4†;E0]+Y¼Æó†õyš]­3ŒÙ¾óXkСWÁáöôlÊÇ"ÇoP€dÌ´sÊ…†±ñ½‰ïèç°ùÔˆ±jøE—]™À›åêRÕ¡Ú
�ÏlêFX- Ðke^õŽbÿ�Ne©Âd&81p¡,â$ 
R‰îhFdIŸ¾ÙÓl~.°iÆï“7ÙúÃîu1ˆ$\½,îÖHÅi&#½^CˆÊñ9Ö+?QX0¿b’RìG=Íþñ½*a9CÝøëJ³bÑiÙŸõ}	D„#}¾ñU+¸àæ|TóeäËn9¼·þ¡.Rol×çú1b±5ýÖ28ž$ÉnMgéÅ¡É—¥E¼¾üšt’çáJ¬¸þ°Ð0¹îEÙëú¬)u~+SL‡üÏÿÄ�&�������!1AQaq @‘¡±0PÁÿÚ��?ú;ŒÐY«(­µ>Þ*Tʯ” $ìs pF•Ä-¶‹¶JªJª¥$á4ØÌ »�òZÖ`ZiHÅûM|ìAÁŽ¶ÃDyõÊb¯0[ ²ŽÝfÆ)Û¿G]W&ñ·ØìcÓ^g©ÉXTRW
@£ H¶D)ÙQ˜ìiÏ�Ï‘…Pò1
+0FTµvÍ3ú^‰·1ì*¶øðx4}�À!áÎme™KT¡´U£ìniK	ÇGŠQê²&6LÒ÷è¾~¥]-dòÀ(%᎐qS!Ôr”ûU^µöq„tžQþñvë
P9@ák¹þhKKwìð½fD5¥ j;½×ë{©ޏê«MåGçÐu¡„üë¦ðèCƒ…�hV@1¢îQµÞ†»a¢¡‚ˆ€Ø#6»r^~‡FFËçöÇ’hñ†¼ýbE;ÁK5—?YcÒB2è¨ìŽG&îƃ»gWÉùgÔˆÒùÄàPlR´ÒÖ<Çußÿ�Îq„Ž‚M‚–·iªz,jˆQæ­ý¾„çñªˆ„K(YÖÎÅû‚{Xtlj²1Sòh½Îq誻Â<Ç«Ìar.Éßã¾iRÔ¤P#WaÓ€ŽC³Þ!ÙPÀÄMŽ9Ù+à?GÔr󣲊üíøbh/FŠ?Ù‰Ê0Þ슯w,àTq~Gäˍgr”?ß¿lê#_“ù쑤7ò}Ü
�i$ÔÂÌàkÉì?8N…‘ZÍë¾t¸¦˜é^wm„Ôž–4G!¬îÞt=ž„¶Ñ×Üö“§¬Æõ ’"ƒ¨]Ã"¥ï0t¶JÈ–¡èǁöìŒÜ
+#¦cӁƒà”3úPõ+.Xœ•ù)tں‚EÁ´.àק!ƒBo7¥ÚM13¦`ó€)½b9p4’考 ¬\æçò-¸2È*¢ [Vu+û”vI†˜ ½ì%X¹·úH‰4Ê€¶ª`\t“ñàp.’
+�âûjv•Þ!aðTS¥v4›oŒE�<c·ul]Íâ‘l�X
+u(éqƒÓÔŽ‚”I±8ãF‘GaëJK"H¼Þÿ�·�èi{ê*={‹ÈÆ­ŒÑnº‚43
+·ã1€ëdŸ�ÕÄÚôƒà@:á‹
+… fƉI°ÿ� ®ó{f·Ÿð¤¬eßÎåØ•Í»ü­ÌPœ‹ècr\ÊPV‚¼ŽôVD/EïÐþ±…¾ÂFÐx˜%Xº{aÓÆ&žõª—º* ��ãìàjÌnÂD÷0X:œ¥ë$tñŠ‰mFÁýasÄœ?ÞC¨Ð‹Ô“ۏùŸÿÙ
\ No newline at end of file
diff --git a/core/modules/media/tests/fixtures/example_2.jpeg b/core/modules/media/tests/fixtures/example_2.jpeg
new file mode 100644
index 000000000000..c0b67c217769
--- /dev/null
+++ b/core/modules/media/tests/fixtures/example_2.jpeg
@@ -0,0 +1,51 @@
+ÿØÿà�JFIF��H�H��ÿáˆExif��MM�*�����������b�������x�������€(��������������‡i�������ˆˆ%����������Drupal EXIF Camera 2�����H������H����‚š��������������öˆ'�����������0210�������þ’
+������ �����0100 ����ÿÿ�����������������2017:05:11 22:38:00����7���������N����������P�����E����������h�������4�����������`—��ó���
�����������Ə��ÆÿáÍhttp://ns.adobe.com/xap/1.0/�<?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?>
+<x:xmpmeta xmlns:x='adobe:ns:meta/'>
+<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
+
+ <rdf:Description xmlns:exif='http://ns.adobe.com/exif/1.0/'>
+  <exif:Model>Drupal EXIF Camera</exif:Model>
+  <exif:XResolution>72</exif:XResolution>
+  <exif:YResolution>72</exif:YResolution>
+  <exif:ResolutionUnit>Inch</exif:ResolutionUnit>
+  <exif:YCbCrPositioning>Centered</exif:YCbCrPositioning>
+  <exif:ExifVersion>Exif Version 2.1</exif:ExifVersion>
+  <exif:FlashPixVersion>FlashPix Version 1.0</exif:FlashPixVersion>
+  <exif:ColorSpace>Uncalibrated</exif:ColorSpace>
+  <exif:InteroperabilityIndex>N</exif:InteroperabilityIndex>
+  <exif:InteroperabilityVersion>52, 30, 32.751</exif:InteroperabilityVersion>
+  <exif:GPSLongitudeRef>E</exif:GPSLongitudeRef>
+  <exif:GPSLongitude>13, 22, 25.5432</exif:GPSLongitude>
+ </rdf:Description>
+
+</rdf:RDF>
+</x:xmpmeta>
+<?xpacket end='r'?>
+ÿÛ�C�
+
+
+

ÿÛ�C		

ÿÂ��Y�È�ÿÄ�������������ÿÄ������������ÿÚ����õH�N«žÁ´�������‰ùÅéÆ‹Ù`:Q&ÜY­Œ ������9nZþüÆlê(-§Ïpûã“Ÿ{“'¸·h´à�����ß\¸Râ@o3uv‡'ƒßÛËô‹N¦ô�����¾‡%Wiñú}c�ÇïÊ­±0ÿ�E‡ØÓÃ-©%•–óª»À���+»Œý[}˜ˆ[Ð��Òå/ÂO¯°¿I„^fdp,ëüƆ§^_¿?³ê}:ΞQ]gYh2óZ‹ÝÞ]ëËÌÕ‹E¦€Þgøý£D­hfôú¯)¶åÉ‹Kê±0Ùq,LîªGdþ²æuœ•ÖÛV·Ù­N¼®¬–Ú#kOŸŸHξWþ+èT×çÏס±_Dó¶Ûç;|ät!Ϊ´ø¯Nüûêrˆvb=Þ%qkMtQé#}£vøw€]ç¡v”’Hxzy³súl_¾i-v·tv¯¥\Ž–ç.Ыj]Î]º$ØÔ:o,o>maÓ_Øô×ð[
+È”êü¼JàØYÔ·Òî���+콟C¨��!’ày³W‹áK?«ºÚüõ­ûùÜ‹2ÿ�Îj¶ �����Uæ½²ªŒË…½Ë¤òºÖQÂX���������������ÿÄ�'���������� 6@03PÿÚ��öH}júÎr5fKlÓ\m‹5ó
ŒqŠ…ôìYìq´ûŽÐhc¥²ºi8Ǻ7çµýç}¶ÙF¬à¯zÉÉetÏöc4
+B/¡»¾îô¶¥ŸÞ,’Œ(‹âšÊ
©Ô%àURÒþ:š•´sZªíºy<™Ù–À. ~Œ¼ÉŸÕR`¢ú=
ÊÓ^Ó%#Ϗ?™»1ZÓwF’Ðhš?;3Z•#.Kéõ£ý¼Ö“Ö8#æú¿‘s;œq—WB»/å(]i€CºIø
=ôÑã*@/.ß&{¨£'ñýÌé)MtZQ5ÙXnæ5Pø©𛇤¦µJ‹£‰‘Úí·fKÊ»s®ó}í%e®g"d!?‚„i¬®qIp÷‹„Ãkůh¤UÃ衈>=ðÛÖ„ºNý6º:·©Ç~£óÆJ)anjZÓYp{³YgP“MšR‹\Qéø;5v‘ÑÀ¯A©*>2”mÇ ûY­”C þèÊ[¨~(ÖSHlÆ"ðüÎÙµ¢¡kÖ¦ü%r²-ïÐç ?@öÃMÁ i ¸¨«Ÿ¦7™ÜD–œÆ$lúSCˆî`†Yt4ñt7¬ˆ7:<Jÿ�—ÿÄ�=�	�������!1AQ"#2aq± @‘Áð05¡Ñ$34BPRcáÿÚ�?õ(4øi{°÷ûAQPèýxUÖF•Ð€0	¨7¢Ð
ÈÖ8ÓZ34¬}‘JËãAëU\.ŽŒ¶–²âŠ•ÈÛ‹iYÐp5n»ú§õ+ÏØœXm%j¡!´':Žº›yÇ Í-jpæQ×êl«\Ã!¼‹ía¿I)JYNýt·œs¶¬}xNógR®KŒþbrã~Ñ«óÿ�•ì̵dد¼f饗Íro:ñáW¥f˜¡Ã]¤Q䎬ì¥]Õö‡°ß¾­M¡P‘˜qó5v`D’Ö¬uûêåq}¥6YVIu?r—(þèQÀcF|´ÂÒt³á°p«[ÎHŒtâjï:DgÂVîú¸ÜD$�5¨Ð›sXÒ'<5yU²èd«B÷k¹\ù§VÞµyW=ºeÒëÃÃW•[.|ó«sR‡çPÿ�>*ùÕé8LW~–Ûišs«R7+C(lyÔ‹LWö')î©–÷¡ž–´ñ¤5½UÔ·zNêL·4†JÚÔEEX@=†ýõhþI¿™«ê¤%p«Â4Ji³¹"¡¶–£ $n«êqŠãúÕ‘@ÄÁ5|PT°à*êAœBö)rŒ»)Ü‚ëÕìÌ>XÔ¬='×lÌ>‘JSs=™Â¡þ,|Uó«û—LJ%µ!	áË!æšG\uTgàz	À÷ýjä34SÇWÆ€À`*ñéI@dc…"Õ	ѧ<GëPìÊCši'õ¶®ð”êTÊqwS))m)<)ö!²ÒöUº|E8wiwK§•ãããWQÀƒÝä)ÈwÇDÑ%;°?XU²ÒXV™þÖáWKY—ÖµÚó¦áÜœê	!>:ª5²Còôâ6Th2¸iÔžŽ'†üiöS!²Úö‘
qÜ(5mŸÍ‘¡{fêô”Oóó©}Ìy¬ÃM)Y‰Ü>tàŒëJS]
ÜjÈ hßøÓKÓõƒ³»õû©v•È“§
+á÷¢"RpVÚ‘ØçŽFbµ!±•ÌÀÑ´Éî®fÛ_Æsܝf¡Û	9ßÙ¶{CNÛ#¹¯<+ШܺE™¡ÚQ4ÌVXì'ûgÿÄ�:�	�������!"1A#2Qq 0@a¡45R‘±Ááð$3PcÑÿÚ�?õQDq}ã(Oz°æ4Û*<UR° áÎÎÃN°ãÎ{ Më=¶&¡ASʺ©)GBЗUŠ›†–»F¸{’RV¬¢‹(åeEÃ-¼å%!ÉõqºÌŽÜp†Š>T–ÐŽèõå7®Ú“Ñ
+[$^Ö¯Bÿ�³åûÔœ9ØÃ?íôãuŒÞ:ÂÅ£]jåÐúrº¡ñ¬¼ºÄ¤ÊUòÕ†ºd0RæÞU.%aÑr
©˜˜Ô‘:ã™z`nå¿Î±Ãå
•†ÄeöJœMÍê#)D“dŠ1` ä6¿OÃU®Yß_vº¬éì¿ŸïSàumôwjOÕßrJÃ
⧢táeNÕ\É7+4Î#!žw‹5¹Cw…)~'K{­í5{ªt%Îu$ÝåyÖ
Þ]b_J_ó•a)`¨ó5†¯Q.,sQ©*.<¢¯Â
¤øV,’$ßÄV2ǹñ¬;è—O´¬×ÞãMæ8iöM1~¡Ùñ±è	¿Æ¤ý]÷'ô¬îóGÏ¢rŠ¤®ý,´ãªìªC3t÷•qÐÆǼ6þMÍëÔu(ºmK•‡(çVÓåR±0´i0,+
–Ë
”¸«m§RÉÓªaaÄr¡6”_LÄ[ÓҏXq´0|é¹0_Ý�*§â!äé5 OêÝ›ßÊ—&;P>Tüö]ŠS›x=1…ÂÒ
+Þ°ý)—TÊÉåLÈKÈ>ºµZã]BOÙü©œ/›Æ®åô£§(ÿ�å$ÈmÀ—7©˜~sŸÂœFˆÉÏŸ²ˆ¡†4Š}„i*Œ«ŽÌ–ßAèvKŒ9¼‹§á^’bºÓŽiyáR±�Ft¹â)¼Eôs½zU\ÓGp÷@§d:÷|ÿ�ŒÿÄ�C�			�������!1"AQaq2B‘ #@¡±ÁÑá0RSTbrs‚²$3P’“£ÂðÿÚ��?ð36S(ê¬2ïÚ­wTÓÍäõ&€kÝkwõŠ~¼rÇ^P‰t7a–@$×2a,L¤ÌËŒˆ:i÷Åež#4d¡æòD¤Ç—Ôlk߸o‹É“|ºÔ#°Žnóè‚ÛfÒÎB–³U+™+BŠœB’hD&Z}^0à‡ò
+Ü|‰Ç×ÕN­»rÓë]5nà ·/—¢
+ÖJ”uŸroªÔÃ=U֏‡ËJ$Ð|¯PöÇŒqJÜO†ÄØ®‚ê 5§XîæeA›ëÂ{T¤c"?»ð‹šÔ•ø”ýŸÑ¬é­–öWU7Dçå§ôÈæZUršô‰?¼¯dJÚm*­¬ÇÚ0Û’Âè(�OeUÕª•vé·˜K”²pG&´êYNjCv‰÷Eúž)™WD”
+ÒÍi”!ç×xáQÆ”×n]ë´‚©dja! 90çU'!¼Åúêoç!T	Y /û+¯ŒXS*Ç$韺¥mÜèú ²ð™H®(Aüw½J‰Þ)ý˜¸á-Ë Ð‘šŽÁS&צÑï0hÐaÍJkFQã¶NN§/„Q0*–däŽÚ½Ðëòh-8È´E¢B†¸äýì…wãy^È“üߨÃM'†ñâbA“›r©GtK!´Ñ6„2xÜD�3C„JSŠ’ÒRxÔŸl).“v›�ð¤$"–)…œ©	¸¥Ž’Œ¶á_Ma]&—wéµ\©‡2n)w~ ›9S?Ž÷©Q/6ŠÓtxŒG·»šL#"‹^sÎzjÐV¿6¸ñå¼œ+»Ni†Ó×x\§Š´G®Ú€K&Y«Ò‚k¤®ËwŒ´2ᇦÔû¡ÕƒjÀ5©ÚL4¹f/P¡6€Æ§i†R¬”�Gš—th,S„(JÞžÛ¥xÀ›å(«vj¥ðâND zyg_v_°[^¯d	©º_£c<c¤KÑ3�P¤öþ0%T·šcªm¹¢!ÀÉèÈtÑ´õvçmlR^õÅ[´œi®–^²WÍ:Œ9/0‹ ÐÓ(³AWC¨âEiéŸãWº
+9=¢Ò»ì™îX™\ìÃø¢]¥ãO´up‡Ý”Jä¦Y¢®Ü] ±Za[”Tl'¨õ*xLÒR¤Ê7üB…jÈ«†¡Äîù#8—Д’6|€´n¦ÔtAÝsMYرŠUÀó"æ},ò…tš�vSþ1“'}äZåPmJú¼¦šÎíЗùA*eŒÃ'¬®; % %#�¯#-º„¸ƒšV*Zl9-¹µ`{ãC”l§b™¯ûGŽœy†}ñj^Y)sé’»ÏòÏÿÄ�)�������!1AQaq‘¡ð @±ÁÑ0ñPÿÚ��?!ú	…åÐG}KFë6ûef¸U‚”"P!/ƒž!i84WM;"äj¶žf­›e±6³¾
+~–òUûãí
/2]á¶$žFTñ€…xdÜÔœ]~Jòpjf‚WÑD±‰ŠsáÈÒ<#³‡~ÆtaÃ)`9T;Ô{‰î³b$c»•¡#¸(ûk.4ú’”™Ç-œîØ/&Yû$±Mæ_{hðàxúìfÖ·y4�—”l`/;Ö¥t¬„—Ÿ'èê�f8ÝÉÊ¥%A<ï?^ø9ôSm¨ù+ç6¥¿´£fŒ(½€.Ì
n¯Æ“¹´P�8MÚËGȳBÅÕDI,Vb—û†”æçòœ"Œ¡ú(p'‚%ÄÓVÝ5Î^ô
+jñQtÛ¾˜æ„mÊwFÏ
+`1‹ò2�ít4àÔº¢ÎßÉâ¤rÈ5ü;¸ü×6ïW÷~ì:ߊH•a^©Â·üP¿¢Õ|æÔöÔˆðš"LjóWUEÕ%�ÂŒRUå«+ŸñýÅ)Vm
%qhè:�FÒ%-¤öÅ"qº™2Êž"&ˆÒ¤@ç¦â=�ŠK纒>‚¼»êÎbÁžà«e
+ãÑ@Yþ'ðLž¸Ž)LÀx™È¥Ã2éҐ ýG,¬ßO}*�‡i¤Eè_à1Ó e+DèÞ›Û>3¤&~f´6MLÊë~k8ÊéTÌ@œ"Š³À¸„µ[ôÿ�‚Ÿ@½-É¥Ø1›‘¡Yܸ
ѱTÁûåbh»SJfbmû
4}X.N•,~¹”M³ŠJÍ6%ñBV‹¾(ò]àwþ#@ßÍÎòIÔ“æä`Q%Þµ5ÎÊb9�»—K‘Ü1"l×ø
+@3‘Á­%�¬|ÌÛ<zDFB‹¾®6ì*>mžåZB`yzIµû”}S†ýg¿J=â�0Ù‹—z£Éõ—Ø,vŠ4ïæ	g…÷¥Ä]ìI£ÿ�3ÿÚ������’G$’I$’I$’rµ’I$’I$’*³îI$’I$’)Sl‰$’I$’DÛmï%òI$’L›m»æ×Ú%5¤Šs¹ÚÄo{‚BjNdûéú„r¦˜ŸrI$É$‘¿„–I$’I$’A–ÒI$’I$’I$’I$’I$’OÿÄ�*�������!1AQaq‘¡±Áð@Ñ 0áPñÿÚ�?þɘâDvÜÏã¨ҍ;ý]çqV~6ÝXUënô¡“®þýj©ÔÏâX+ܯ̊yvÐí¿-öŒR¦•ëþnù^š)_K
Jt‹AÓô}ÿ�	x±÷Ö–\.ñÆ„î´A¹Îžzöƒ­)”¿€ªJ6’%÷7ë¿à¦ÐÜí[ö£a-¼¿šI؁èæ³JUÚf"#‡z´‚ElŽü!Äÿ�bµˆãHÖ7§C@ôŸŸç+¡§‡9jõ¾Â u@ÐÄ-ÓlUšÐBÊî:SYËqÎÄ¢ë$_	ñ5*o‡€*Oabäj;P¢ÀÝø-7½ª]=áý@†DÑÖÖv58˜¤ßž]ï1]·37ÑÐM°76MNæ±÷{Uè^ñà‘pÊì|½-µŠœ‚óe¢×³Ó”óVÚLwÙáì´ëèPOÕú:ߍhcC9Q5α¶u6{W­ö;2”õU({Òå†òR œAî’½V˜F
+ù£å¸f®&‰ë+ì”Í`ö}Ú #aˆÒ8Úˆ—¼û“A3pœaÄDñPDUÚ‰In#WÝíUb[/säðÃBíßWÅ"ѼñýšÎ´ñwÙñáäü4Eˆ©´“7ÆéF”{k¤¨˜I%—tæ÷\ºT],‹Êê›Ð;¨V+-ž£zikí$ÆËJ!±eYž|Ë­,ƆšºÐé=Úu¡ñCã•Äí33„ÂB6‹ï¥ô‚H¨,,̓›‘h-Ú‡×8neLãŠYlΙÔҏëøö¬±ž¦‰V†Ü‹¤è›k9ãkSìý*qûÍ—Ê€,»ñºÓ€Ç˜LVL‚bÎçÙÈm,c.νêP5kúEŽ¬éýIÎb3`>?£Oò°1¢aðŠ­[´kŽ½
+»ÔûÖ8ã¹DŠ4jzþ¨?
@ÈïKA>_”ÉsȤçÊÝ`!ß/›ÿ�3ÿÄ�*��������!1AQaq‘¡±ÁÑð@á 0ñPÿÚ�?þ
+×n™„ä_oDZB5éó§xcRNRúZÁÊôÑ$ÉÁá¥O/‡'ñ/ÖÁ‹÷=i¤à×7Ÿ±Îq¢…÷ü:ÚˆD"Lš%¿œÌù<~ìv°^Xß}eýeCÛúó†ðÆÍu‚@ÌYÏÞjú'óÕÃŽ^„Ö)Ç™HÊ…â3Ó.'ûý™ƒe³9Êt¡yš½ãÛùÀCЏÉy®Ü÷©®0ÁÙKÄ…S˜™ëŠTÀNR˜F‰Rµ<˜“¿mî³›&gNU�¾›Ôy„b–ƒDÖ³P5Ð÷ӝB1¡»ÌÓ4Þ9Nc™–¦ù]:
1_^FÙVĦtÍÊ­RU¯ˆé¹£Éßíz4SºûúÀ5}¯IãB
+pµÝñïUȃŠÇ–¦ýb„µx¶GύéÓ’Ì°¢yª»sÞ¼o
+´1c€õž”Xa¥šYvlr£ŇQù¤Y<{S­IÂÈÐ@7Kœ¡à¤›+¯8Îs½48³4†;E0]+Y¼Æó†õyš]­3ŒÙ¾óXkСWÁáöôlÊÇ"ÇoP€dÌ´sÊ…†±ñ½‰ïèç°ùÔˆ±jøE—]™À›åêRÕ¡Ú
�ÏlêFX- Ðke^õŽbÿ�Ne©Âd&81p¡,â$ 
R‰îhFdIŸ¾ÙÓl~.°iÆï“7ÙúÃîu1ˆ$\½,îÖHÅi&#½^CˆÊñ9Ö+?QX0¿b’RìG=Íþñ½*a9CÝøëJ³bÑiÙŸõ}	D„#}¾ñU+¸àæ|TóeäËn9¼·þ¡.Rol×çú1b±5ýÖ28ž$ÉnMgéÅ¡É—¥E¼¾üšt’çáJ¬¸þ°Ð0¹îEÙëú¬)u~+SL‡üÏÿÄ�&�������!1AQaq @‘¡±0PÁÿÚ��?ú;ŒÐY«(­µ>Þ*Tʯ” $ìs pF•Ä-¶‹¶JªJª¥$á4ØÌ »�òZÖ`ZiHÅûM|ìAÁŽ¶ÃDyõÊb¯0[ ²ŽÝfÆ)Û¿G]W&ñ·ØìcÓ^g©ÉXTRW
@£ H¶D)ÙQ˜ìiÏ�Ï‘…Pò1
+0FTµvÍ3ú^‰·1ì*¶øðx4}�À!áÎme™KT¡´U£ìniK	ÇGŠQê²&6LÒ÷è¾~¥]-dòÀ(%᎐qS!Ôr”ûU^µöq„tžQþñvë
P9@ák¹þhKKwìð½fD5¥ j;½×ë{©ޏê«MåGçÐu¡„üë¦ðèCƒ…�hV@1¢îQµÞ†»a¢¡‚ˆ€Ø#6»r^~‡FFËçöÇ’hñ†¼ýbE;ÁK5—?YcÒB2è¨ìŽG&îƃ»gWÉùgÔˆÒùÄàPlR´ÒÖ<Çußÿ�Îq„Ž‚M‚–·iªz,jˆQæ­ý¾„çñªˆ„K(YÖÎÅû‚{Xtlj²1Sòh½Îq誻Â<Ç«Ìar.Éßã¾iRÔ¤P#WaÓ€ŽC³Þ!ÙPÀÄMŽ9Ù+à?GÔr󣲊üíøbh/FŠ?Ù‰Ê0Þ슯w,àTq~Gäˍgr”?ß¿lê#_“ù쑤7ò}Ü
�i$ÔÂÌàkÉì?8N…‘ZÍë¾t¸¦˜é^wm„Ôž–4G!¬îÞt=ž„¶Ñ×Üö“§¬Æõ ’"ƒ¨]Ã"¥ï0t¶JÈ–¡èǁöìŒÜ
+#¦cӁƒà”3úPõ+.Xœ•ù)tں‚EÁ´.àק!ƒBo7¥ÚM13¦`ó€)½b9p4’考 ¬\æçò-¸2È*¢ [Vu+û”vI†˜ ½ì%X¹·úH‰4Ê€¶ª`\t“ñàp.’
+�âûjv•Þ!aðTS¥v4›oŒE�<c·ul]Íâ‘l�X
+u(éqƒÓÔŽ‚”I±8ãF‘GaëJK"H¼Þÿ�·�èi{ê*={‹ÈÆ­ŒÑnº‚43
+·ã1€ëdŸ�ÕÄÚôƒà@:á‹
+… fƉI°ÿ� ®ó{f·Ÿð¤¬eßÎåØ•Í»ü­ÌPœ‹ècr\ÊPV‚¼ŽôVD/EïÐþ±…¾ÂFÐx˜%Xº{aÓÆ&žõª—º* ��ãìàjÌnÂD÷0X:œ¥ë$tñŠ‰mFÁýasÄœ?ÞC¨Ð‹Ô“ۏùŸÿÙ
\ No newline at end of file
diff --git a/core/modules/media/tests/src/Functional/MediaRevisionTest.php b/core/modules/media/tests/src/Functional/MediaRevisionTest.php
index f35b97bb38bd..ce1897f3ce18 100644
--- a/core/modules/media/tests/src/Functional/MediaRevisionTest.php
+++ b/core/modules/media/tests/src/Functional/MediaRevisionTest.php
@@ -3,6 +3,7 @@
 namespace Drupal\Tests\media\Functional;
 
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\field\Entity\FieldConfig;
 
 /**
  * Tests the revisionability of media entities.
@@ -44,6 +45,46 @@ public function testFileMediaRevision() {
     $this->assertRevisionCount($media, 2);
   }
 
+  /**
+   * Tests creating revisions of a Image media item.
+   */
+  public function testImageMediaRevision() {
+    $assert = $this->assertSession();
+
+    /** @var \Drupal\field\FieldConfigInterface $field */
+    // Disable the alt text field, because this is not a JavaScript test and
+    // the alt text field will therefore not appear without a full page refresh.
+    $field = FieldConfig::load('media.image.field_media_image');
+    $settings = $field->getSettings();
+    $settings['alt_field'] = FALSE;
+    $settings['alt_field_required'] = FALSE;
+    $field->set('settings', $settings);
+    $field->save();
+
+    // Create a media item.
+    $this->drupalGet('/media/add/image');
+    $page = $this->getSession()->getPage();
+    $page->fillField('Name', 'Foobar');
+    $page->attachFileToField('Image', \Drupal::root() . '/core/modules/media/tests/fixtures/example_1.jpeg');
+    $page->pressButton('Save and publish');
+    $assert->addressMatches('/^\/media\/[0-9]+$/');
+
+    // The media item was just created, so it should only have one revision.
+    $media = $this->container
+      ->get('entity_type.manager')
+      ->getStorage('media')
+      ->load(1);
+    $this->assertRevisionCount($media, 1);
+
+    // If we edit the item, we should get a new revision.
+    $this->drupalGet('/media/1/edit');
+    $assert->checkboxChecked('Create new revision');
+    $page = $this->getSession()->getPage();
+    $page->fillField('Name', 'Foobaz');
+    $page->pressButton('Save and keep published');
+    $this->assertRevisionCount($media, 2);
+  }
+
   /**
    * Asserts that an entity has a certain number of revisions.
    *
diff --git a/core/modules/media/tests/src/Functional/MediaUiFunctionalTest.php b/core/modules/media/tests/src/Functional/MediaUiFunctionalTest.php
index e37b850c750c..8f3f67506a45 100644
--- a/core/modules/media/tests/src/Functional/MediaUiFunctionalTest.php
+++ b/core/modules/media/tests/src/Functional/MediaUiFunctionalTest.php
@@ -33,6 +33,7 @@ protected function setUp() {
     // We need to test without any default configuration in place.
     // @TODO: Remove this when https://www.drupal.org/node/2883813 lands.
     MediaType::load('file')->delete();
+    MediaType::load('image')->delete();
   }
 
   /**
diff --git a/core/modules/media/tests/src/FunctionalJavascript/MediaSourceImageTest.php b/core/modules/media/tests/src/FunctionalJavascript/MediaSourceImageTest.php
new file mode 100644
index 000000000000..0505d3bb1167
--- /dev/null
+++ b/core/modules/media/tests/src/FunctionalJavascript/MediaSourceImageTest.php
@@ -0,0 +1,79 @@
+<?php
+
+namespace Drupal\Tests\media\FunctionalJavascript;
+
+use Drupal\media\Entity\Media;
+use Drupal\media\Entity\MediaType;
+use Drupal\media\Plugin\media\Source\Image;
+
+/**
+ * Tests the image media source.
+ *
+ * @group media
+ */
+class MediaSourceImageTest extends MediaSourceTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    // We need to test without any default configuration in place.
+    // @TODO: Remove this as part of https://www.drupal.org/node/2883813.
+    MediaType::load('file')->delete();
+    MediaType::load('image')->delete();
+  }
+
+  /**
+   * Tests the image media source.
+   */
+  public function testMediaImageSource() {
+    $media_type_id = 'test_media_image_type';
+    $source_field_id = 'field_media_image';
+    $provided_fields = [
+      Image::METADATA_ATTRIBUTE_WIDTH,
+      Image::METADATA_ATTRIBUTE_HEIGHT,
+    ];
+
+    $session = $this->getSession();
+    $page = $session->getPage();
+    $assert_session = $this->assertSession();
+
+    $this->doTestCreateMediaType($media_type_id, 'image', $provided_fields);
+
+    // Create custom fields for the media type to store metadata attributes.
+    $fields = [
+      'field_string_width' => 'string',
+      'field_string_height' => 'string',
+    ];
+    $this->createMediaTypeFields($fields, $media_type_id);
+
+    // Hide the name field widget to test default name generation.
+    $this->hideMediaTypeFieldWidget('name', $media_type_id);
+
+    $this->drupalGet("admin/structure/media/manage/{$media_type_id}");
+    $page->selectFieldOption("field_map[" . Image::METADATA_ATTRIBUTE_WIDTH . "]", 'field_string_width');
+    $page->selectFieldOption("field_map[" . Image::METADATA_ATTRIBUTE_HEIGHT . "]", 'field_string_height');
+    $page->pressButton('Save');
+
+    // Create a media item.
+    $this->drupalGet("media/add/{$media_type_id}");
+    $page->attachFileToField("files[{$source_field_id}_0]", \Drupal::root() . '/core/modules/media/tests/fixtures/example_1.jpeg');
+    $assert_session->assertWaitOnAjaxRequest();
+    $page->fillField("{$source_field_id}[0][alt]", 'Image Alt Text 1');
+    $page->pressButton('Save and publish');
+
+    $assert_session->addressEquals('media/1');
+
+    // Make sure the thumbnail is displayed from uploaded image.
+    $assert_session->elementAttributeContains('css', '.image-style-thumbnail', 'src', 'example_1.jpeg');
+
+    // Load the media and check that all fields are properly populated.
+    $media = Media::load(1);
+    $this->assertEquals('example_1.jpeg', $media->label());
+    $this->assertEquals('200', $media->get('field_string_width')->value);
+    $this->assertEquals('89', $media->get('field_string_height')->value);
+  }
+
+}
diff --git a/core/modules/media/tests/src/FunctionalJavascript/MediaSourceTestBase.php b/core/modules/media/tests/src/FunctionalJavascript/MediaSourceTestBase.php
index 5af6d5c14340..24cd13426605 100644
--- a/core/modules/media/tests/src/FunctionalJavascript/MediaSourceTestBase.php
+++ b/core/modules/media/tests/src/FunctionalJavascript/MediaSourceTestBase.php
@@ -37,10 +37,22 @@ protected function createMediaTypeField($field_name, $field_type, $media_type_id
     // Make the field widget visible in the form display.
     $component = \Drupal::service('plugin.manager.field.widget')
       ->prepareConfiguration($field_type, []);
-    /** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $entity_form_display */
+
+    // @todo Replace entity_get_form_display() when #2367933 is done.
+    // https://www.drupal.org/node/2872159.
     $entity_form_display = entity_get_form_display('media', $media_type_id, 'default');
     $entity_form_display->setComponent($field_name, $component)
       ->save();
+
+    // Use the default formatter and settings.
+    $component = \Drupal::service('plugin.manager.field.formatter')
+      ->prepareConfiguration($field_type, []);
+
+    // @todo Replace entity_get_display() when #2367933 is done.
+    // https://www.drupal.org/node/2872159.
+    $entity_display = entity_get_display('media', $media_type_id, 'default');
+    $entity_display->setComponent($field_name, $component)
+      ->save();
   }
 
   /**
diff --git a/core/modules/media/tests/src/FunctionalJavascript/MediaUiJavascriptTest.php b/core/modules/media/tests/src/FunctionalJavascript/MediaUiJavascriptTest.php
index bb49fefc560d..b150f894da70 100644
--- a/core/modules/media/tests/src/FunctionalJavascript/MediaUiJavascriptTest.php
+++ b/core/modules/media/tests/src/FunctionalJavascript/MediaUiJavascriptTest.php
@@ -42,6 +42,7 @@ protected function setUp() {
     // We need to test without any default configuration in place.
     // @TODO: Remove this as part of https://www.drupal.org/node/2883813.
     MediaType::load('file')->delete();
+    MediaType::load('image')->delete();
   }
 
   /**
diff --git a/core/modules/media/tests/src/Kernel/MediaSourceFileTest.php b/core/modules/media/tests/src/Kernel/MediaSourceFileTest.php
index 9ad6916a38b4..d716e15b40c2 100644
--- a/core/modules/media/tests/src/Kernel/MediaSourceFileTest.php
+++ b/core/modules/media/tests/src/Kernel/MediaSourceFileTest.php
@@ -20,6 +20,7 @@ protected function setUp() {
     // We need to test without any default configuration in place.
     // @TODO: Remove this as part of https://www.drupal.org/node/2883813.
     MediaType::load('file')->delete();
+    MediaType::load('image')->delete();
   }
 
   /**
-- 
GitLab