You are here

class FilterImageResize in Image Resize Filter 8

Provides a filter to resize images.

Plugin annotation


@Filter(
  id = "filter_image_resize",
  title = @Translation("Image Resize Filter: Resize images based on their given height and width attributes"),
  description = @Translation("Analyze the <img> tags and compare the given height and width attributes to the actual file. If the file dimensions are different than those given in the <img> tag, the image will be copied and the src attribute will be updated to point to the resized image."),
  type = Drupal\filter\Plugin\FilterInterface::TYPE_TRANSFORM_REVERSIBLE,
  settings = {
    "image_locations" = {
       "local" = 1,
       "remote" = 0
  },
  }
)

Hierarchy

Expanded class hierarchy of FilterImageResize

File

src/Plugin/Filter/FilterImageResize.php, line 31

Namespace

Drupal\image_resize_filter\Plugin\Filter
View source
class FilterImageResize extends FilterBase implements ContainerFactoryPluginInterface {

  /**
   * ImageFactory instance.
   *
   * @var \Drupal\Core\Image\ImageFactory
   */
  protected $imageFactory;

  /**
   * @var \Drupal\Core\Config\ImmutableConfig
   */
  protected $systemFileConfig;

  /**
   * The stream wrapper manager.
   *
   * @var \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface
   */
  protected $streamWrapperManager;

  /**
   * The file system.
   *
   * @var \Drupal\Core\File\FileSystemInterface
   */
  protected $fileSystem;

  /**
   * FilterImageResize constructor.
   * @param array $configuration
   * @param string $plugin_id
   * @param mixed $plugin_definition
   * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
   *   The entity Repository.
   * @param \Drupal\Core\Image\ImageFactory $image_factory
   *   Image Factory.
   * @param \Drupal\Core\Config\Config $system_file_config
   *   The system file configuration.
   * @param \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $stream_wrapper_manager
   *   The stream wrapper manager.
   * @param \Drupal\Core\File\FileSystemInterface $file_system
   *   The file system.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, ImageFactory $image_factory, Config $system_file_config, StreamWrapperManagerInterface $stream_wrapper_manager, FileSystemInterface $file_system) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->imageFactory = $image_factory;
    $this->systemFileConfig = $system_file_config;
    $this->streamWrapperManager = $stream_wrapper_manager;
    $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('image.factory'), $container
      ->get('config.factory')
      ->get('system.file'), $container
      ->get('stream_wrapper_manager'), $container
      ->get('file_system'));
  }

  /**
   * {@inheritdoc}
   */
  public function process($text, $langcode) {
    return new FilterProcessResult($this
      ->getImages($text));
  }

  /**
   * Locate all images in a piece of text that need replacing.
   *
   *   An array of settings that will be used to identify which images need
   *   updating. Includes the following:
   *
   *   - image_locations: An array of acceptable image locations.
   *     of the following values: "remote". Remote image will be downloaded and
   *     saved locally. This procedure is intensive as the images need to
   *     be retrieved to have their dimensions checked.
   *
   * @param string $text
   *   The text to be updated with the new img src tags.
   *
   * @return string $images
   *   An list of images.
   */
  private function getImages($text) {
    $images = image_resize_filter_get_images($this->settings, $text);
    $search = [];
    $replace = [];
    foreach ($images as $image) {

      // Copy remote images locally.
      if ($image['location'] == 'remote') {
        $local_file_path = 'resize/remote/' . md5(file_get_contents($image['local_path'])) . '-' . $image['expected_size']['width'] . 'x' . $image['expected_size']['height'] . '.' . $image['extension'];

        // Once Drupal 8.7.x is unsupported remove this IF statement.
        if (floatval(\Drupal::VERSION) >= 8.800000000000001) {
          $image['destination'] = $this->systemFileConfig
            ->get('default_scheme') . '://' . $local_file_path;
        }
        else {
          $image['destination'] = file_default_scheme() . '://' . $local_file_path;
        }
      }
      elseif (!$image['resize']) {
        $image['destination'] = $image['local_path'];
      }
      else {
        $path_info = image_resize_filter_pathinfo($image['local_path']);

        // Once Drupal 8.7.x is unsupported remove this IF statement.
        if (floatval(\Drupal::VERSION) >= 8.800000000000001) {
          $local_file_dir = $this->streamWrapperManager
            ->getTarget($path_info['dirname']);
        }
        else {
          $local_file_dir = file_uri_target($path_info['dirname']);
        }
        $local_file_path = 'resize/' . ($local_file_dir ? $local_file_dir . '/' : '') . $path_info['filename'] . '-' . $image['expected_size']['width'] . 'x' . $image['expected_size']['height'] . '.' . $path_info['extension'];
        $image['destination'] = $path_info['scheme'] . '://' . $local_file_path;
      }
      if (!file_exists($image['destination'])) {

        // Basic flood prevention of resizing.
        $resize_threshold = 10;
        $flood = \Drupal::flood();
        if (!$flood
          ->isAllowed('image_resize_filter_resize', $resize_threshold, 120)) {
          $this->messenger
            ->addMessage(t('Image resize threshold of @count per minute reached. Some images have not been resized. Resave the content to resize remaining images.', [
            '@count' => floor($resize_threshold / 2),
          ]), 'error', FALSE);
          continue;
        }
        $flood
          ->register('image_resize_filter_resize', 120);

        // Create the resize directory.
        $directory = dirname($image['destination']);
        $this->fileSystem
          ->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY);

        // Move remote images into place if they are already the right size.
        if ($image['location'] == 'remote' && !$image['resize']) {
          $handle = fopen($image['destination'], 'w');
          fwrite($handle, file_get_contents($image['local_path']));
          fclose($handle);
        }
        elseif ($image['resize']) {
          $copy = $this->fileSystem
            ->copy($image['local_path'], $image['destination']);
          $res = $this->imageFactory
            ->get($copy);
          if ($res) {

            // Image loaded successfully; resize.
            $res
              ->resize($image['expected_size']['width'], $image['expected_size']['height']);
            $res
              ->save();
          }
          else {

            // Image failed to load - type doesn't match extension or invalid; keep original file
            $handle = fopen($image['destination'], 'w');
            fwrite($handle, file_get_contents($image['local_path']));
            fclose($handle);
          }
        }
        @chmod($image['destination'], 0664);
      }

      // Delete our temporary file if this is a remote image.
      image_resize_filter_delete_temp_file($image['location'], $image['local_path']);

      // Replace the existing image source with the resized image.
      // Set the image we're currently updating in the callback function.
      $search[] = $image['img_tag'];
      $replace[] = image_resize_filter_image_tag($image, $this->settings);
    }
    return str_replace($search, $replace, $text);
  }

  /**
   * {@inheritdoc}
   */
  function settingsForm(array $form, FormStateInterface $form_state) {
    $settings['image_locations'] = [
      '#type' => 'checkboxes',
      '#title' => $this
        ->t('Resize images stored'),
      '#options' => [
        'local' => $this
          ->t('Locally'),
        'remote' => $this
          ->t('On remote servers (note: this copies <em>all</em> remote images locally)'),
      ],
      '#default_value' => array_keys(array_filter($this->settings['image_locations'])),
      '#description' => $this
        ->t('This option will determine which images will be analyzed for &lt;img&gt; tag differences. Enabling resizing of remote images can have performance impacts, as all images in the filtered text needs to be transferred via HTTP each time the filter cache is cleared.'),
    ];
    return $settings;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
FilterBase::$provider public property The name of the provider that owns this filter.
FilterBase::$settings public property An associative array containing the configured settings of this filter.
FilterBase::$status public property A Boolean indicating whether this filter is enabled.
FilterBase::$weight public property The weight of this filter compared to others in a filter collection.
FilterBase::calculateDependencies public function Calculates dependencies for the configured plugin. Overrides DependentPluginInterface::calculateDependencies 1
FilterBase::defaultConfiguration public function Gets default configuration for this plugin. Overrides ConfigurableInterface::defaultConfiguration
FilterBase::getConfiguration public function Gets this plugin's configuration. Overrides ConfigurableInterface::getConfiguration
FilterBase::getDescription public function Returns the administrative description for this filter plugin. Overrides FilterInterface::getDescription
FilterBase::getHTMLRestrictions public function Returns HTML allowed by this filter's configuration. Overrides FilterInterface::getHTMLRestrictions 4
FilterBase::getLabel public function Returns the administrative label for this filter plugin. Overrides FilterInterface::getLabel
FilterBase::getType public function Returns the processing type of this filter plugin. Overrides FilterInterface::getType
FilterBase::prepare public function Prepares the text for processing. Overrides FilterInterface::prepare
FilterBase::setConfiguration public function Sets the configuration for this plugin instance. Overrides ConfigurableInterface::setConfiguration 1
FilterBase::tips public function Generates a filter's tip. Overrides FilterInterface::tips 9
FilterImageResize::$fileSystem protected property The file system.
FilterImageResize::$imageFactory protected property ImageFactory instance.
FilterImageResize::$streamWrapperManager protected property The stream wrapper manager.
FilterImageResize::$systemFileConfig protected property
FilterImageResize::create public static function Creates an instance of the plugin. Overrides ContainerFactoryPluginInterface::create
FilterImageResize::getImages private function Locate all images in a piece of text that need replacing.
FilterImageResize::process public function Performs the filter processing. Overrides FilterInterface::process
FilterImageResize::settingsForm function Generates a filter's settings form. Overrides FilterBase::settingsForm
FilterImageResize::__construct public function FilterImageResize constructor. Overrides FilterBase::__construct
FilterInterface::TYPE_HTML_RESTRICTOR constant HTML tag and attribute restricting filters to prevent XSS attacks.
FilterInterface::TYPE_MARKUP_LANGUAGE constant Non-HTML markup language filters that generate HTML.
FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE constant Irreversible transformation filters.
FilterInterface::TYPE_TRANSFORM_REVERSIBLE constant Reversible transformation filters.
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 3
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::isConfigurable public function Determines if the plugin is configurable.
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.