You are here

class Exif in File metadata manager 8

Same name and namespace in other branches
  1. 8.2 file_mdm_exif/src/Plugin/FileMetadata/Exif.php \Drupal\file_mdm_exif\Plugin\FileMetadata\Exif

FileMetadata plugin for EXIF.

Plugin annotation


@FileMetadata(
  id = "exif",
  title = @Translation("EXIF"),
  help = @Translation("File metadata plugin for EXIF image information, using the PHP Exif Library (PEL)."),
)

Hierarchy

Expanded class hierarchy of Exif

1 string reference to 'Exif'
file_mdm_exif.file_metadata_plugin.exif.yml in file_mdm_exif/config/install/file_mdm_exif.file_metadata_plugin.exif.yml
file_mdm_exif/config/install/file_mdm_exif.file_metadata_plugin.exif.yml

File

file_mdm_exif/src/Plugin/FileMetadata/Exif.php, line 26

Namespace

Drupal\file_mdm_exif\Plugin\FileMetadata
View source
class Exif extends FileMetadataPluginBase {

  /**
   * The MIME type guessing service.
   *
   * @var \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface
   */
  protected $mimeTypeGuesser;

  /**
   * The EXIF tag mapping service.
   *
   * @var \Drupal\file_mdm_exif\ExifTagMapperInterface
   */
  protected $tagMapper;

  /**
   * The PEL file object being processed.
   *
   * @var \lsolesen\pel\PelJpeg|\lsolesen\pel\PelTiff
   */
  protected $pelFile;

  /**
   * Constructs an Exif file metadata plugin.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param array $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_service
   *   The cache service.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The config factory.
   * @param \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface $mime_type_guesser
   *   The MIME type mapping service.
   * @param \Drupal\file_mdm_exif\ExifTagMapperInterface $tag_mapper
   *   The EXIF tag mapping service.
   */
  public function __construct(array $configuration, $plugin_id, array $plugin_definition, CacheBackendInterface $cache_service, ConfigFactoryInterface $config_factory, MimeTypeGuesserInterface $mime_type_guesser, ExifTagMapperInterface $tag_mapper) {
    parent::__construct($configuration, $plugin_id, $plugin_definition, $cache_service, $config_factory);
    $this->mimeTypeGuesser = $mime_type_guesser;
    $this->tagMapper = $tag_mapper;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static($configuration, $plugin_id, $plugin_definition, $container
      ->get('cache.file_mdm'), $container
      ->get('config.factory'), $container
      ->get('file.mime_type.guesser'), $container
      ->get('file_mdm_exif.tag_mapper'));
  }

  /**
   * {@inheritdoc}
   */
  public function getSupportedKeys($options = NULL) {
    return $this->tagMapper
      ->getSupportedKeys($options);
  }

  /**
   * Returns the PEL file object for the image file.
   *
   * @return \lsolesen\pel\PelJpeg|\lsolesen\pel\PelTiff
   *   A PEL file object.
   */
  protected function getFile() {
    if ($this->pelFile !== NULL) {
      return $this->pelFile;
    }
    else {
      switch ($this->mimeTypeGuesser
        ->guess($this
        ->getUri())) {
        case 'image/jpeg':
          $this->pelFile = new PelJpeg($this
            ->getLocalTempPath());
          return $this->pelFile !== NULL ? $this->pelFile : FALSE;
        case 'image/tiff':
          $this->pelFile = new PelTiff($this
            ->getLocalTempPath());
          return $this->pelFile !== NULL ? $this->pelFile : FALSE;
        default:
          return FALSE;
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  protected function doGetMetadataFromFile() {

    // Get the file as a PelJpeg or PelTiff object.
    $file = $this
      ->getFile();
    if (!$file) {
      return [];
    }

    // Get the TIFF section if existing, or return if not.
    if ($file instanceof PelJpeg) {
      $exif = $file
        ->getExif();
      if ($exif === NULL) {
        return [];
      }
      $tiff = $exif
        ->getTiff();
      if ($tiff === NULL) {
        return [];
      }
    }
    elseif ($file instanceof PelTiff) {
      $tiff = $file;
    }

    // Scans metadata for entries of supported tags.
    $metadata = [];
    $keys = $this->tagMapper
      ->getSupportedKeys();
    foreach ($keys as $key) {
      $ifd_tag = $this->tagMapper
        ->resolveKeyToIfdAndTag($key);
      if ($entry = $this
        ->getEntry($tiff, $ifd_tag['ifd'], $ifd_tag['tag'])) {
        $metadata[$ifd_tag['ifd']][$ifd_tag['tag']] = $entry;
      }
    }
    return $metadata;
  }

  /**
   * Returns a PelEntry.
   *
   * @param \lsolesen\pel\PelTiff $tiff
   *   A PelTiff object.
   * @param int $ifd_tag
   *   The IFD EXIF integer identifier.
   * @param int $key_tag
   *   The TAG EXIF integer identifier.
   *
   * @return \lsolesen\pel\PelEntry
   *   The PelEntry for the specified IFD and TAG.
   */
  protected function getEntry(PelTiff $tiff, $ifd_tag, $key_tag) {
    $ifd = $tiff
      ->getIfd();
    switch ($ifd_tag) {
      case PelIfd::IFD0:
        return $ifd
          ->getEntry($key_tag);
      case PelIfd::IFD1:
        $ifd1 = $ifd
          ->getNextIfd();
        if (!$ifd1) {
          return NULL;
        }
        return $ifd1
          ->getEntry($key_tag);
      case PelIfd::EXIF:
        $exif = $ifd
          ->getSubIfd(PelIfd::EXIF);
        if (!$exif) {
          return NULL;
        }
        return $exif
          ->getEntry($key_tag);
      case PelIfd::INTEROPERABILITY:
        $exif = $ifd
          ->getSubIfd(PelIfd::EXIF);
        if (!$exif) {
          return NULL;
        }
        $interop = $exif
          ->getSubIfd(PelIfd::INTEROPERABILITY);
        if (!$interop) {
          return NULL;
        }
        return $interop
          ->getEntry($key_tag);
      case PelIfd::GPS:
        $gps = $ifd
          ->getSubIfd(PelIfd::GPS);
        if (!$gps) {
          return NULL;
        }
        return $gps
          ->getEntry($key_tag);
    }
  }

  /**
   * {@inheritdoc}
   */
  public function isSaveToFileSupported() {
    return TRUE;
  }

  /**
   * {@inheritdoc}
   */
  protected function doSaveMetadataToFile() {

    // Get the file as a PelJpeg or PelTiff object.
    $file = $this
      ->getFile();
    if (!$file) {
      return FALSE;
    }

    // Get the TIFF section if existing, or create one if not.
    if ($file instanceof PelJpeg) {
      $exif = $file
        ->getExif();
      if ($exif === NULL) {

        // If EXIF section is missing we simply create a new APP1 section
        // (a PelExif object) and add it to the PelJpeg object.
        $exif = new PelExif();
        $file
          ->setExif($exif);
      }
      $tiff = $exif
        ->getTiff();
      if ($tiff === NULL) {

        // Same for TIFF section.
        $tiff = new PelTiff();
        $exif
          ->setTiff($tiff);
      }
    }
    elseif ($file instanceof PelTiff) {
      $tiff = $file;
    }

    // Get IFD0 if existing, or create it if not.
    $ifd0 = $tiff
      ->getIfd();
    if ($ifd0 === NULL) {

      // No IFD in the TIFF data, we just create and insert an empty PelIfd
      // object.
      $ifd0 = new PelIfd(PelIfd::IFD0);
      $tiff
        ->setIfd($ifd0);
    }

    // Loops through in-memory metadata and update tag entries accordingly.
    foreach ($this->metadata as $ifd_id => $entries) {
      switch ($ifd_id) {
        case PelIfd::IFD0:
          $this
            ->setIfdEntries($ifd0, $entries);
          break;
        case PelIfd::IFD1:
          $ifd1 = $ifd0
            ->getNextIfd();
          if ($ifd1 === NULL) {
            $ifd1 = new PelIfd(PelIfd::IFD1);
            $ifd0
              ->setNextIfd($ifd1);
          }
          $this
            ->setIfdEntries($ifd1, $entries);
          break;
        case PelIfd::EXIF:
          $exif = $ifd0
            ->getSubIfd(PelIfd::EXIF);
          if ($exif === NULL) {
            $exif = new PelIfd(PelIfd::EXIF);
            $ifd0
              ->addSubIfd($exif);
          }
          $this
            ->setIfdEntries($exif, $entries);
          break;
        case PelIfd::INTEROPERABILITY:
          $exif = $ifd0
            ->getSubIfd(PelIfd::EXIF);
          if ($exif === NULL) {
            $exif = new PelIfd(PelIfd::EXIF);
            $ifd0
              ->addSubIfd($exif);
          }
          $interop = $exif
            ->getSubIfd(PelIfd::INTEROPERABILITY);
          if ($interop === NULL) {
            $interop = new PelIfd(PelIfd::INTEROPERABILITY);
            $exif
              ->addSubIfd($interop);
          }
          $this
            ->setIfdEntries($interop, $entries);
          break;
        case PelIfd::GPS:
          $gps = $ifd0
            ->getSubIfd(PelIfd::GPS);
          if ($gps === NULL) {
            $gps = new PelIfd(PelIfd::GPS);
            $ifd0
              ->addSubIfd($gps);
          }
          $this
            ->setIfdEntries($gps, $entries);
          break;
      }
    }
    return $file
      ->saveFile($this
      ->getLocalTempPath()) === FALSE ? FALSE : TRUE;
  }

  /**
   * Adds or changes entries for an IFD.
   *
   * @param lsolesen\pel\PelIfd $ifd
   *   A PelIfd object.
   * @param lsolesen\pel\PelEntry[] $entries
   *   An array of PelEntry objects.
   *
   * @return bool
   *   TRUE if entries were added/changed successfully, FALSE otherwise.
   */
  protected function setIfdEntries(PelIfd $ifd, array $entries) {
    foreach ($entries as $tag => $input_entry) {
      if ($c = $ifd
        ->getEntry($tag)) {
        if ($input_entry === 'deleted') {
          unset($ifd[$tag]);
        }
        else {
          $c
            ->setValue($input_entry
            ->getValue());
        }
      }
      else {
        if ($input_entry !== 'deleted') {
          $ifd
            ->addEntry($input_entry);
        }
      }
    }
    return TRUE;
  }

  /**
   * {@inheritdoc}
   */
  protected function doGetMetadata($key = NULL) {
    if (!$this->metadata) {
      return NULL;
    }
    if (!$key) {
      return $this->metadata;
    }
    else {
      $ifd_tag = $this->tagMapper
        ->resolveKeyToIfdAndTag($key);
      if (!isset($this->metadata[$ifd_tag['ifd']][$ifd_tag['tag']]) || $this->metadata[$ifd_tag['ifd']][$ifd_tag['tag']] === 'deleted') {
        return NULL;
      }
      $entry = $this->metadata[$ifd_tag['ifd']][$ifd_tag['tag']];
      return [
        'value' => $entry
          ->getValue(),
        'text' => $entry
          ->getText(),
      ];
    }
  }

  /**
   * {@inheritdoc}
   */
  protected function doSetMetadata($key, $value) {
    $ifd_tag = $this->tagMapper
      ->resolveKeyToIfdAndTag($key);
    if ($value instanceof PelEntry) {
      $this->metadata[$ifd_tag['ifd']][$ifd_tag['tag']] = $value;
      return TRUE;
    }
    elseif (isset($this->metadata[$ifd_tag['ifd']][$ifd_tag['tag']])) {
      $this->metadata[$ifd_tag['ifd']][$ifd_tag['tag']]
        ->setValue($value);
      return TRUE;
    }
    return FALSE;
  }

  /**
   * {@inheritdoc}
   */
  protected function doRemoveMetadata($key) {
    if (!$this->metadata || !$key) {
      return FALSE;
    }
    else {
      $ifd_tag = $this->tagMapper
        ->resolveKeyToIfdAndTag($key);
      if (isset($this->metadata[$ifd_tag['ifd']][$ifd_tag['tag']])) {
        $this->metadata[$ifd_tag['ifd']][$ifd_tag['tag']] = 'deleted';
        return TRUE;
      }
      return FALSE;
    }
  }

}

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
Exif::$mimeTypeGuesser protected property The MIME type guessing service.
Exif::$pelFile protected property The PEL file object being processed.
Exif::$tagMapper protected property The EXIF tag mapping service.
Exif::create public static function Creates an instance of the plugin. Overrides FileMetadataPluginBase::create
Exif::doGetMetadata protected function Gets a metadata element. Overrides FileMetadataPluginBase::doGetMetadata
Exif::doGetMetadataFromFile protected function Gets file metadata from the file at URI/local path. Overrides FileMetadataPluginBase::doGetMetadataFromFile
Exif::doRemoveMetadata protected function Removes a metadata element. Overrides FileMetadataPluginBase::doRemoveMetadata
Exif::doSaveMetadataToFile protected function Saves metadata to file at URI. Overrides FileMetadataPluginBase::doSaveMetadataToFile
Exif::doSetMetadata protected function Sets a metadata element. Overrides FileMetadataPluginBase::doSetMetadata
Exif::getEntry protected function Returns a PelEntry.
Exif::getFile protected function Returns the PEL file object for the image file.
Exif::getSupportedKeys public function Returns a list of metadata keys supported by the plugin. Overrides FileMetadataPluginInterface::getSupportedKeys
Exif::isSaveToFileSupported public function Determines if plugin is capable of writing metadata to files. Overrides FileMetadataPluginBase::isSaveToFileSupported
Exif::setIfdEntries protected function Adds or changes entries for an IFD.
Exif::__construct public function Constructs an Exif file metadata plugin. Overrides FileMetadataPluginBase::__construct
FileMetadataPluginBase::$cache protected property The cache service.
FileMetadataPluginBase::$configFactory protected property The config factory.
FileMetadataPluginBase::$hash protected property The hash used to reference the URI.
FileMetadataPluginBase::$hasMetadataChangedFromCacheVersion protected property Track if file metadata on cache needs update.
FileMetadataPluginBase::$hasMetadataChangedFromFileVersion protected property Track if metadata has been changed from version on file.
FileMetadataPluginBase::$isMetadataLoaded protected property The metadata loading status.
FileMetadataPluginBase::$localTempPath protected property The local filesystem path to the file.
FileMetadataPluginBase::$metadata protected property The metadata of the file.
FileMetadataPluginBase::$uri protected property The URI of the file.
FileMetadataPluginBase::buildConfigurationForm public function Form constructor. Overrides PluginFormInterface::buildConfigurationForm
FileMetadataPluginBase::defaultConfiguration public static function Gets default configuration for this plugin. Overrides FileMetadataPluginInterface::defaultConfiguration
FileMetadataPluginBase::deleteCachedMetadata public function Removes cached metadata for file at URI. Overrides FileMetadataPluginInterface::deleteCachedMetadata
FileMetadataPluginBase::getConfigObject protected function Gets the configuration object for this plugin.
FileMetadataPluginBase::getLocalTempPath public function Gets the local filesystem path to the file. Overrides FileMetadataPluginInterface::getLocalTempPath
FileMetadataPluginBase::getMetadata public function Gets a metadata element. Overrides FileMetadataPluginInterface::getMetadata
FileMetadataPluginBase::getMetadataToCache protected function Gets metadata to save to cache.
FileMetadataPluginBase::getUri public function Gets the URI of the file. Overrides FileMetadataPluginInterface::getUri
FileMetadataPluginBase::isMetadataLoaded public function Checks if file metadata has been already loaded. Overrides FileMetadataPluginInterface::isMetadataLoaded
FileMetadataPluginBase::isUriFileMetadataCacheable protected function Checks if file metadata should be cached.
FileMetadataPluginBase::loadMetadata public function Loads file metadata from an in-memory object/array. Overrides FileMetadataPluginInterface::loadMetadata
FileMetadataPluginBase::loadMetadataFromCache public function Loads file metadata from a cache entry. Overrides FileMetadataPluginInterface::loadMetadataFromCache
FileMetadataPluginBase::loadMetadataFromFile public function Loads file metadata from the file at URI/local path. Overrides FileMetadataPluginInterface::loadMetadataFromFile
FileMetadataPluginBase::removeMetadata public function Removes a metadata element. Overrides FileMetadataPluginInterface::removeMetadata
FileMetadataPluginBase::saveMetadataToCache public function Caches metadata for file at URI. Overrides FileMetadataPluginInterface::saveMetadataToCache
FileMetadataPluginBase::saveMetadataToFile public function Saves metadata to file at URI. Overrides FileMetadataPluginInterface::saveMetadataToFile
FileMetadataPluginBase::setHash public function Sets the hash used to reference the URI by the metadata manager. Overrides FileMetadataPluginInterface::setHash
FileMetadataPluginBase::setLocalTempPath public function Sets the local filesystem path to the file. Overrides FileMetadataPluginInterface::setLocalTempPath
FileMetadataPluginBase::setMetadata public function Sets a metadata element. Overrides FileMetadataPluginInterface::setMetadata
FileMetadataPluginBase::setUri public function Sets the URI of the file. Overrides FileMetadataPluginInterface::setUri
FileMetadataPluginBase::submitConfigurationForm public function Form submission handler. Overrides PluginFormInterface::submitConfigurationForm
FileMetadataPluginBase::validateConfigurationForm public function Form validation handler. Overrides PluginFormInterface::validateConfigurationForm
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.