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; } } }