forked from alxp/islandora
-
Notifications
You must be signed in to change notification settings - Fork 118
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
issue #959: Cache TIFF width and height into fields on File media if they exist #983
Closed
Closed
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
95d3152
Refactor IIIF, create IIIF Info Service.
alxp 13b7400
Islandora IIIF: Add action to retrieve image attributes from IIIF ser…
alxp 4450248
Islandora IIIF: Add auth headers to IIIF Info request.
alxp ba3024d
Islandora IIIF: Change media action to node.
alxp 21d4682
Islandora IIIF: Update README.
alxp 565a1b4
Islandora IIIF: Get image dimensions from field on media if they exist.:
alxp 8c8de83
Islandora IIIF: Address PHPCS errors.
alxp c1b4141
Islandora IIIF: Address PHPCS errors.
alxp 8151059
Islandora IIIF: Address PHPCS errors.
alxp 847fb4f
islandora_iiif: Fix Authorization header syntax.
alxp ec29a45
959-iiif-width-height-caching Islandora IIIF: Add search endpoint con…
alxp 6a1c033
959-iiif-width-height-caching Add handler for ServerException in Isla…
alxp fa7f449
959-iiif-width-height-caching Add option to skip retrieveing TIFF and…
alxp 0b66fba
Checking for width/height on media first when generating IIIF manifest
dannylamb bd327d9
959-iiif-width-height-caching Add IIIF service function to get downla…
alxp File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
modules/islandora_iiif/config/optional/system.action.media_attributes_from_iiif_action.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
langcode: en | ||
status: true | ||
dependencies: | ||
module: | ||
- islandora_iiif | ||
id: media_attributes_from_iiif_action | ||
label: 'Media attributes from IIIF' | ||
type: node | ||
plugin: islandora_iiif:media_attributes_from_iiif_action:media | ||
configuration: { } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<?php | ||
|
||
/** | ||
* @file | ||
* Install/update hook implementations. | ||
*/ | ||
|
||
use Symfony\Component\Yaml\Yaml; | ||
|
||
/** | ||
* Add Media Attributes from IIIF action. | ||
*/ | ||
function islandora_iiif_update_92001(&$sandbox) { | ||
$config_id = 'system.action.media_attributes_from_iiif_action'; | ||
$config_path = \Drupal::service('extension.list.module')->getPath('islandora_iiif') . '/config/optional/' . $config_id . '.yml'; | ||
$data = Yaml::parseFile($config_path); | ||
\Drupal::configFactory()->getEditable($config_id)->setData($data)->save(TRUE); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
services: | ||
islandora_iiif: | ||
class: Drupal\islandora_iiif\IiifInfo | ||
arguments: ['@config.factory', '@http_client', '@logger.channel.islandora', '@jwt.authentication.jwt'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
<?php | ||
|
||
namespace Drupal\islandora_iiif; | ||
|
||
use Drupal\Core\Config\ConfigFactoryInterface; | ||
use Drupal\Core\Logger\LoggerChannelInterface; | ||
use Drupal\file\FileInterface; | ||
use Drupal\jwt\Authentication\Provider\JwtAuth; | ||
|
||
use GuzzleHttp\Client; | ||
use GuzzleHttp\Exception\ClientException; | ||
use GuzzleHttp\Exception\ConnectException; | ||
use GuzzleHttp\Exception\ServerException; | ||
|
||
/** | ||
* Get IIIF related info for a given File or Image entity. | ||
*/ | ||
class IiifInfo { | ||
|
||
/** | ||
* The config factory. | ||
* | ||
* @var \Drupal\Core\Config\ConfigFactoryInterface | ||
*/ | ||
protected $configFactory; | ||
|
||
|
||
/** | ||
* The HTTP client. | ||
* | ||
* @var \GuzzleHttp\Client | ||
*/ | ||
protected $httpClient; | ||
|
||
/** | ||
* This module's config. | ||
* | ||
* @var \Drupal\Core\Config\ImmutableConfig | ||
*/ | ||
protected $iiifConfig; | ||
|
||
/** | ||
* JWT Auth provider service. | ||
* | ||
* @var \Drupal\jwt\Authentication\Provider\JwtAuth | ||
*/ | ||
protected $jwtAuth; | ||
|
||
/** | ||
* The logger. | ||
* | ||
* @var \Drupal\Core\Logger\LoggerChannelInterface | ||
*/ | ||
protected $logger; | ||
|
||
/** | ||
* Constructs an IiifInfo object. | ||
* | ||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory | ||
* The config factory. | ||
* @param \Guzzle\Http\Client $http_client | ||
* The HTTP Client. | ||
* @param \Drupal\Core\Logger\LoggerChannelInterface $channel | ||
* Logger channel. | ||
* @param \Drupal\jwt\Authentication\Provider\JwtAuth $jwt_auth | ||
* The JWT auth provider. | ||
*/ | ||
public function __construct(ConfigFactoryInterface $config_factory, Client $http_client, LoggerChannelInterface $channel, JwtAuth $jwt_auth) { | ||
$this->configFactory = $config_factory; | ||
|
||
$this->iiifConfig = $this->configFactory->get('islandora_iiif.settings'); | ||
$this->httpClient = $http_client; | ||
$this->logger = $channel; | ||
$this->jwtAuth = $jwt_auth; | ||
} | ||
|
||
/** | ||
* The IIIF base URL for an image. | ||
* | ||
* Visiting this URL will resolve to the info.json for the image. | ||
* | ||
* @return string | ||
* The absolute URL on the IIIF server. | ||
*/ | ||
public function baseUrl($image) { | ||
|
||
if ($this->iiifConfig->get('use_relative_paths')) { | ||
$file_url = ltrim($image->createFileUrl(TRUE), '/'); | ||
} | ||
else { | ||
$file_url = $image->createFileUrl(FALSE); | ||
} | ||
|
||
$iiif_address = $this->iiifConfig->get('iiif_server'); | ||
$iiif_url = rtrim($iiif_address, '/') . '/' . urlencode($file_url); | ||
|
||
return $iiif_url; | ||
} | ||
|
||
/** | ||
* Retrieve an image's original dimensions via the IIIF server. | ||
* | ||
* @param \Drupal\File\FileInterface $file | ||
* The image file. | ||
* | ||
* @return array|false | ||
* The image dimensions in an array as [$width, $height] | ||
*/ | ||
public function getImageDimensions(FileInterface $file) { | ||
$iiif_url = $this->baseUrl($file); | ||
try { | ||
$info_json = $this->httpClient->request('get', $iiif_url, [ | ||
'headers' => [ | ||
'Authorization' => 'Bearer ' . $this->jwtAuth->generateToken(), | ||
], | ||
])->getBody(); | ||
$resource = json_decode($info_json, TRUE); | ||
$width = $resource['width']; | ||
$height = $resource['height']; | ||
if (is_numeric($width) && is_numeric($height)) { | ||
return [intval($width), intval($height)]; | ||
} | ||
} | ||
catch (ClientException | ConnectException | ServerException $e) { | ||
alxp marked this conversation as resolved.
Show resolved
Hide resolved
|
||
$this->logger->info("Error getting image file dimensions from IIIF server: " . $e->getMessage()); | ||
} | ||
return FALSE; | ||
} | ||
|
||
/** | ||
* The IIIF base URL for an image. | ||
* | ||
* Visiting this URL will resolve to the full image resized to the maximum dimensions given. | ||
* | ||
* @see https://iiif.io/api/image/2.1/ | ||
* | ||
* @param Drupal\file\FileInterface $image | ||
* The image entity. | ||
* @param int width | ||
* The maximum width of the image to be returned. 0 for no constraint. | ||
* @param int $height | ||
* The maxim um height of the image to be returned. 0 for no contraint. | ||
* | ||
* @return string | ||
* The IIIF URl to retrieve the full image with the given max dimensions. | ||
*/ | ||
public function getImageWithMaxDimensions($image, $width = 0, $height = 0) { | ||
$base_url = $this->baseUrl($image); | ||
return $base_url . "/full/!$width,$height/0/default.jpg"; | ||
|
||
} | ||
|
||
} |
165 changes: 165 additions & 0 deletions
165
modules/islandora_iiif/src/Plugin/Action/MediaAttributesFromIiif.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
<?php | ||
|
||
namespace Drupal\islandora_iiif\Plugin\Action; | ||
|
||
use Drupal\Component\Datetime\TimeInterface; | ||
use Drupal\Core\Action\Plugin\Action\SaveAction; | ||
use Drupal\Core\Entity\EntityTypeManagerInterface; | ||
use Drupal\Core\Logger\LoggerChannelInterface; | ||
use Drupal\Core\Session\AccountInterface; | ||
use Drupal\islandora\IslandoraUtils; | ||
use Drupal\islandora\MediaSource\MediaSourceService; | ||
use Drupal\islandora_iiif\IiifInfo; | ||
use GuzzleHttp\Client; | ||
use Symfony\Component\DependencyInjection\ContainerInterface; | ||
|
||
/** | ||
* Provides an action that can save any entity. | ||
* | ||
* @Action( | ||
* id = "islandora_iiif:media_attributes_from_iiif_action", | ||
* action_label = @Translation("Add image dimensions retrieved from the IIIF server"), | ||
* deriver = "Drupal\Core\Action\Plugin\Action\Derivative\EntityChangedActionDeriver", | ||
* ) | ||
*/ | ||
class MediaAttributesFromIiif extends SaveAction { | ||
|
||
/** | ||
* The HTTP client. | ||
* | ||
* @var \GuzzleHttp\Client | ||
*/ | ||
protected $httpClient; | ||
|
||
/** | ||
* The IIIF Info service. | ||
* | ||
* @var \Drupal\islandora_iiif\IiifInfo | ||
*/ | ||
protected $iiifInfo; | ||
|
||
/** | ||
* The logger. | ||
* | ||
* @var \Drupal\Core\Logger\LoggerChannelInterface | ||
*/ | ||
protected $logger; | ||
|
||
/** | ||
* Islandora utility functions. | ||
* | ||
* @var \Drupal\islandora\IslandoraUtils | ||
*/ | ||
protected $utils; | ||
|
||
/** | ||
* A MediaSourceService. | ||
* | ||
* @var \Drupal\islandora\MediaSource\MediaSourceService | ||
*/ | ||
protected $mediaSource; | ||
|
||
/** | ||
* Constructs a TiffMediaSaveAction object. | ||
* | ||
* @param mixed[] $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 | ||
* The entity type manager. | ||
* @param \Drupal\Component\Datetime\TimeInterface $time | ||
* The time service. | ||
* @param \Guzzle\Http\Client $http_client | ||
* The HTTP Client. | ||
* @param \Drupal\islandora_iiif\IiifInfo $iiif_info | ||
* The IIIF INfo service. | ||
* @param \Drupal\islandora\IslandoraUtils $islandora_utils | ||
* Islandora utility functions. | ||
* @param \Drupal\islandora\MediaSource\MediaSourceService $media_source | ||
* Islandora media service. | ||
* @param \Drupal\Core\Logger\LoggerChannelInterface $channel | ||
* Logger channel. | ||
*/ | ||
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, TimeInterface $time, Client $http_client, IiifInfo $iiif_info, IslandoraUtils $islandora_utils, MediaSourceService $media_source, LoggerChannelInterface $channel) { | ||
parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $time); | ||
|
||
$this->httpClient = $http_client; | ||
$this->iiifInfo = $iiif_info; | ||
$this->utils = $islandora_utils; | ||
$this->mediaSource = $media_source; | ||
$this->logger = $channel; | ||
} | ||
|
||
/** | ||
* {@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('datetime.time'), | ||
$container->get('http_client'), | ||
$container->get('islandora_iiif'), | ||
$container->get('islandora.utils'), | ||
$container->get('islandora.media_source_service'), | ||
$container->get('logger.channel.islandora') | ||
); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function execute($entity = NULL) { | ||
$width = $height = FALSE; | ||
|
||
// Get the original File media use term. | ||
$original_file_term = $this->utils->getTermForUri('http://pcdm.org/use#OriginalFile'); | ||
|
||
/** | ||
* @var \Drupal\media\MediaInterface $original_file_media | ||
*/ | ||
$original_file_mids = $this->utils->getMediaReferencingNodeAndTerm($entity, $original_file_term); | ||
if (!empty($original_file_mids)) { | ||
|
||
// Ordinarily there shouldn't be more than one Original File media but | ||
// it's not guaranteed. | ||
foreach ($original_file_mids as $original_file_mid) { | ||
|
||
/** | ||
* @var \Drupal\Media\MediaInterface $original_file_media | ||
*/ | ||
$original_file_media = $this->entityTypeManager->getStorage('media')->load($original_file_mid); | ||
|
||
// Get the media MIME Type. | ||
$original_file = $this->mediaSource->getSourceFile($original_file_media); | ||
$mime_type = $original_file->getMimeType(); | ||
|
||
if (in_array($mime_type, ['image/tiff', 'image/jp2'])) { | ||
[$width, $height] = $this->iiifInfo->getImageDimensions($original_file); | ||
} | ||
|
||
// @todo Make field configurable. Low priority since this whole thing is a workaround for an Islandora limitation. | ||
if ($original_file_media->hasField('field_width') && $original_file_media->hasField('field_height')) { | ||
$original_file_media->set('field_height', $height); | ||
$original_file_media->set('field_width', $width); | ||
$original_file_media->save(); | ||
} | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) { | ||
|
||
/** @var \Drupal\Core\Entity\EntityInterface $object */ | ||
return $object->access('update', $account, $return_as_object); | ||
} | ||
|
||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs
use GuzzleHttp\Exception\RequestException;
also.