diff --git a/core/modules/image/src/Plugin/Filter/FilterImageStyle.php b/core/modules/image/src/Plugin/Filter/FilterImageStyle.php
new file mode 100644
index 0000000..dd04459
--- /dev/null
+++ b/core/modules/image/src/Plugin/Filter/FilterImageStyle.php
@@ -0,0 +1,326 @@
+entityTypeManager = $entity_type_manager;
+ $this->entityRepository = $entity_repository;
+ $this->imageFactory = $image_factory;
+ $this->renderer = $renderer;
+ }
+
+ /**
+ * {@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.repository'),
+ $container->get('image.factory'),
+ $container->get('renderer')
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function process($text, $langcode) {
+ if (stristr($text, 'data-image-style') !== FALSE) {
+ // Load all image styles so each image found in the text can be checked
+ // against a valid image style.
+ $image_styles = $this->getAllowedImageStyleIds();
+
+ $dom = Html::load($text);
+ $xpath = new \DOMXPath($dom);
+
+ // Process each image element found with the necessary attributes.
+ /** @var \DOMElement $dom_element */
+ foreach ($xpath->query('//*[@data-entity-type="file" and @data-entity-uuid and @data-image-style]') as $dom_element) {
+ // Get the UUID and image style for the file.
+ $file_uuid = $dom_element->getAttribute('data-entity-uuid');
+ $image_style_id = $dom_element->getAttribute('data-image-style');
+
+ // If the image style is not a valid one, then don't transform the HTML.
+ if (empty($file_uuid) || !in_array($image_style_id, $image_styles)) {
+ continue;
+ }
+
+ /** @var \Drupal\file\FileInterface $file */
+ $file = $this->entityRepository->loadEntityByUuid('file', $file_uuid);
+
+ if (!$file) {
+ continue;
+ }
+
+ // Transform the HTML for the img element by applying an image style.
+ $altered_img_markup = $this->getImageStyleHtml($file_uuid, $image_style_id, $dom_element);
+ $altered_img = $dom->createDocumentFragment();
+ $altered_img->appendXML($altered_img_markup);
+ $dom_element->parentNode->replaceChild($altered_img, $dom_element);
+ }
+
+ return new FilterProcessResult(Html::serialize($dom));
+ }
+
+ // Process the filter if no image style img elements are found.
+ return new FilterProcessResult($text);
+ }
+
+ /**
+ * Loads image styles.
+ *
+ * @param array $ids
+ * Optional array of image style IDs to load. If omitted, all image styles
+ * will be returned.
+ *
+ * @return \Drupal\image\ImageStyleInterface[]
+ * The image styles.
+ */
+ protected function loadImageStyles(array $ids = NULL) {
+ return $this->entityTypeManager->getStorage('image_style')->loadMultiple($ids);
+ }
+
+ /**
+ * Returns the machine names of the allowed image styles.
+ *
+ * @return string[]
+ * The machine names of the allowed image styles.
+ */
+ protected function getAllowedImageStyleIds() {
+ if (!empty($this->settings['allowed_styles'])) {
+ return $this->settings['allowed_styles'];
+ }
+ // If no image styles are selected, then all are allowed.
+ return array_keys($this->loadImageStyles());
+ }
+
+ /**
+ * Returns the allowed image styles.
+ *
+ * @return \Drupal\image\ImageStyleInterface[]
+ * The allowed image styles.
+ */
+ public function getAllowedImageStyles() {
+ $ids = !empty($this->settings['allowed_styles']) ? $this->settings['allowed_styles'] : NULL;
+ return $this->loadImageStyles($ids);
+ }
+
+ /**
+ * Gets the the width and height of an image based on the file UUID.
+ *
+ * @param string $file_uuid
+ * The UUID for the file.
+ *
+ * @return array
+ * The image information.
+ */
+ protected function getImageInfo($file_uuid) {
+ /** @var \Drupal\file\FileInterface $file */
+ $file = $this->entityRepository->loadEntityByUuid('file', $file_uuid);
+
+ // Determine uri, width and height of the source image.
+ $image_uri = $image_width = $image_height = NULL;
+ $image = $this->imageFactory->get($file->getFileUri());
+ if ($image->isValid()) {
+ $image_uri = $file->getFileUri();
+ $image_width = $image->getWidth();
+ $image_height = $image->getHeight();
+ }
+
+ return [
+ 'uri' => $image_uri,
+ 'width' => $image_width,
+ 'height' => $image_height,
+ ];
+ }
+
+ /**
+ * Removes attributes that will be generated from image style theme function.
+ *
+ * @param \DOMElement $dom_element
+ * The DOM element for the img element.
+ *
+ * @return array
+ * The attributes array.
+ */
+ protected function prepareImageAttributes(\DOMElement $dom_element) {
+ // Remove attributes that are generated by the image style.
+ $dom_element->removeAttribute('width');
+ $dom_element->removeAttribute('height');
+ $dom_element->removeAttribute('src');
+
+ // Make sure all non-regenerated attributes are retained.
+ $attributes = [];
+ for ($i = 0; $i < $dom_element->attributes->length; $i++) {
+ $attr = $dom_element->attributes->item($i);
+ $attributes[$attr->name] = $attr->value;
+ }
+
+ return $attributes;
+ }
+
+ /**
+ * Gets the HTML for the image element after image style is applied.
+ *
+ * @param string $file_uuid
+ * The UUID for the file.
+ * @param string $image_style_id
+ * The ID for the image style.
+ * @param \DOMElement $dom_element
+ * The DOM element for the image element.
+ *
+ * @return string
+ * The img element with the image style applied.
+ */
+ protected function getImageStyleHtml($file_uuid, $image_style_id, \DOMElement $dom_element) {
+ $image_info = $this->getImageInfo($file_uuid);
+
+ // Remove attributes that will be generated by the image style.
+ $attributes = $this->prepareImageAttributes($dom_element);
+
+ // Re-render as an image style.
+ $image = [
+ '#theme' => 'image_style',
+ '#style_name' => $image_style_id,
+ '#uri' => $image_info['uri'],
+ '#width' => $image_info['width'],
+ '#height' => $image_info['height'],
+ '#attributes' => $attributes,
+ ];
+
+ $output = $this->renderer->executeInRenderContext(new RenderContext(), function () use (&$image) {
+ return $this->renderer->render($image);
+ });
+
+ return $output;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function settingsForm(array $form, FormStateInterface $form_state) {
+ $image_styles = $this->loadImageStyles();
+ $options = array_map(function (ImageStyleInterface $image_style) {
+ return $image_style->label();
+ }, $image_styles);
+ $form['allowed_styles'] = [
+ '#type' => 'select',
+ '#title' => $this->t('Allowed image styles'),
+ '#options' => $options,
+ '#default_value' => $this->settings['allowed_styles'],
+ '#description' => $this->t('The image styles that can be used. If none are selected then all image styles can be used.'),
+ '#multiple' => TRUE,
+ // Limit the select box in length if there are a large number of image
+ // styles.
+ '#size' => min(20, count($image_styles)),
+ ];
+ return $form;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function calculateDependencies() {
+ $dependencies = parent::calculateDependencies();
+
+ // Add the image styles that are allowed by this filter as dependencies.
+ foreach ($this->getAllowedImageStyles() as $image_style) {
+ $dependencies[$image_style->getConfigDependencyKey()][] = $image_style->getConfigDependencyName();
+ }
+ return $dependencies;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function tips($long = FALSE) {
+ if ($long) {
+ $image_styles = $this->getAllowedImageStyleIds();
+ $list = new TranslatableMarkup('' . implode('
, ', $image_styles) . '
');
+ return t('
You can display images using site-wide styles by adding a data-image-style
attribute, whose values is one of the image style machine names: @image-style-machine-name-list.