From d16e49748a9f849288d4d294229d2f61fc26c34a Mon Sep 17 00:00:00 2001 From: Joe Corall Date: Wed, 18 Sep 2019 11:48:23 -0400 Subject: [PATCH] IIIF Presentation API Validator (#166) * Add a manifest label, and width/height of image per https://iiif.io/api/presentation/validator/service/ * try fetching image metadata from IIIF before using Drupal's settings * Move $mime_type into scope --- .../src/Plugin/views/style/IIIFManifest.php | 96 +++++++++++++++---- 1 file changed, 78 insertions(+), 18 deletions(-) diff --git a/modules/islandora_iiif/src/Plugin/views/style/IIIFManifest.php b/modules/islandora_iiif/src/Plugin/views/style/IIIFManifest.php index e2b80520..0e33199b 100644 --- a/modules/islandora_iiif/src/Plugin/views/style/IIIFManifest.php +++ b/modules/islandora_iiif/src/Plugin/views/style/IIIFManifest.php @@ -9,6 +9,10 @@ use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\Serializer\SerializerInterface; use Symfony\Component\HttpFoundation\Request; use Drupal\Core\Config\ImmutableConfig; +use Drupal\Core\File\FileSystem; +use GuzzleHttp\Client; +use GuzzleHttp\Exception\ClientException; +use GuzzleHttp\Exception\ServerException; /** * Provide serializer format for IIIF Manifest. @@ -62,15 +66,24 @@ class IIIFManifest extends StylePluginBase { */ protected $iiifConfig; + /** + * The Drupal Filesystem. + * + * @var \Drupal\Core\File\FileSystem + */ + protected $fileSystem; + /** * {@inheritdoc} */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, SerializerInterface $serializer, Request $request, ImmutableConfig $iiif_config) { + public function __construct(array $configuration, $plugin_id, $plugin_definition, SerializerInterface $serializer, Request $request, ImmutableConfig $iiif_config, FileSystem $file_system, Client $http_client) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->serializer = $serializer; $this->request = $request; $this->iiifConfig = $iiif_config; + $this->fileSystem = $file_system; + $this->httpClient = $http_client; } /** @@ -83,7 +96,9 @@ class IIIFManifest extends StylePluginBase { $plugin_definition, $container->get('serializer'), $container->get('request_stack')->getCurrentRequest(), - $container->get('config.factory')->get('islandora_iiif.settings') + $container->get('config.factory')->get('islandora_iiif.settings'), + $container->get('file_system'), + $container->get('http_client') ); } @@ -105,12 +120,16 @@ class IIIFManifest extends StylePluginBase { $json += [ '@type' => 'sc:Manifest', '@id' => $request_url, + // If the View has a title, set the View title as the manifest label. + 'label' => $this->view->getTitle() ?: 'IIIF Manifest', '@context' => 'http://iiif.io/api/presentation/2/context.json', // @see https://iiif.io/api/presentation/2.1/#sequence 'sequences' => [ - '@context' => 'http://iiif.io/api/presentation/2/context.json', - '@id' => $iiif_base_id . '/sequence/normal', - '@type' => 'sc:Sequence', + [ + '@context' => 'http://iiif.io/api/presentation/2/context.json', + '@id' => $iiif_base_id . '/sequence/normal', + '@type' => 'sc:Sequence', + ], ], ]; // For each row in the View result. @@ -157,32 +176,73 @@ class IIIFManifest extends StylePluginBase { // Create the IIIF URL for this file // Visiting $iiif_url will resolve to the info.json for the image. $file_url = $image->entity->url(); + $mime_type = $image->entity->getMimeType(); $iiif_url = rtrim($iiif_address, '/') . '/' . urlencode($file_url); // Create the necessary ID's for the canvas and annotation. $canvas_id = $iiif_base_id . '/canvas/' . $entity->id(); $annotation_id = $iiif_base_id . '/annotation/' . $entity->id(); + // Try to fetch the IIIF metadata for the image. + try { + $info_json = $this->httpClient->get($iiif_url)->getBody(); + $resource = json_decode($info_json, TRUE); + $width = $resource['width']; + $height = $resource['height']; + } + catch (ClientException $e) { + } + catch (ServerException $e) { + } + + // If we couldn't get the info.json from IIIF + // try seeing if we can get it from Drupal. + if (empty($width) || empty($height)) { + // Get the image properties so we know the image width/height. + $properties = $image->getProperties(); + $width = isset($properties['width']) ? $properties['width'] : 0; + $height = isset($properties['height']) ? $properties['height'] : 0; + + // If this is a TIFF AND we don't know the width/height + // see if we can get the image size via PHP's core function. + if ($mime_type === 'image/tiff' && !$width || !$height) { + $uri = $image->entity->getFileUri(); + $path = $this->fileSystem->realpath($uri); + $image_size = getimagesize($path); + if ($image_size) { + $width = $image_size[0]; + $height = $image_size[1]; + } + } + } + $canvases[] = [ // @see https://iiif.io/api/presentation/2.1/#canvas '@id' => $canvas_id, '@type' => 'sc:Canvas', - 'label' => $entity->label(), + 'label' => $image->entity->label(), + 'height' => $height, + 'width' => $width, // @see https://iiif.io/api/presentation/2.1/#image-resources - 'images' => [[ - '@id' => $annotation_id, - "@type" => "oa:Annotation", - 'motivation' => 'sc:painting', - 'resource' => [ - '@id' => $iiif_url . '/full/full/0/default.jpg', - 'service' => [ - '@id' => $iiif_url, - '@context' => 'http://iiif.io/api/image/2/context.json', - 'profile' => 'http://iiif.io/api/image/2/profiles/level2.json', + 'images' => [ + [ + '@id' => $annotation_id, + "@type" => "oa:Annotation", + 'motivation' => 'sc:painting', + 'resource' => [ + '@id' => $iiif_url . '/full/full/0/default.jpg', + "@type" => "dctypes:Image", + 'format' => $mime_type, + 'height' => $height, + 'width' => $width, + 'service' => [ + '@id' => $iiif_url, + '@context' => 'http://iiif.io/api/image/2/context.json', + 'profile' => 'http://iiif.io/api/image/2/profiles/level2.json', + ], ], + 'on' => $canvas_id, ], - 'on' => $canvas_id, - ], ], ]; }