From baf28deb9f14aaf8dd46f1c572dc5e98b9909cb8 Mon Sep 17 00:00:00 2001 From: Johan Pieterse Date: Tue, 18 Nov 2025 08:46:52 +0200 Subject: [PATCH 1/7] arIiifPlugin - IIIF Integration for AtoM A comprehensive IIIF (International Image Interoperability Framework) plugin for AtoM (Access to Memory) that provides deep zoom image viewing capabilities using OpenSeadragon and Cantaloupe image server integration. ## Features - **IIIF Image Viewer**: OpenSeadragon-based viewer with deep zoom capabilities - **Image Carousel**: Multiple image support with auto-rotation - **IIIF Manifest Generation**: Presentation API 2.1 compliant manifests - **Cantaloupe Integration**: Seamless integration with Cantaloupe IIIF image server - **Responsive Design**: Mobile-friendly viewing experience - **Thumbnail Navigation**: Quick image browsing with thumbnail strip - **Download Support**: Direct image download functionality --- plugins/arIiifPlugin/INSTALL.md | 420 ++++++++++++++++++ plugins/arIiifPlugin/README.md | 420 ++++++++++++++++++ plugins/arIiifPlugin/config/app.yml | 39 ++ .../arIiifPluginConfiguration.class.php | 69 +++ plugins/arIiifPlugin/config/iiif.yml | 27 ++ plugins/arIiifPlugin/css/iiif-carousel.css | 209 +++++++++ plugins/arIiifPlugin/install.sh | 139 ++++++ plugins/arIiifPlugin/js/iiif-carousel.js | 271 +++++++++++ .../lib/arIiifPluginComponents.class.php | 172 +++++++ .../arIiifPluginComponents.class.php.backup | 209 +++++++++ .../arIiifPlugin/actions/components.class.php | 172 +++++++ .../arIiifPlugin/templates/_carousel.php | 96 ++++ .../arIiifPlugin/templates/_viewer.php | 148 ++++++ .../modules/iiif/actions/actions.class.php | 365 +++++++++++++++ .../iiif/actions/actions.class.php.backup | 365 +++++++++++++++ .../iiif/actions/actions.class.php.bak | 365 +++++++++++++++ .../modules/iiif/templates/canvasSuccess.php | 5 + .../iiif/templates/manifestSuccess.php | 5 + .../iiif/templates/objectManifestSuccess.php | 5 + .../images/button_grouphover.png | Bin 0 -> 1506 bytes .../openseadragon/images/button_hover.png | Bin 0 -> 1827 bytes .../openseadragon/images/button_pressed.png | Bin 0 -> 1895 bytes .../openseadragon/images/button_rest.png | Bin 0 -> 1066 bytes .../openseadragon/images/flip_grouphover.png | Bin 0 -> 4920 bytes .../openseadragon/images/flip_hover.png | Bin 0 -> 4920 bytes .../openseadragon/images/flip_pressed.png | Bin 0 -> 4920 bytes .../vendor/openseadragon/images/flip_rest.png | Bin 0 -> 4920 bytes .../images/fullpage_grouphover.png | Bin 0 -> 1085 bytes .../openseadragon/images/fullpage_hover.png | Bin 0 -> 2184 bytes .../openseadragon/images/fullpage_pressed.png | Bin 0 -> 2225 bytes .../openseadragon/images/fullpage_rest.png | Bin 0 -> 1309 bytes .../openseadragon/images/home_grouphover.png | Bin 0 -> 1062 bytes .../openseadragon/images/home_hover.png | Bin 0 -> 2091 bytes .../openseadragon/images/home_pressed.png | Bin 0 -> 2138 bytes .../vendor/openseadragon/images/home_rest.png | Bin 0 -> 1258 bytes .../openseadragon/images/next_grouphover.png | Bin 0 -> 1918 bytes .../openseadragon/images/next_hover.png | Bin 0 -> 2358 bytes .../openseadragon/images/next_pressed.png | Bin 0 -> 2411 bytes .../vendor/openseadragon/images/next_rest.png | Bin 0 -> 2027 bytes .../images/previous_grouphover.png | Bin 0 -> 1933 bytes .../openseadragon/images/previous_hover.png | Bin 0 -> 2361 bytes .../openseadragon/images/previous_pressed.png | Bin 0 -> 2413 bytes .../openseadragon/images/previous_rest.png | Bin 0 -> 2029 bytes .../images/rotateleft_grouphover.png | Bin 0 -> 1731 bytes .../openseadragon/images/rotateleft_hover.png | Bin 0 -> 2094 bytes .../images/rotateleft_pressed.png | Bin 0 -> 2036 bytes .../openseadragon/images/rotateleft_rest.png | Bin 0 -> 1779 bytes .../images/rotateright_grouphover.png | Bin 0 -> 1800 bytes .../images/rotateright_hover.png | Bin 0 -> 2158 bytes .../images/rotateright_pressed.png | Bin 0 -> 2039 bytes .../openseadragon/images/rotateright_rest.png | Bin 0 -> 1812 bytes .../images/zoomin_grouphover.png | Bin 0 -> 1060 bytes .../openseadragon/images/zoomin_hover.png | Bin 0 -> 2116 bytes .../openseadragon/images/zoomin_pressed.png | Bin 0 -> 2159 bytes .../openseadragon/images/zoomin_rest.png | Bin 0 -> 1262 bytes .../images/zoomout_grouphover.png | Bin 0 -> 977 bytes .../openseadragon/images/zoomout_hover.png | Bin 0 -> 1926 bytes .../openseadragon/images/zoomout_pressed.png | Bin 0 -> 1997 bytes .../openseadragon/images/zoomout_rest.png | Bin 0 -> 1153 bytes .../vendor/openseadragon/openseadragon.min.js | 9 + 60 files changed, 3510 insertions(+) create mode 100644 plugins/arIiifPlugin/INSTALL.md create mode 100644 plugins/arIiifPlugin/README.md create mode 100644 plugins/arIiifPlugin/config/app.yml create mode 100644 plugins/arIiifPlugin/config/arIiifPluginConfiguration.class.php create mode 100644 plugins/arIiifPlugin/config/iiif.yml create mode 100644 plugins/arIiifPlugin/css/iiif-carousel.css create mode 100644 plugins/arIiifPlugin/install.sh create mode 100644 plugins/arIiifPlugin/js/iiif-carousel.js create mode 100644 plugins/arIiifPlugin/lib/arIiifPluginComponents.class.php create mode 100644 plugins/arIiifPlugin/lib/arIiifPluginComponents.class.php.backup create mode 100644 plugins/arIiifPlugin/modules/arIiifPlugin/actions/components.class.php create mode 100644 plugins/arIiifPlugin/modules/arIiifPlugin/templates/_carousel.php create mode 100644 plugins/arIiifPlugin/modules/arIiifPlugin/templates/_viewer.php create mode 100644 plugins/arIiifPlugin/modules/iiif/actions/actions.class.php create mode 100644 plugins/arIiifPlugin/modules/iiif/actions/actions.class.php.backup create mode 100644 plugins/arIiifPlugin/modules/iiif/actions/actions.class.php.bak create mode 100644 plugins/arIiifPlugin/modules/iiif/templates/canvasSuccess.php create mode 100644 plugins/arIiifPlugin/modules/iiif/templates/manifestSuccess.php create mode 100644 plugins/arIiifPlugin/modules/iiif/templates/objectManifestSuccess.php create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/button_grouphover.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/button_hover.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/button_pressed.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/button_rest.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/flip_grouphover.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/flip_hover.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/flip_pressed.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/flip_rest.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/fullpage_grouphover.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/fullpage_hover.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/fullpage_pressed.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/fullpage_rest.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/home_grouphover.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/home_hover.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/home_pressed.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/home_rest.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/next_grouphover.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/next_hover.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/next_pressed.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/next_rest.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/previous_grouphover.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/previous_hover.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/previous_pressed.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/previous_rest.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/rotateleft_grouphover.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/rotateleft_hover.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/rotateleft_pressed.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/rotateleft_rest.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/rotateright_grouphover.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/rotateright_hover.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/rotateright_pressed.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/rotateright_rest.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/zoomin_grouphover.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/zoomin_hover.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/zoomin_pressed.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/zoomin_rest.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/zoomout_grouphover.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/zoomout_hover.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/zoomout_pressed.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/images/zoomout_rest.png create mode 100644 plugins/arIiifPlugin/vendor/openseadragon/openseadragon.min.js diff --git a/plugins/arIiifPlugin/INSTALL.md b/plugins/arIiifPlugin/INSTALL.md new file mode 100644 index 0000000000..2cdaee3229 --- /dev/null +++ b/plugins/arIiifPlugin/INSTALL.md @@ -0,0 +1,420 @@ +# Installation Guide for arIiifPlugin + +This guide provides detailed instructions for installing the IIIF Image Carousel plugin in AtoM. + +## Prerequisites + +- AtoM 2.x or later installed at `/usr/share/nginx/atom` (or adjust paths accordingly) +- Root or sudo access to the server +- PHP 5.6+ (PHP 7.x recommended) +- IIIF-compliant image server (optional but recommended) + +## Quick Installation + +### Option 1: Automated Installation (Recommended) + +```bash +# Navigate to the plugin directory +cd arIiifPlugin + +# Run the installation script +sudo ./install.sh +``` + +The script will: +- Copy plugin files to AtoM plugins directory +- Download and install OpenSeadragon +- Set correct permissions +- Enable the plugin +- Clear AtoM cache +- Restart services + +### Option 2: Manual Installation + +Follow these steps if the automated installation doesn't work or you need more control: + +#### 1. Copy Plugin Files + +```bash +# Copy the plugin to AtoM plugins directory +sudo cp -r arIiifPlugin /usr/share/nginx/atom/plugins/ + +# Set correct ownership +sudo chown -R www-data:www-data /usr/share/nginx/atom/plugins/arIiifPlugin + +# Set correct permissions +sudo chmod -R 755 /usr/share/nginx/atom/plugins/arIiifPlugin +``` + +#### 2. Install OpenSeadragon + +```bash +# Download OpenSeadragon +cd /tmp +wget https://github.com/openseadragon/openseadragon/releases/download/v4.1.0/openseadragon-bin-4.1.0.zip + +# Extract +unzip openseadragon-bin-4.1.0.zip + +# Copy to plugin vendor directory +sudo cp openseadragon-bin-4.1.0/openseadragon.min.js \ + /usr/share/nginx/atom/plugins/arIiifPlugin/vendor/openseadragon/ + +sudo cp -r openseadragon-bin-4.1.0/images/* \ + /usr/share/nginx/atom/plugins/arIiifPlugin/vendor/openseadragon/images/ + +# Set permissions +sudo chown -R www-data:www-data /usr/share/nginx/atom/plugins/arIiifPlugin/vendor +sudo chmod -R 755 /usr/share/nginx/atom/plugins/arIiifPlugin/vendor +``` + +#### 3. Enable Plugin in AtoM + +```bash +cd /usr/share/nginx/atom + +# Enable the plugin +sudo -u www-data php symfony tools:enable-plugin arIiifPlugin + +# Verify plugin is enabled +sudo -u www-data php symfony tools:list-plugins +``` + +#### 4. Configure Plugin + +Edit your AtoM configuration: + +```bash +sudo nano /usr/share/nginx/atom/apps/qubit/config/app.yml +``` + +Add the IIIF configuration (adjust as needed): + +```yaml +all: + iiif: + # Your IIIF Image Server base URL + base_url: https://your-iiif-server.com/iiif/2 + + # IIIF API version + api_version: 2 + + # Enable IIIF Presentation API manifests + enable_manifests: true + + # Carousel settings + carousel: + auto_rotate: true + rotate_interval: 5000 + show_navigation: true + show_thumbnails: false + viewer_height: 600 + + # Viewer settings + viewer: + enable_zoom: true + enable_rotation: true + enable_fullscreen: true + max_zoom_level: 4 +``` + +#### 5. Clear Cache and Restart Services + +```bash +# Clear AtoM cache +sudo -u www-data php symfony cc + +# Clear symfony cache +sudo rm -rf /usr/share/nginx/atom/cache/* + +# Restart PHP-FPM (adjust version as needed) +sudo systemctl restart php7.4-fpm + +# Restart Nginx +sudo systemctl restart nginx +``` + +## Post-Installation Configuration + +### 1. Setting up IIIF Image Server (Cantaloupe Example) + +If you don't have a IIIF image server, here's how to set up Cantaloupe: + +```bash +# Install Java (if not already installed) +sudo apt-get update +sudo apt-get install -y openjdk-11-jre-headless + +# Download Cantaloupe +cd /opt +sudo wget https://github.com/cantaloupe-project/cantaloupe/releases/download/v5.0.5/cantaloupe-5.0.5.zip +sudo unzip cantaloupe-5.0.5.zip +cd cantaloupe-5.0.5 + +# Create configuration +sudo cp cantaloupe.properties.sample cantaloupe.properties +sudo nano cantaloupe.properties +``` + +Edit these key settings in `cantaloupe.properties`: + +```properties +# HTTP port +http.port = 8182 + +# Enable IIIF Image API 2.0 +endpoint.iiif.2.enabled = true + +# Disable IIIF Image API 3.0 (unless needed) +endpoint.iiif.3.enabled = false + +# Set source for images +FilesystemSource.BasicLookupStrategy.path_prefix = /usr/share/nginx/atom/uploads/ + +# Enable caching +cache.server.derivative.enabled = true +cache.server.derivative = FilesystemCache +FilesystemCache.pathname = /var/cache/cantaloupe +``` + +Create systemd service: + +```bash +sudo nano /etc/systemd/system/cantaloupe.service +``` + +```ini +[Unit] +Description=Cantaloupe IIIF Image Server +After=network.target + +[Service] +Type=simple +User=www-data +WorkingDirectory=/opt/cantaloupe-5.0.5 +ExecStart=/usr/bin/java -Dcantaloupe.config=/opt/cantaloupe-5.0.5/cantaloupe.properties -Xmx2g -jar /opt/cantaloupe-5.0.5/cantaloupe-5.0.5.jar +Restart=on-failure +RestartSec=10 + +[Install] +WantedBy=multi-user.target +``` + +Start and enable: + +```bash +# Create cache directory +sudo mkdir -p /var/cache/cantaloupe +sudo chown www-data:www-data /var/cache/cantaloupe + +# Start service +sudo systemctl daemon-reload +sudo systemctl enable cantaloupe +sudo systemctl start cantaloupe + +# Check status +sudo systemctl status cantaloupe +``` + +Update `app.yml` with Cantaloupe URL: + +```yaml +all: + iiif: + base_url: http://localhost:8182/iiif/2 +``` + +### 2. Configure Nginx Proxy (Optional but Recommended) + +To serve IIIF over HTTPS alongside AtoM: + +```bash +sudo nano /etc/nginx/sites-available/atom +``` + +Add inside the server block: + +```nginx +# IIIF Image Server Proxy +location /iiif/2/ { + proxy_pass http://localhost:8182/iiif/2/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # CORS headers + add_header 'Access-Control-Allow-Origin' '*' always; + add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS' always; + add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, Content-Type, Accept' always; + + if ($request_method = 'OPTIONS') { + return 204; + } +} +``` + +Test and reload: + +```bash +sudo nginx -t +sudo systemctl reload nginx +``` + +Update `app.yml`: + +```yaml +all: + iiif: + base_url: https://your-atom-domain.com/iiif/2 +``` + +## Verification + +### 1. Check Plugin Status + +```bash +cd /usr/share/nginx/atom +sudo -u www-data php symfony tools:list-plugins +``` + +You should see `arIiifPlugin` in the enabled plugins list. + +### 2. Check Files + +```bash +# Check plugin directory +ls -la /usr/share/nginx/atom/plugins/arIiifPlugin/ + +# Check OpenSeadragon +ls -la /usr/share/nginx/atom/plugins/arIiifPlugin/vendor/openseadragon/ + +# Check assets +ls -la /usr/share/nginx/atom/plugins/arIiifPlugin/js/ +ls -la /usr/share/nginx/atom/plugins/arIiifPlugin/css/ +``` + +### 3. Test IIIF Server (if installed) + +```bash +# Test Cantaloupe is running +curl http://localhost:8182/iiif/2/ + +# Should return JSON with IIIF server info +``` + +### 4. Test in Browser + +1. Log into your AtoM instance +2. Navigate to an information object with digital objects +3. Add the component to a template (see Usage section in README.md) +4. View the page to see the carousel + +## Troubleshooting Installation + +### Plugin Not Listed + +```bash +# Check plugin directory exists +ls -la /usr/share/nginx/atom/plugins/ | grep arIiif + +# Check permissions +ls -la /usr/share/nginx/atom/plugins/arIiifPlugin/ + +# Try re-enabling +sudo -u www-data php symfony tools:enable-plugin arIiifPlugin +``` + +### OpenSeadragon Not Loading + +```bash +# Verify OpenSeadragon files exist +ls -la /usr/share/nginx/atom/plugins/arIiifPlugin/vendor/openseadragon/openseadragon.min.js + +# Check file permissions +sudo chmod 755 /usr/share/nginx/atom/plugins/arIiifPlugin/vendor/openseadragon/openseadragon.min.js +``` + +### Cache Issues + +```bash +# Clear all caches thoroughly +cd /usr/share/nginx/atom +sudo -u www-data php symfony cc +sudo rm -rf cache/* +sudo -u www-data php symfony tools:clear-cache + +# Restart services +sudo systemctl restart php7.4-fpm nginx +``` + +### Permission Issues + +```bash +# Fix all permissions +sudo chown -R www-data:www-data /usr/share/nginx/atom/plugins/arIiifPlugin +sudo chmod -R 755 /usr/share/nginx/atom/plugins/arIiifPlugin + +# Fix web directory permissions +sudo chown -R www-data:www-data /usr/share/nginx/atom/ +``` + +### IIIF Server Connection Issues + +```bash +# Test local connection +curl http://localhost:8182/iiif/2/ + +# Check if Cantaloupe is running +sudo systemctl status cantaloupe + +# Check logs +sudo journalctl -u cantaloupe -f +``` + +### PHP Errors + +```bash +# Check PHP error log +sudo tail -f /var/log/php7.4-fpm.log + +# Check Nginx error log +sudo tail -f /var/log/nginx/error.log + +# Check AtoM logs +tail -f /usr/share/nginx/atom/log/*.log +``` + +## Uninstallation + +If you need to remove the plugin: + +```bash +# Disable plugin +cd /usr/share/nginx/atom +sudo -u www-data php symfony tools:disable-plugin arIiifPlugin + +# Remove plugin files +sudo rm -rf /usr/share/nginx/atom/plugins/arIiifPlugin + +# Clear cache +sudo -u www-data php symfony cc + +# Restart services +sudo systemctl restart php7.4-fpm nginx +``` + +## Getting Help + +- Check the README.md in the plugin directory +- Review AtoM documentation: https://www.accesstomemory.org/docs/ +- IIIF specifications: https://iiif.io/ +- OpenSeadragon documentation: https://openseadragon.github.io/ + +## Next Steps + +After successful installation, see README.md for: +- Usage examples +- Configuration options +- Integration with your templates +- IIIF manifest generation diff --git a/plugins/arIiifPlugin/README.md b/plugins/arIiifPlugin/README.md new file mode 100644 index 0000000000..2c447ca19e --- /dev/null +++ b/plugins/arIiifPlugin/README.md @@ -0,0 +1,420 @@ +# arIiifPlugin - IIIF Image Carousel Plugin for AtoM + +A comprehensive IIIF (International Image Interoperability Framework) plugin for Access to Memory (AtoM) that provides rotating image carousels, deep zoom viewers, and IIIF Presentation API manifest generation. + +## Features + +- **Auto-rotating Image Carousel** with configurable intervals +- **OpenSeadragon Integration** for deep zoom and pan capabilities +- **IIIF Presentation API 2.1** manifest generation +- **Multiple viewing modes**: carousel and single viewer +- **Navigation controls**: previous, next, play/pause +- **Keyboard navigation** (arrow keys) +- **Optional thumbnail strip** +- **Fully responsive design** +- **Configurable via app.yml** + +## Requirements + +- AtoM 2.x or later (Symfony 1.4) +- PHP 5.6+ (7.x recommended) +- IIIF-compliant image server (Cantaloupe, IIPImage, Loris, etc.) +- OpenSeadragon library (included) + +## Installation + +### 1. Copy Plugin to AtoM + +```bash +# Copy the plugin to the AtoM plugins directory +sudo cp -r arIiifPlugin /usr/share/nginx/atom/plugins/ + +# Set correct permissions +sudo chown -R www-data:www-data /usr/share/nginx/atom/plugins/arIiifPlugin +sudo chmod -R 755 /usr/share/nginx/atom/plugins/arIiifPlugin +``` + +### 2. Download OpenSeadragon + +```bash +# Download OpenSeadragon +cd /tmp +wget https://github.com/openseadragon/openseadragon/releases/download/v4.1.0/openseadragon-bin-4.1.0.zip +unzip openseadragon-bin-4.1.0.zip + +# Copy to plugin vendor directory +sudo cp openseadragon-bin-4.1.0/openseadragon.min.js /usr/share/nginx/atom/plugins/arIiifPlugin/vendor/openseadragon/ +sudo cp -r openseadragon-bin-4.1.0/images/* /usr/share/nginx/atom/plugins/arIiifPlugin/vendor/openseadragon/images/ + +# Set permissions +sudo chown -R www-data:www-data /usr/share/nginx/atom/plugins/arIiifPlugin/vendor +``` + +### 3. Configure Plugin + +Edit your AtoM configuration to include the IIIF server URL: + +```bash +sudo nano /usr/share/nginx/atom/apps/qubit/config/app.yml +``` + +Add or modify the following configuration: + +```yaml +all: + iiif: + # Base URL for your IIIF Image Server + base_url: https://your-iiif-server.com/iiif/2 + + # IIIF API version (2 or 3) + api_version: 2 + + # Image server type + server_type: cantaloupe + + # Enable IIIF Presentation API manifest generation + enable_manifests: true + + # Carousel default settings + carousel: + auto_rotate: true + rotate_interval: 5000 + show_navigation: true + show_thumbnails: false + viewer_height: 600 + + # Viewer settings + viewer: + enable_zoom: true + enable_rotation: true + enable_fullscreen: true + max_zoom_level: 4 +``` + +### 4. Enable Plugin in AtoM + +```bash +# Enable the plugin +sudo php /usr/share/nginx/atom/symfony tools:enable-plugin arIiifPlugin + +# Clear cache +sudo php /usr/share/nginx/atom/symfony cc + +# Rebuild assets +sudo php /usr/share/nginx/atom/symfony tools:clear-cache +``` + +### 5. Restart Services + +```bash +sudo systemctl restart php7.4-fpm # Adjust PHP version as needed +sudo systemctl restart nginx +``` + +## Usage + +### Method 1: Using Component in Templates + +#### Display Carousel for Information Object + +In your template file (e.g., `apps/qubit/modules/informationobject/templates/showSuccess.php`): + +```php + $resource, + 'autoRotate' => true, + 'rotateInterval' => 5000, + 'showNavigation' => true, + 'showThumbnails' => true, + 'viewerHeight' => 600 +)); +?> +``` + +#### Display Single Viewer for Digital Object + +```php + $digitalObject, + 'viewerHeight' => 600 +)); +?> +``` + +### Method 2: Custom Implementation + +You can also manually specify IIIF images: + +```php + 'https://iiif.example.com/image/1/info.json', + 'label' => 'First Image' + ), + array( + 'url' => 'https://iiif.example.com/image/2/info.json', + 'label' => 'Second Image' + ) +); + +include_component('arIiifPlugin', 'carousel', array( + 'images' => $images, + 'autoRotate' => true, + 'showThumbnails' => true +)); +?> +``` + +## Configuration Options + +### Carousel Component + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `resource` | object | required | QubitInformationObject or QubitDigitalObject | +| `images` | array | null | Manual array of IIIF image URLs (alternative to resource) | +| `autoRotate` | boolean | true | Enable automatic rotation | +| `rotateInterval` | integer | 5000 | Rotation interval in milliseconds | +| `showNavigation` | boolean | true | Show navigation controls | +| `showThumbnails` | boolean | false | Show thumbnail strip | +| `viewerHeight` | integer | 600 | Height of viewer in pixels | + +### Viewer Component + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `resource` | object | required | QubitDigitalObject | +| `viewerHeight` | integer | 600 | Height of viewer in pixels | + +## IIIF Manifest API + +The plugin provides IIIF Presentation API 2.1 manifests: + +### Information Object Manifest + +``` +GET /iiif/{slug}/manifest +``` + +Example: +``` +https://your-atom-site.com/iiif/my-collection/manifest +``` + +### Digital Object Manifest + +``` +GET /iiif/object/{id}/manifest +``` + +Example: +``` +https://your-atom-site.com/iiif/object/123/manifest +``` + +### Canvas Endpoint + +``` +GET /iiif/{slug}/canvas/{canvas_index} +``` + +## Digital Object Configuration + +### Option 1: Add IIIF Property + +Add a property to your digital object: + +```php +$property = new QubitProperty(); +$property->objectId = $digitalObject->id; +$property->name = 'iiifManifestUrl'; +$property->value = 'https://your-iiif-server.com/iiif/2/image123/info.json'; +$property->save(); +``` + +### Option 2: Auto-generate from File Path + +The plugin can automatically generate IIIF URLs from digital object file paths if your IIIF server is configured in `app.yml`. + +## Setting up IIIF Image Server + +### Recommended: Cantaloupe + +1. **Download Cantaloupe:** +```bash +cd /opt +sudo wget https://github.com/cantaloupe-project/cantaloupe/releases/download/v5.0.5/cantaloupe-5.0.5.zip +sudo unzip cantaloupe-5.0.5.zip +cd cantaloupe-5.0.5 +``` + +2. **Configure Cantaloupe:** +```bash +sudo cp cantaloupe.properties.sample cantaloupe.properties +sudo nano cantaloupe.properties +``` + +Set: +```properties +FilesystemSource.BasicLookupStrategy.path_prefix = /usr/share/nginx/atom/uploads/ +endpoint.iiif.2.enabled = true +endpoint.iiif.3.enabled = false +``` + +3. **Run Cantaloupe:** +```bash +java -Dcantaloupe.config=cantaloupe.properties -Xmx2g -jar cantaloupe-5.0.5.jar +``` + +4. **Create systemd service:** +```bash +sudo nano /etc/systemd/system/cantaloupe.service +``` + +```ini +[Unit] +Description=Cantaloupe IIIF Image Server +After=network.target + +[Service] +Type=simple +User=www-data +WorkingDirectory=/opt/cantaloupe-5.0.5 +ExecStart=/usr/bin/java -Dcantaloupe.config=/opt/cantaloupe-5.0.5/cantaloupe.properties -Xmx2g -jar /opt/cantaloupe-5.0.5/cantaloupe-5.0.5.jar +Restart=on-failure + +[Install] +WantedBy=multi-user.target +``` + +```bash +sudo systemctl enable cantaloupe +sudo systemctl start cantaloupe +``` + +## Troubleshooting + +### Images Not Loading + +1. **Check IIIF server is running:** +```bash +curl http://localhost:8182/iiif/2/ +``` + +2. **Verify CORS headers** on IIIF server + +3. **Check browser console** for errors + +4. **Verify file permissions:** +```bash +sudo ls -la /usr/share/nginx/atom/uploads/ +``` + +### OpenSeadragon Not Found + +Check that OpenSeadragon files exist: +```bash +ls -la /usr/share/nginx/atom/plugins/arIiifPlugin/vendor/openseadragon/ +``` + +### Plugin Not Enabled + +```bash +# Check enabled plugins +php /usr/share/nginx/atom/symfony tools:list-plugins + +# Enable if needed +sudo php /usr/share/nginx/atom/symfony tools:enable-plugin arIiifPlugin +sudo php /usr/share/nginx/atom/symfony cc +``` + +### Clear Cache Issues + +```bash +# Clear all caches +sudo php /usr/share/nginx/atom/symfony cc +sudo rm -rf /usr/share/nginx/atom/cache/* +sudo php /usr/share/nginx/atom/symfony tools:clear-cache + +# Restart services +sudo systemctl restart php7.4-fpm +sudo systemctl restart nginx +``` + +## File Structure + +``` +arIiifPlugin/ +├── config/ +│ ├── arIiifPluginConfiguration.class.php +│ └── app.yml +├── css/ +│ └── iiif-carousel.css +├── js/ +│ └── iiif-carousel.js +├── lib/ +│ └── arIiifPluginComponents.class.php +├── modules/ +│ ├── arIiifPlugin/ +│ │ └── templates/ +│ │ ├── _carousel.php +│ │ └── _viewer.php +│ └── iiif/ +│ └── actions/ +│ └── actions.class.php +├── vendor/ +│ └── openseadragon/ +│ ├── openseadragon.min.js +│ └── images/ +└── README.md +``` + +## Example Integration + +Replace the default digital object display in `showSuccess.php`: + +```php +getDigitalObjectCount() > 0): ?> +
+

+ + $resource, + 'showThumbnails' => true, + 'autoRotate' => true + )); + ?> + +
+ +``` + +## Browser Support + +- Chrome 90+ +- Firefox 88+ +- Safari 14+ +- Edge 90+ + +## License + +AGPL-3.0 (same as AtoM) + +## Support + +- AtoM Documentation: https://www.accesstomemory.org/docs/ +- IIIF Specifications: https://iiif.io/ +- OpenSeadragon: https://openseadragon.github.io/ + +## Credits + +- Built for Access to Memory (AtoM) +- Uses OpenSeadragon for deep zoom +- Implements IIIF Image API and Presentation API diff --git a/plugins/arIiifPlugin/config/app.yml b/plugins/arIiifPlugin/config/app.yml new file mode 100644 index 0000000000..0c72c28298 --- /dev/null +++ b/plugins/arIiifPlugin/config/app.yml @@ -0,0 +1,39 @@ +# arIiifPlugin application configuration + +all: + # IIIF Image Server Configuration + iiif: + # Base URL for your IIIF Image Server + # Example: https://iiif.example.com/iiif/2 + base_url: ~ + + # IIIF API version (2 or 3) + api_version: 2 + + # Image server type (cantaloupe, iipimage, loris, etc.) + server_type: cantaloupe + + # Enable IIIF Presentation API manifest generation + enable_manifests: true + + # Carousel default settings + carousel: + auto_rotate: true + rotate_interval: 5000 # milliseconds + show_navigation: true + show_thumbnails: false + viewer_height: 600 # pixels + + # Viewer settings + viewer: + enable_zoom: true + enable_rotation: true + enable_fullscreen: true + max_zoom_level: 4 + + # Thumbnail settings + thumbnail: + width: 150 + height: ~ # null = auto + quality: default + format: jpg diff --git a/plugins/arIiifPlugin/config/arIiifPluginConfiguration.class.php b/plugins/arIiifPlugin/config/arIiifPluginConfiguration.class.php new file mode 100644 index 0000000000..e5c251fe05 --- /dev/null +++ b/plugins/arIiifPlugin/config/arIiifPluginConfiguration.class.php @@ -0,0 +1,69 @@ +dispatcher->connect('routing.load_configuration', array($this, 'listenToRoutingLoadConfigurationEvent')); + } + + /** + * Listen to routing.load_configuration event + * + * @param sfEvent $event + */ + public function listenToRoutingLoadConfigurationEvent(sfEvent $event) + { + $routing = $event->getSubject(); + + // Load plugin routing rules + $routing->prependRoute('iiif_manifest', new sfRoute( + '/iiif/:slug/manifest', + array('module' => 'iiif', 'action' => 'manifest') + )); + + $routing->prependRoute('iiif_object_manifest', new sfRoute( + '/iiif/object/:id/manifest', + array('module' => 'iiif', 'action' => 'objectManifest') + )); + + $routing->prependRoute('iiif_canvas', new sfRoute( + '/iiif/:slug/canvas/:canvas', + array('module' => 'iiif', 'action' => 'canvas') + )); + } + + /** + * Establish plugin version + */ + public static function getVersion() + { + return self::$version; + } +} diff --git a/plugins/arIiifPlugin/config/iiif.yml b/plugins/arIiifPlugin/config/iiif.yml new file mode 100644 index 0000000000..3ef43d8fa7 --- /dev/null +++ b/plugins/arIiifPlugin/config/iiif.yml @@ -0,0 +1,27 @@ +# arIiifPlugin IIIF Configuration +# This file is processed by sfDefineEnvironmentConfigHandler + +# IIIF Image Server Configuration +iiif_base_url: ~ +iiif_api_version: 2 +iiif_server_type: cantaloupe +iiif_enable_manifests: true + +# Carousel Settings +iiif_carousel_auto_rotate: true +iiif_carousel_rotate_interval: 5000 +iiif_carousel_show_navigation: true +iiif_carousel_show_thumbnails: false +iiif_carousel_viewer_height: 600 + +# Viewer Settings +iiif_viewer_enable_zoom: true +iiif_viewer_enable_rotation: true +iiif_viewer_enable_fullscreen: true +iiif_viewer_max_zoom_level: 4 + +# Thumbnail Settings +iiif_thumbnail_width: 150 +iiif_thumbnail_height: ~ +iiif_thumbnail_quality: default +iiif_thumbnail_format: jpg \ No newline at end of file diff --git a/plugins/arIiifPlugin/css/iiif-carousel.css b/plugins/arIiifPlugin/css/iiif-carousel.css new file mode 100644 index 0000000000..118927d140 --- /dev/null +++ b/plugins/arIiifPlugin/css/iiif-carousel.css @@ -0,0 +1,209 @@ +/** + * IIIF Image Carousel Styles for AtoM + */ + +.iiif-carousel-wrapper { + position: relative; + width: 100%; + background: #000; + border-radius: 4px; + overflow: hidden; +} + +.iiif-viewer-container { + width: 100%; + height: 600px; + background: #1a1a1a; + position: relative; +} + +/* Navigation Controls */ +.iiif-carousel-nav { + position: absolute; + bottom: 20px; + left: 50%; + transform: translateX(-50%); + display: flex; + align-items: center; + gap: 15px; + background: rgba(0, 0, 0, 0.7); + padding: 10px 20px; + border-radius: 25px; + z-index: 1000; +} + +.iiif-nav-btn { + background: transparent; + border: 2px solid #fff; + color: #fff; + width: 40px; + height: 40px; + border-radius: 50%; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s ease; + font-size: 18px; +} + +.iiif-nav-btn:hover { + background: #fff; + color: #000; + transform: scale(1.1); +} + +.iiif-nav-btn:active { + transform: scale(0.95); +} + +.iiif-carousel-counter { + color: #fff; + font-size: 14px; + font-weight: 500; + padding: 0 10px; + white-space: nowrap; +} + +.iiif-play-pause { + background: transparent; + border: 2px solid #fff; + color: #fff; + width: 40px; + height: 40px; + border-radius: 50%; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s ease; + font-size: 16px; +} + +.iiif-play-pause:hover { + background: #fff; + color: #000; +} + +/* Thumbnails */ +.iiif-carousel-thumbnails { + display: flex; + gap: 10px; + padding: 15px; + background: #2a2a2a; + overflow-x: auto; + overflow-y: hidden; +} + +.iiif-thumbnail { + flex-shrink: 0; + width: 120px; + height: 80px; + cursor: pointer; + border: 3px solid transparent; + border-radius: 4px; + overflow: hidden; + transition: all 0.3s ease; + opacity: 0.6; +} + +.iiif-thumbnail:hover { + opacity: 1; + border-color: #4a90e2; + transform: scale(1.05); +} + +.iiif-thumbnail.active { + opacity: 1; + border-color: #fff; +} + +.iiif-thumbnail img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; +} + +/* Icon styles (assuming Font Awesome or similar) */ +.icon-left-arrow::before { + content: '‹'; + font-size: 24px; +} + +.icon-right-arrow::before { + content: '›'; + font-size: 24px; +} + +.icon-pause::before { + content: '❚❚'; + font-size: 12px; +} + +.icon-play::before { + content: '▶'; + font-size: 14px; +} + +/* Responsive Design */ +@media (max-width: 768px) { + .iiif-viewer-container { + height: 400px; + } + + .iiif-carousel-nav { + bottom: 10px; + padding: 8px 15px; + gap: 10px; + } + + .iiif-nav-btn, + .iiif-play-pause { + width: 35px; + height: 35px; + font-size: 16px; + } + + .iiif-carousel-counter { + font-size: 12px; + } + + .iiif-thumbnail { + width: 80px; + height: 60px; + } +} + +@media (max-width: 480px) { + .iiif-viewer-container { + height: 300px; + } + + .iiif-carousel-thumbnails { + padding: 10px; + gap: 8px; + } +} + +/* Loading state */ +.iiif-carousel-wrapper.loading::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 50px; + height: 50px; + margin: -25px 0 0 -25px; + border: 4px solid rgba(255, 255, 255, 0.3); + border-top-color: #fff; + border-radius: 50%; + animation: iiif-spin 1s linear infinite; + z-index: 999; +} + +@keyframes iiif-spin { + to { + transform: rotate(360deg); + } +} diff --git a/plugins/arIiifPlugin/install.sh b/plugins/arIiifPlugin/install.sh new file mode 100644 index 0000000000..a53b71c895 --- /dev/null +++ b/plugins/arIiifPlugin/install.sh @@ -0,0 +1,139 @@ +#!/bin/bash + +# arIiifPlugin Installation Script for AtoM +# This script automates the installation of the IIIF plugin + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Configuration +ATOM_PATH="/usr/share/nginx/atom" +PLUGIN_NAME="arIiifPlugin" +PLUGIN_PATH="$ATOM_PATH/plugins/$PLUGIN_NAME" +OPENSEADRAGON_VERSION="4.1.0" + +echo -e "${GREEN}========================================${NC}" +echo -e "${GREEN}arIiifPlugin Installation Script${NC}" +echo -e "${GREEN}========================================${NC}" +echo "" + +# Check if running as root or with sudo +if [ "$EUID" -ne 0 ]; then + echo -e "${RED}Error: This script must be run as root or with sudo${NC}" + exit 1 +fi + +# Check if AtoM directory exists +if [ ! -d "$ATOM_PATH" ]; then + echo -e "${RED}Error: AtoM directory not found at $ATOM_PATH${NC}" + echo "Please specify the correct AtoM path by editing this script" + exit 1 +fi + +echo -e "${YELLOW}Step 1: Copying plugin files...${NC}" +if [ -d "$PLUGIN_PATH" ]; then + echo -e "${YELLOW}Plugin directory already exists. Backing up...${NC}" + mv "$PLUGIN_PATH" "${PLUGIN_PATH}.backup.$(date +%Y%m%d_%H%M%S)" +fi + +cp -r "$(dirname "$0")" "$PLUGIN_PATH" +echo -e "${GREEN}✓ Plugin files copied${NC}" + +echo "" +echo -e "${YELLOW}Step 2: Setting permissions...${NC}" +chown -R www-data:www-data "$PLUGIN_PATH" +chmod -R 755 "$PLUGIN_PATH" +echo -e "${GREEN}✓ Permissions set${NC}" + +echo "" +echo -e "${YELLOW}Step 3: Downloading OpenSeadragon...${NC}" +cd /tmp + +if [ ! -f "openseadragon-bin-${OPENSEADRAGON_VERSION}.zip" ]; then + wget -q "https://github.com/openseadragon/openseadragon/releases/download/v${OPENSEADRAGON_VERSION}/openseadragon-bin-${OPENSEADRAGON_VERSION}.zip" + if [ $? -ne 0 ]; then + echo -e "${YELLOW}Warning: Could not download OpenSeadragon automatically${NC}" + echo "Please download it manually from: https://openseadragon.github.io/" + else + unzip -q "openseadragon-bin-${OPENSEADRAGON_VERSION}.zip" + + # Copy OpenSeadragon files + mkdir -p "$PLUGIN_PATH/vendor/openseadragon/images" + cp "openseadragon-bin-${OPENSEADRAGON_VERSION}/openseadragon.min.js" "$PLUGIN_PATH/vendor/openseadragon/" + cp -r "openseadragon-bin-${OPENSEADRAGON_VERSION}/images/"* "$PLUGIN_PATH/vendor/openseadragon/images/" + + # Set permissions + chown -R www-data:www-data "$PLUGIN_PATH/vendor" + chmod -R 755 "$PLUGIN_PATH/vendor" + + echo -e "${GREEN}✓ OpenSeadragon installed${NC}" + fi +else + echo -e "${GREEN}✓ OpenSeadragon already downloaded${NC}" +fi + +echo "" +echo -e "${YELLOW}Step 4: Enabling plugin in AtoM...${NC}" +cd "$ATOM_PATH" + +# Check if plugin is already enabled +if sudo -u www-data php symfony tools:list-plugins | grep -q "$PLUGIN_NAME"; then + echo -e "${GREEN}✓ Plugin already enabled${NC}" +else + sudo -u www-data php symfony tools:enable-plugin "$PLUGIN_NAME" + echo -e "${GREEN}✓ Plugin enabled${NC}" +fi + +echo "" +echo -e "${YELLOW}Step 5: Clearing cache...${NC}" +sudo -u www-data php symfony cc +echo -e "${GREEN}✓ Cache cleared${NC}" + +echo "" +echo -e "${YELLOW}Step 6: Restarting services...${NC}" + +# Detect PHP-FPM version +PHP_FPM_SERVICE=$(systemctl list-units --type=service | grep -o 'php[0-9.]*-fpm' | head -1) + +if [ -n "$PHP_FPM_SERVICE" ]; then + systemctl restart "$PHP_FPM_SERVICE" + echo -e "${GREEN}✓ $PHP_FPM_SERVICE restarted${NC}" +else + echo -e "${YELLOW}Warning: Could not detect PHP-FPM service${NC}" +fi + +if systemctl is-active --quiet nginx; then + systemctl restart nginx + echo -e "${GREEN}✓ Nginx restarted${NC}" +else + echo -e "${YELLOW}Warning: Nginx service not found${NC}" +fi + +echo "" +echo -e "${GREEN}========================================${NC}" +echo -e "${GREEN}Installation Complete!${NC}" +echo -e "${GREEN}========================================${NC}" +echo "" +echo -e "${YELLOW}Next Steps:${NC}" +echo "1. Configure your IIIF server URL in:" +echo " $ATOM_PATH/apps/qubit/config/app.yml" +echo "" +echo "2. Add the following configuration:" +echo " ${GREEN}all:${NC}" +echo " ${GREEN} iiif:${NC}" +echo " ${GREEN} base_url: https://your-iiif-server.com/iiif/2${NC}" +echo " ${GREEN} enable_manifests: true${NC}" +echo "" +echo "3. Clear cache again:" +echo " ${GREEN}sudo php $ATOM_PATH/symfony cc${NC}" +echo "" +echo "4. Use the component in your templates:" +echo " ${GREEN} \$resource)); ?>${NC}" +echo "" +echo -e "For more information, see: ${GREEN}$PLUGIN_PATH/README.md${NC}" +echo "" diff --git a/plugins/arIiifPlugin/js/iiif-carousel.js b/plugins/arIiifPlugin/js/iiif-carousel.js new file mode 100644 index 0000000000..b7831dff1d --- /dev/null +++ b/plugins/arIiifPlugin/js/iiif-carousel.js @@ -0,0 +1,271 @@ +/** + * IIIF Image Carousel for AtoM + * Rotating IIIF images display using OpenSeadragon + */ + +(function($) { + 'use strict'; + + var IIIFCarousel = function(element, options) { + this.element = element; + this.$element = $(element); + this.options = $.extend({}, IIIFCarousel.DEFAULTS, options); + this.currentIndex = 0; + this.viewer = null; + this.autoRotateInterval = null; + this.init(); + }; + + IIIFCarousel.DEFAULTS = { + autoRotate: true, + rotateInterval: 5000, // 5 seconds + showNavigation: true, + showThumbnails: false, + images: [] // Array of IIIF manifest URLs or info.json URLs + }; + + IIIFCarousel.prototype = { + init: function() { + this.buildCarousel(); + this.initializeViewer(); + this.bindEvents(); + + if (this.options.autoRotate) { + this.startAutoRotate(); + } + }, + + buildCarousel: function() { + var html = ''; + + this.$element.html(html); + this.$viewerContainer = this.$element.find('.iiif-viewer-container'); + this.viewerId = this.$viewerContainer.attr('id'); + }, + + initializeViewer: function() { + if (typeof OpenSeadragon === 'undefined') { + console.error('OpenSeadragon library is required for IIIF viewer'); + return; + } + + this.viewer = OpenSeadragon({ + id: this.viewerId, + prefixUrl: '/plugins/arDominionPlugin/images/openseadragon/', + tileSources: this.getTileSource(0), + showNavigationControl: true, + navigationControlAnchor: OpenSeadragon.ControlAnchor.TOP_RIGHT, + showRotationControl: true, + showHomeControl: true, + showFullPageControl: true, + showZoomControl: true, + sequenceMode: false, + preserveViewport: false, + constrainDuringPan: true, + visibilityRatio: 1.0, + minZoomImageRatio: 0.8, + maxZoomPixelRatio: 2 + }); + + this.loadThumbnails(); + }, + + getTileSource: function(index) { + if (!this.options.images[index]) { + return null; + } + + var imageUrl = this.options.images[index]; + + // Check if it's a full info.json URL or just the base IIIF URL + if (imageUrl.indexOf('info.json') === -1) { + imageUrl = imageUrl + '/info.json'; + } + + return imageUrl; + }, + + loadThumbnails: function() { + if (!this.options.showThumbnails) { + return; + } + + var $thumbnailContainer = this.$element.find('.iiif-carousel-thumbnails'); + var self = this; + + this.options.images.forEach(function(imageUrl, index) { + var thumbnailUrl = imageUrl.replace('/info.json', '') + '/full/150,/0/default.jpg'; + + var $thumb = $('
' + + 'Thumbnail ' + (index + 1) + '' + + '
'); + + $thumb.on('click', function() { + self.goToSlide(index); + }); + + $thumbnailContainer.append($thumb); + }); + }, + + bindEvents: function() { + var self = this; + + this.$element.find('.iiif-prev').on('click', function(e) { + e.preventDefault(); + self.prev(); + }); + + this.$element.find('.iiif-next').on('click', function(e) { + e.preventDefault(); + self.next(); + }); + + this.$element.find('.iiif-play-pause').on('click', function(e) { + e.preventDefault(); + self.toggleAutoRotate(); + }); + + // Keyboard navigation + $(document).on('keydown', function(e) { + if (self.$element.is(':visible')) { + if (e.keyCode === 37) { // Left arrow + self.prev(); + } else if (e.keyCode === 39) { // Right arrow + self.next(); + } + } + }); + }, + + next: function() { + this.currentIndex = (this.currentIndex + 1) % this.options.images.length; + this.updateViewer(); + }, + + prev: function() { + this.currentIndex = (this.currentIndex - 1 + this.options.images.length) % this.options.images.length; + this.updateViewer(); + }, + + goToSlide: function(index) { + this.currentIndex = index; + this.updateViewer(); + }, + + updateViewer: function() { + if (this.viewer) { + this.viewer.open(this.getTileSource(this.currentIndex)); + this.updateCounter(); + this.updateThumbnails(); + } + }, + + updateCounter: function() { + this.$element.find('.current-slide').text(this.currentIndex + 1); + }, + + updateThumbnails: function() { + if (this.options.showThumbnails) { + this.$element.find('.iiif-thumbnail').removeClass('active'); + this.$element.find('.iiif-thumbnail').eq(this.currentIndex).addClass('active'); + } + }, + + startAutoRotate: function() { + var self = this; + this.autoRotateInterval = setInterval(function() { + self.next(); + }, this.options.rotateInterval); + + this.$element.find('.iiif-play-pause .icon-pause').removeClass('icon-pause').addClass('icon-play'); + }, + + stopAutoRotate: function() { + if (this.autoRotateInterval) { + clearInterval(this.autoRotateInterval); + this.autoRotateInterval = null; + } + + this.$element.find('.iiif-play-pause .icon-play').removeClass('icon-play').addClass('icon-pause'); + }, + + toggleAutoRotate: function() { + if (this.autoRotateInterval) { + this.stopAutoRotate(); + } else { + this.startAutoRotate(); + } + }, + + destroy: function() { + this.stopAutoRotate(); + if (this.viewer) { + this.viewer.destroy(); + } + this.$element.empty(); + } + }; + + // jQuery plugin definition + $.fn.iiifCarousel = function(option) { + return this.each(function() { + var $this = $(this); + var data = $this.data('iiif.carousel'); + var options = typeof option === 'object' && option; + + if (!data) { + $this.data('iiif.carousel', (data = new IIIFCarousel(this, options))); + } + + if (typeof option === 'string') { + data[option](); + } + }); + }; + + $.fn.iiifCarousel.Constructor = IIIFCarousel; + +})(jQuery); + +// Initialize on document ready +jQuery(document).ready(function($) { + // Auto-initialize any elements with data-iiif-carousel attribute + $('[data-iiif-carousel]').each(function() { + var $this = $(this); + var images = $this.data('iiif-images') || []; + + $this.iiifCarousel({ + images: images, + autoRotate: $this.data('auto-rotate') !== false, + rotateInterval: $this.data('rotate-interval') || 5000, + showNavigation: $this.data('show-navigation') !== false, + showThumbnails: $this.data('show-thumbnails') === true + }); + }); +}); diff --git a/plugins/arIiifPlugin/lib/arIiifPluginComponents.class.php b/plugins/arIiifPlugin/lib/arIiifPluginComponents.class.php new file mode 100644 index 0000000000..a7a942de1d --- /dev/null +++ b/plugins/arIiifPlugin/lib/arIiifPluginComponents.class.php @@ -0,0 +1,172 @@ +resource)) + { + return sfView::NONE; + } + + $this->images = array(); + + if ($this->resource instanceof QubitDigitalObject) + { + $this->images = $this->getDigitalObjectIIIFImages($this->resource); + } + else if ($this->resource instanceof QubitInformationObject) + { + $this->images = $this->getInformationObjectIIIFImages($this->resource); + } + + if (empty($this->images)) + { + return sfView::NONE; + } + + $config = sfConfig::get('app_iiif_carousel', array( + 'auto_rotate' => true, + 'rotate_interval' => 5000, + 'show_navigation' => true, + 'show_thumbnails' => false, + 'viewer_height' => 600 + )); + + $this->autoRotate = isset($this->autoRotate) ? $this->autoRotate : $config['auto_rotate']; + $this->rotateInterval = isset($this->rotateInterval) ? $this->rotateInterval : $config['rotate_interval']; + $this->showNavigation = isset($this->showNavigation) ? $this->showNavigation : $config['show_navigation']; + $this->showThumbnails = isset($this->showThumbnails) ? $this->showThumbnails : $config['show_thumbnails']; + $this->viewerHeight = isset($this->viewerHeight) ? $this->viewerHeight : $config['viewer_height']; + + $this->carouselId = 'iiif-carousel-' . uniqid(); + $this->addAssets(); + } + + /** + * Display simple IIIF viewer + */ + public function executeViewer($request) + { + if (!isset($this->resource) || !$this->resource instanceof QubitDigitalObject) + { + return sfView::NONE; + } + + $images = $this->getDigitalObjectIIIFImages($this->resource); + + if (empty($images)) + { + return sfView::NONE; + } + + $this->iiifUrl = $images[0]['url']; + $this->imageLabel = isset($images[0]['label']) ? $images[0]['label'] : ''; + + $config = sfConfig::get('app_iiif_carousel', array('viewer_height' => 600)); + $this->viewerHeight = isset($this->viewerHeight) ? $this->viewerHeight : $config['viewer_height']; + $this->viewerId = 'iiif-viewer-' . uniqid(); + $this->addAssets(); + } + + /** + * Get IIIF images from a digital object + */ + protected function getDigitalObjectIIIFImages($digitalObject) + { + $images = array(); + + // Check for IIIF manifest URL property using Criteria + $criteria = new Criteria; + $criteria->add(QubitProperty::OBJECT_ID, $digitalObject->id); + $criteria->add(QubitProperty::NAME, 'iiifManifestUrl'); + + foreach (QubitProperty::get($criteria) as $property) + { + $images[] = array( + 'url' => $property->value, + 'label' => $digitalObject->name, + 'identifier' => $digitalObject->id + ); + + return $images; + } + + // Construct IIIF URL from file path + if (null !== $digitalObject->path) + { + $iiifBaseUrl = sfConfig::get('app_iiif_base_url'); + + if (!empty($iiifBaseUrl)) + { + $identifier = $this->getIIIFIdentifier($digitalObject); + + $images[] = array( + 'url' => rtrim($iiifBaseUrl, '/') . '/' . $identifier . '/info.json', + 'label' => $digitalObject->name, + 'identifier' => $digitalObject->id, + 'path' => $digitalObject->path + ); + } + } + + return $images; + } + + /** + * Get IIIF images from an information object + */ + protected function getInformationObjectIIIFImages($informationObject) + { + $images = array(); + + $criteria = new Criteria; + $criteria->add(QubitDigitalObject::OBJECT_ID, $informationObject->id); + $criteria->addAscendingOrderByColumn(QubitDigitalObject::SEQUENCE); + + foreach (QubitDigitalObject::get($criteria) as $digitalObject) + { + $digitalObjectImages = $this->getDigitalObjectIIIFImages($digitalObject); + $images = array_merge($images, $digitalObjectImages); + } + + return $images; + } + + /** + * Generate IIIF identifier from digital object + */ + protected function getIIIFIdentifier($digitalObject) + { + if (null !== $digitalObject->checksum) + { + return $digitalObject->checksum; + } + + $filename = pathinfo($digitalObject->path, PATHINFO_FILENAME); + $identifier = preg_replace('/[^a-zA-Z0-9_-]/', '_', $filename); + + return $identifier; + } + + /** + * Add required CSS and JavaScript assets + */ + protected function addAssets() + { + $response = $this->getResponse(); + $response->addJavaScript('/plugins/arIiifPlugin/vendor/openseadragon/openseadragon.min.js', 'last'); + $response->addJavaScript('/plugins/arIiifPlugin/js/iiif-carousel.js', 'last'); + $response->addStylesheet('/plugins/arIiifPlugin/css/iiif-carousel.css', 'last'); + } +} diff --git a/plugins/arIiifPlugin/lib/arIiifPluginComponents.class.php.backup b/plugins/arIiifPlugin/lib/arIiifPluginComponents.class.php.backup new file mode 100644 index 0000000000..882a544962 --- /dev/null +++ b/plugins/arIiifPlugin/lib/arIiifPluginComponents.class.php.backup @@ -0,0 +1,209 @@ +resource)) + { + return sfView::NONE; + } + + // Initialize images array + $this->images = array(); + + // Check if this is a digital object with IIIF support + if ($this->resource instanceof QubitDigitalObject) + { + $this->images = $this->getDigitalObjectIIIFImages($this->resource); + } + // Check if this is an information object with multiple digital objects + else if ($this->resource instanceof QubitInformationObject) + { + $this->images = $this->getInformationObjectIIIFImages($this->resource); + } + + // If no images found, don't display component + if (empty($this->images)) + { + return sfView::NONE; + } + + // Load configuration + $config = sfConfig::get('app_iiif_carousel', array()); + + // Set options with defaults from configuration + $this->autoRotate = isset($this->autoRotate) ? $this->autoRotate : $config['auto_rotate']; + $this->rotateInterval = isset($this->rotateInterval) ? $this->rotateInterval : $config['rotate_interval']; + $this->showNavigation = isset($this->showNavigation) ? $this->showNavigation : $config['show_navigation']; + $this->showThumbnails = isset($this->showThumbnails) ? $this->showThumbnails : $config['show_thumbnails']; + $this->viewerHeight = isset($this->viewerHeight) ? $this->viewerHeight : $config['viewer_height']; + + // Generate unique ID for this carousel instance + $this->carouselId = 'iiif-carousel-' . uniqid(); + + // Add required assets to response + $this->addAssets(); + } + + /** + * Display simple IIIF viewer (non-carousel, single image) + * + * @param sfRequest $request A request object + */ + public function executeViewer($request) + { + // Get the digital object + if (!isset($this->resource) || !$this->resource instanceof QubitDigitalObject) + { + return sfView::NONE; + } + + // Get IIIF URL + $images = $this->getDigitalObjectIIIFImages($this->resource); + + if (empty($images)) + { + return sfView::NONE; + } + + $this->iiifUrl = $images[0]['url']; + $this->imageLabel = isset($images[0]['label']) ? $images[0]['label'] : ''; + + // Load configuration + $config = sfConfig::get('app_iiif_carousel', array()); + + // Set viewer height + $this->viewerHeight = isset($this->viewerHeight) ? $this->viewerHeight : $config['viewer_height']; + + // Generate unique ID + $this->viewerId = 'iiif-viewer-' . uniqid(); + + // Add assets + $this->addAssets(); + } + + /** + * Get IIIF images from a digital object + * + * @param QubitDigitalObject $digitalObject + * @return array + */ + protected function getDigitalObjectIIIFImages($digitalObject) + { + $images = array(); + + // Check if digital object has IIIF manifest URL in properties + foreach ($digitalObject->getProperties(null, 'iiifManifestUrl') as $property) + { + $images[] = array( + 'url' => $property->value, + 'label' => $digitalObject->name, + 'identifier' => $digitalObject->id + ); + + // Return first match + return $images; + } + + // Check master file path and construct IIIF URL + if (null !== $digitalObject->path) + { + // Get IIIF base URL from configuration + $iiifBaseUrl = sfConfig::get('app_iiif_base_url'); + + if (!empty($iiifBaseUrl)) + { + // Construct IIIF URL from file identifier + $identifier = $this->getIIIFIdentifier($digitalObject); + + $images[] = array( + 'url' => rtrim($iiifBaseUrl, '/') . '/' . $identifier . '/info.json', + 'label' => $digitalObject->name, + 'identifier' => $digitalObject->id, + 'path' => $digitalObject->path + ); + } + } + + return $images; + } + + /** + * Get IIIF images from an information object (multiple digital objects) + * + * @param QubitInformationObject $informationObject + * @return array + */ + protected function getInformationObjectIIIFImages($informationObject) + { + $images = array(); + + // Get all digital objects for this information object + $criteria = new Criteria; + $criteria->add(QubitDigitalObject::OBJECT_ID, $informationObject->id); + $criteria->addAscendingOrderByColumn(QubitDigitalObject::SEQUENCE); + + foreach (QubitDigitalObject::get($criteria) as $digitalObject) + { + $digitalObjectImages = $this->getDigitalObjectIIIFImages($digitalObject); + $images = array_merge($images, $digitalObjectImages); + } + + return $images; + } + + /** + * Generate IIIF identifier from digital object + * + * @param QubitDigitalObject $digitalObject + * @return string + */ + protected function getIIIFIdentifier($digitalObject) + { + // Use the digital object's checksum if available + if (null !== $digitalObject->checksum) + { + return $digitalObject->checksum; + } + + // Or use the filename without extension + $filename = pathinfo($digitalObject->path, PATHINFO_FILENAME); + + // Clean filename for URL + $identifier = preg_replace('/[^a-zA-Z0-9_-]/', '_', $filename); + + return $identifier; + } + + /** + * Add required CSS and JavaScript assets + */ + protected function addAssets() + { + $response = $this->getResponse(); + + // Add OpenSeadragon library + $response->addJavaScript('/plugins/arIiifPlugin/vendor/openseadragon/openseadragon.min.js', 'last'); + + // Add IIIF carousel JavaScript + $response->addJavaScript('/plugins/arIiifPlugin/js/iiif-carousel.js', 'last'); + + // Add IIIF carousel CSS + $response->addStylesheet('/plugins/arIiifPlugin/css/iiif-carousel.css', 'last'); + } +} diff --git a/plugins/arIiifPlugin/modules/arIiifPlugin/actions/components.class.php b/plugins/arIiifPlugin/modules/arIiifPlugin/actions/components.class.php new file mode 100644 index 0000000000..a7a942de1d --- /dev/null +++ b/plugins/arIiifPlugin/modules/arIiifPlugin/actions/components.class.php @@ -0,0 +1,172 @@ +resource)) + { + return sfView::NONE; + } + + $this->images = array(); + + if ($this->resource instanceof QubitDigitalObject) + { + $this->images = $this->getDigitalObjectIIIFImages($this->resource); + } + else if ($this->resource instanceof QubitInformationObject) + { + $this->images = $this->getInformationObjectIIIFImages($this->resource); + } + + if (empty($this->images)) + { + return sfView::NONE; + } + + $config = sfConfig::get('app_iiif_carousel', array( + 'auto_rotate' => true, + 'rotate_interval' => 5000, + 'show_navigation' => true, + 'show_thumbnails' => false, + 'viewer_height' => 600 + )); + + $this->autoRotate = isset($this->autoRotate) ? $this->autoRotate : $config['auto_rotate']; + $this->rotateInterval = isset($this->rotateInterval) ? $this->rotateInterval : $config['rotate_interval']; + $this->showNavigation = isset($this->showNavigation) ? $this->showNavigation : $config['show_navigation']; + $this->showThumbnails = isset($this->showThumbnails) ? $this->showThumbnails : $config['show_thumbnails']; + $this->viewerHeight = isset($this->viewerHeight) ? $this->viewerHeight : $config['viewer_height']; + + $this->carouselId = 'iiif-carousel-' . uniqid(); + $this->addAssets(); + } + + /** + * Display simple IIIF viewer + */ + public function executeViewer($request) + { + if (!isset($this->resource) || !$this->resource instanceof QubitDigitalObject) + { + return sfView::NONE; + } + + $images = $this->getDigitalObjectIIIFImages($this->resource); + + if (empty($images)) + { + return sfView::NONE; + } + + $this->iiifUrl = $images[0]['url']; + $this->imageLabel = isset($images[0]['label']) ? $images[0]['label'] : ''; + + $config = sfConfig::get('app_iiif_carousel', array('viewer_height' => 600)); + $this->viewerHeight = isset($this->viewerHeight) ? $this->viewerHeight : $config['viewer_height']; + $this->viewerId = 'iiif-viewer-' . uniqid(); + $this->addAssets(); + } + + /** + * Get IIIF images from a digital object + */ + protected function getDigitalObjectIIIFImages($digitalObject) + { + $images = array(); + + // Check for IIIF manifest URL property using Criteria + $criteria = new Criteria; + $criteria->add(QubitProperty::OBJECT_ID, $digitalObject->id); + $criteria->add(QubitProperty::NAME, 'iiifManifestUrl'); + + foreach (QubitProperty::get($criteria) as $property) + { + $images[] = array( + 'url' => $property->value, + 'label' => $digitalObject->name, + 'identifier' => $digitalObject->id + ); + + return $images; + } + + // Construct IIIF URL from file path + if (null !== $digitalObject->path) + { + $iiifBaseUrl = sfConfig::get('app_iiif_base_url'); + + if (!empty($iiifBaseUrl)) + { + $identifier = $this->getIIIFIdentifier($digitalObject); + + $images[] = array( + 'url' => rtrim($iiifBaseUrl, '/') . '/' . $identifier . '/info.json', + 'label' => $digitalObject->name, + 'identifier' => $digitalObject->id, + 'path' => $digitalObject->path + ); + } + } + + return $images; + } + + /** + * Get IIIF images from an information object + */ + protected function getInformationObjectIIIFImages($informationObject) + { + $images = array(); + + $criteria = new Criteria; + $criteria->add(QubitDigitalObject::OBJECT_ID, $informationObject->id); + $criteria->addAscendingOrderByColumn(QubitDigitalObject::SEQUENCE); + + foreach (QubitDigitalObject::get($criteria) as $digitalObject) + { + $digitalObjectImages = $this->getDigitalObjectIIIFImages($digitalObject); + $images = array_merge($images, $digitalObjectImages); + } + + return $images; + } + + /** + * Generate IIIF identifier from digital object + */ + protected function getIIIFIdentifier($digitalObject) + { + if (null !== $digitalObject->checksum) + { + return $digitalObject->checksum; + } + + $filename = pathinfo($digitalObject->path, PATHINFO_FILENAME); + $identifier = preg_replace('/[^a-zA-Z0-9_-]/', '_', $filename); + + return $identifier; + } + + /** + * Add required CSS and JavaScript assets + */ + protected function addAssets() + { + $response = $this->getResponse(); + $response->addJavaScript('/plugins/arIiifPlugin/vendor/openseadragon/openseadragon.min.js', 'last'); + $response->addJavaScript('/plugins/arIiifPlugin/js/iiif-carousel.js', 'last'); + $response->addStylesheet('/plugins/arIiifPlugin/css/iiif-carousel.css', 'last'); + } +} diff --git a/plugins/arIiifPlugin/modules/arIiifPlugin/templates/_carousel.php b/plugins/arIiifPlugin/modules/arIiifPlugin/templates/_carousel.php new file mode 100644 index 0000000000..cfd2000fb8 --- /dev/null +++ b/plugins/arIiifPlugin/modules/arIiifPlugin/templates/_carousel.php @@ -0,0 +1,96 @@ + + + + + + + +
+ + +
+ diff --git a/plugins/arIiifPlugin/modules/arIiifPlugin/templates/_viewer.php b/plugins/arIiifPlugin/modules/arIiifPlugin/templates/_viewer.php new file mode 100644 index 0000000000..69c8a3ba20 --- /dev/null +++ b/plugins/arIiifPlugin/modules/arIiifPlugin/templates/_viewer.php @@ -0,0 +1,148 @@ +"; ?> + +\n"; + +// Normalize +$clean = preg_replace('#^/uploads/#', '', $raw); +$clean = trim($clean, "/"); + +// Extract +$filename = basename($clean); +$folder = dirname($clean); + +// Encode folder +$encodedFolder = str_replace('/', '_SL_', $folder); + +// Final ID +$encoded = $encodedFolder . "_SL_" . $filename; + +// IIIF URL +$base = rtrim(sfConfig::get("app_base_url"), "/"); +$iiifInfo = $base . "/iiif/2/" . $encoded . "/info.json"; + +// DEBUG dump +echo "\n"; +echo "\n"; +echo "\n"; +echo "\n"; +echo "\n"; +?> + +
+ IIIF DEBUG PANEL
+ RAW:
+ CLEAN:
+ FOLDER:
+ FILE:
+ ENCODED ID:
+ IIIF INFO.JSON: +
+ +
+
+ Initializing IIIF Viewer… +
+
+ + + + + diff --git a/plugins/arIiifPlugin/modules/iiif/actions/actions.class.php b/plugins/arIiifPlugin/modules/iiif/actions/actions.class.php new file mode 100644 index 0000000000..ca6feaa9dc --- /dev/null +++ b/plugins/arIiifPlugin/modules/iiif/actions/actions.class.php @@ -0,0 +1,365 @@ +resource = QubitInformationObject::getBySlug($request->slug); + + if (null === $this->resource) + { + $this->forward404(); + } + + // Check if manifests are enabled + if (!sfConfig::get('app_iiif_enable_manifests', false)) + { + $this->forward404(); + } + + // Get all digital objects for this information object + $this->digitalObjects = $this->getDigitalObjects($this->resource); + + if (empty($this->digitalObjects)) + { + $this->forward404(); + } + + // Set response content type + $this->getResponse()->setContentType('application/json'); + $this->getResponse()->setHttpHeader('Access-Control-Allow-Origin', '*'); + + // Build manifest + $manifest = $this->buildManifest($this->resource, $this->digitalObjects); + + $this->getResponse()->setContent(json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); + return sfView::NONE; + } + + /** + * Generate IIIF manifest for a single digital object + * + * @param sfWebRequest $request + */ + public function executeObjectManifest(sfWebRequest $request) + { + // Get digital object by ID + $this->resource = QubitDigitalObject::getById($request->id); + + if (null === $this->resource) + { + $this->forward404(); + } + + // Check if manifests are enabled + if (!sfConfig::get('app_iiif_enable_manifests', false)) + { + $this->forward404(); + } + + // Set response content type + $this->getResponse()->setContentType('application/json'); + $this->getResponse()->setHttpHeader('Access-Control-Allow-Origin', '*'); + + // Build manifest for single object + $manifest = $this->buildSingleObjectManifest($this->resource); + + $this->getResponse()->setContent(json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); + return sfView::NONE; + } + + /** + * Canvas endpoint + * + * @param sfWebRequest $request + */ + public function executeCanvas(sfWebRequest $request) + { + $this->resource = QubitInformationObject::getBySlug($request->slug); + + if (null === $this->resource) + { + $this->forward404(); + } + + // Get canvas index + $canvasIndex = (int)$request->canvas; + + // Get digital objects + $digitalObjects = $this->getDigitalObjects($this->resource); + + if (!isset($digitalObjects[$canvasIndex])) + { + $this->forward404(); + } + + $this->getResponse()->setContentType('application/json'); + $this->getResponse()->setHttpHeader('Access-Control-Allow-Origin', '*'); + + // Build canvas + $canvas = $this->buildCanvas($digitalObjects[$canvasIndex], $canvasIndex); + + $this->getResponse()->setContent(json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); + return sfView::NONE; + } + + /** + * Get digital objects for an information object + * + * @param QubitInformationObject $resource + * @return array + */ + protected function getDigitalObjects($resource) + { + $digitalObjects = array(); + + $criteria = new Criteria; + $criteria->add(QubitDigitalObject::OBJECT_ID, $resource->id); + $criteria->addAscendingOrderByColumn(QubitDigitalObject::SEQUENCE); + + foreach (QubitDigitalObject::get($criteria) as $digitalObject) + { + // Check if this object has a valid path or IIIF URL + if (null !== $digitalObject->path || $this->hasIIIFUrl($digitalObject)) + { + $digitalObjects[] = $digitalObject; + } + } + + return $digitalObjects; + } + + /** + * Check if digital object has IIIF URL + * + * @param QubitDigitalObject $digitalObject + * @return boolean + */ + protected function hasIIIFUrl($digitalObject) + { + $criteria = new Criteria; + $criteria->add(QubitProperty::OBJECT_ID, $digitalObject->id); + $criteria->add(QubitProperty::NAME, 'iiifManifestUrl'); + + return QubitProperty::get($criteria)->count() > 0; + } + + /** + * Build IIIF Presentation API 2.1 manifest + * + * @param QubitInformationObject $resource + * @param array $digitalObjects + * @return array + */ + protected function buildManifest($resource, $digitalObjects) + { + $baseUrl = $this->getContext()->getRequest()->getUriPrefix() . + $this->getContext()->getRequest()->getRelativeUrlRoot(); + + $manifestUrl = $baseUrl . '/iiif/' . $resource->slug . '/manifest'; + $iiifBaseUrl = sfConfig::get('app_iiif_base_url'); + + $manifest = array( + '@context' => 'http://iiif.io/api/presentation/2/context.json', + '@id' => $manifestUrl, + '@type' => 'sc:Manifest', + 'label' => $resource->getTitle(array('cultureFallback' => true)), + 'metadata' => $this->buildMetadata($resource), + 'description' => strip_tags($resource->getScopeAndContent(array('cultureFallback' => true))), + 'attribution' => $resource->getRepository(array('cultureFallback' => true)), + 'logo' => $baseUrl . '/uploads/r/repository/logo/logo.png', + 'sequences' => array( + array( + '@type' => 'sc:Sequence', + 'label' => 'Image sequence', + 'canvases' => array() + ) + ) + ); + + // Build canvases + foreach ($digitalObjects as $index => $digitalObject) + { + $manifest['sequences'][0]['canvases'][] = $this->buildCanvas($digitalObject, $index); + } + + return $manifest; + } + + /** + * Build manifest for single digital object + * + * @param QubitDigitalObject $digitalObject + * @return array + */ + protected function buildSingleObjectManifest($digitalObject) + { + $baseUrl = $this->getContext()->getRequest()->getUriPrefix() . + $this->getContext()->getRequest()->getRelativeUrlRoot(); + + $manifestUrl = $baseUrl . '/iiif/object/' . $digitalObject->id . '/manifest'; + + $manifest = array( + '@context' => 'http://iiif.io/api/presentation/2/context.json', + '@id' => $manifestUrl, + '@type' => 'sc:Manifest', + 'label' => $digitalObject->name, + 'sequences' => array( + array( + '@type' => 'sc:Sequence', + 'canvases' => array( + $this->buildCanvas($digitalObject, 0) + ) + ) + ) + ); + + return $manifest; + } + + /** + * Build canvas for a digital object + * + * @param QubitDigitalObject $digitalObject + * @param int $index + * @return array + */ + protected function buildCanvas($digitalObject, $index) + { + $baseUrl = $this->getContext()->getRequest()->getUriPrefix() . + $this->getContext()->getRequest()->getRelativeUrlRoot(); + + $iiifBaseUrl = sfConfig::get('app_iiif_base_url'); + + // Get IIIF identifier + $identifier = $this->getIIIFIdentifier($digitalObject); + $imageUrl = rtrim($iiifBaseUrl, '/') . '/' . $identifier; + + // Get image dimensions (you may need to adjust this based on your setup) + $width = 1000; // Default width + $height = 1000; // Default height + + // Try to get actual dimensions if available + if (file_exists($digitalObject->getAbsolutePath())) + { + $imageSize = @getimagesize($digitalObject->getAbsolutePath()); + if ($imageSize !== false) + { + $width = $imageSize[0]; + $height = $imageSize[1]; + } + } + + $canvas = array( + '@id' => $baseUrl . '/iiif/canvas/' . $digitalObject->id, + '@type' => 'sc:Canvas', + 'label' => $digitalObject->name ?: 'Image ' . ($index + 1), + 'width' => $width, + 'height' => $height, + 'images' => array( + array( + '@type' => 'oa:Annotation', + 'motivation' => 'sc:painting', + 'resource' => array( + '@id' => $imageUrl . '/full/full/0/default.jpg', + '@type' => 'dctypes:Image', + 'format' => 'image/jpeg', + 'width' => $width, + 'height' => $height, + 'service' => array( + '@context' => 'http://iiif.io/api/image/2/context.json', + '@id' => $imageUrl, + 'profile' => 'http://iiif.io/api/image/2/level2.json' + ) + ), + 'on' => $baseUrl . '/iiif/canvas/' . $digitalObject->id + ) + ) + ); + + return $canvas; + } + + /** + * Build metadata array + * + * @param QubitInformationObject $resource + * @return array + */ + protected function buildMetadata($resource) + { + $metadata = array(); + + // Add reference code + if ($refCode = $resource->referenceCode) + { + $metadata[] = array( + 'label' => 'Reference code', + 'value' => $refCode + ); + } + + // Add creation date + if ($dates = $resource->getDates()) + { + foreach ($dates as $date) + { + $metadata[] = array( + 'label' => 'Date', + 'value' => $date->getDate(array('cultureFallback' => true)) + ); + } + } + + // Add level of description + if ($levelOfDescription = $resource->getLevelOfDescription()) + { + $metadata[] = array( + 'label' => 'Level of description', + 'value' => $levelOfDescription->__toString() + ); + } + + return $metadata; + } + + /** + * Generate IIIF identifier from digital object + * + * @param QubitDigitalObject $digitalObject + * @return string + */ + protected function getIIIFIdentifier($digitalObject) + { + $criteria = new Criteria; + $criteria->add(QubitProperty::OBJECT_ID, $digitalObject->id); + $criteria->add(QubitProperty::NAME, 'iiifIdentifier'); + + foreach (QubitProperty::get($criteria) as $property) + { + return $property->value; + } + + if (null !== $digitalObject->checksum) + { + return $digitalObject->checksum; + } + + $filename = pathinfo($digitalObject->path, PATHINFO_FILENAME); + return preg_replace('/[^a-zA-Z0-9_-]/', '_', $filename); + } +} diff --git a/plugins/arIiifPlugin/modules/iiif/actions/actions.class.php.backup b/plugins/arIiifPlugin/modules/iiif/actions/actions.class.php.backup new file mode 100644 index 0000000000..b06bb4e897 --- /dev/null +++ b/plugins/arIiifPlugin/modules/iiif/actions/actions.class.php.backup @@ -0,0 +1,365 @@ +resource = QubitInformationObject::getBySlug($request->slug); + + if (null === $this->resource) + { + $this->forward404(); + } + + // Check if manifests are enabled + if (!sfConfig::get('app_iiif_enable_manifests', false)) + { + $this->forward404(); + } + + // Get all digital objects for this information object + $this->digitalObjects = $this->getDigitalObjects($this->resource); + + if (empty($this->digitalObjects)) + { + $this->forward404(); + } + + // Set response content type + $this->getResponse()->setContentType('application/json'); + $this->getResponse()->setHttpHeader('Access-Control-Allow-Origin', '*'); + + // Build manifest + $manifest = $this->buildManifest($this->resource, $this->digitalObjects); + + $this->getResponse()->setContent(json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); + return sfView::NONE; + } + + /** + * Generate IIIF manifest for a single digital object + * + * @param sfWebRequest $request + */ + public function executeObjectManifest(sfWebRequest $request) + { + // Get digital object by ID + $this->resource = QubitDigitalObject::getById($request->id); + + if (null === $this->resource) + { + $this->forward404(); + } + + // Check if manifests are enabled + if (!sfConfig::get('app_iiif_enable_manifests', false)) + { + $this->forward404(); + } + + // Set response content type + $this->getResponse()->setContentType('application/json'); + $this->getResponse()->setHttpHeader('Access-Control-Allow-Origin', '*'); + + // Build manifest for single object + $manifest = $this->buildSingleObjectManifest($this->resource); + + $this->getResponse()->setContent(json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); + return sfView::NONE; + } + + /** + * Canvas endpoint + * + * @param sfWebRequest $request + */ + public function executeCanvas(sfWebRequest $request) + { + $this->resource = QubitInformationObject::getBySlug($request->slug); + + if (null === $this->resource) + { + $this->forward404(); + } + + // Get canvas index + $canvasIndex = (int)$request->canvas; + + // Get digital objects + $digitalObjects = $this->getDigitalObjects($this->resource); + + if (!isset($digitalObjects[$canvasIndex])) + { + $this->forward404(); + } + + $this->getResponse()->setContentType('application/json'); + $this->getResponse()->setHttpHeader('Access-Control-Allow-Origin', '*'); + + // Build canvas + $canvas = $this->buildCanvas($digitalObjects[$canvasIndex], $canvasIndex); + + $this->getResponse()->setContent(json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); + return sfView::NONE; + } + + /** + * Get digital objects for an information object + * + * @param QubitInformationObject $resource + * @return array + */ + protected function getDigitalObjects($resource) + { + $digitalObjects = array(); + + $criteria = new Criteria; + $criteria->add(QubitDigitalObject::OBJECT_ID, $resource->id); + $criteria->addAscendingOrderByColumn(QubitDigitalObject::SEQUENCE); + + foreach (QubitDigitalObject::get($criteria) as $digitalObject) + { + // Check if this object has a valid path or IIIF URL + if (null !== $digitalObject->path || $this->hasIIIFUrl($digitalObject)) + { + $digitalObjects[] = $digitalObject; + } + } + + return $digitalObjects; + } + + /** + * Check if digital object has IIIF URL + * + * @param QubitDigitalObject $digitalObject + * @return boolean + */ + protected function hasIIIFUrl($digitalObject) + { + foreach ($digitalObject->getProperties(null, 'iiifManifestUrl') as $property) + { + return true; + } + + return false; + } + + /** + * Build IIIF Presentation API 2.1 manifest + * + * @param QubitInformationObject $resource + * @param array $digitalObjects + * @return array + */ + protected function buildManifest($resource, $digitalObjects) + { + $baseUrl = $this->getContext()->getRequest()->getUriPrefix() . + $this->getContext()->getRequest()->getRelativeUrlRoot(); + + $manifestUrl = $baseUrl . '/iiif/' . $resource->slug . '/manifest'; + $iiifBaseUrl = sfConfig::get('app_iiif_base_url'); + + $manifest = array( + '@context' => 'http://iiif.io/api/presentation/2/context.json', + '@id' => $manifestUrl, + '@type' => 'sc:Manifest', + 'label' => $resource->getTitle(array('cultureFallback' => true)), + 'metadata' => $this->buildMetadata($resource), + 'description' => strip_tags($resource->getScopeAndContent(array('cultureFallback' => true))), + 'attribution' => $resource->getRepository(array('cultureFallback' => true)), + 'logo' => $baseUrl . '/uploads/r/repository/logo/logo.png', + 'sequences' => array( + array( + '@type' => 'sc:Sequence', + 'label' => 'Image sequence', + 'canvases' => array() + ) + ) + ); + + // Build canvases + foreach ($digitalObjects as $index => $digitalObject) + { + $manifest['sequences'][0]['canvases'][] = $this->buildCanvas($digitalObject, $index); + } + + return $manifest; + } + + /** + * Build manifest for single digital object + * + * @param QubitDigitalObject $digitalObject + * @return array + */ + protected function buildSingleObjectManifest($digitalObject) + { + $baseUrl = $this->getContext()->getRequest()->getUriPrefix() . + $this->getContext()->getRequest()->getRelativeUrlRoot(); + + $manifestUrl = $baseUrl . '/iiif/object/' . $digitalObject->id . '/manifest'; + + $manifest = array( + '@context' => 'http://iiif.io/api/presentation/2/context.json', + '@id' => $manifestUrl, + '@type' => 'sc:Manifest', + 'label' => $digitalObject->name, + 'sequences' => array( + array( + '@type' => 'sc:Sequence', + 'canvases' => array( + $this->buildCanvas($digitalObject, 0) + ) + ) + ) + ); + + return $manifest; + } + + /** + * Build canvas for a digital object + * + * @param QubitDigitalObject $digitalObject + * @param int $index + * @return array + */ + protected function buildCanvas($digitalObject, $index) + { + $baseUrl = $this->getContext()->getRequest()->getUriPrefix() . + $this->getContext()->getRequest()->getRelativeUrlRoot(); + + $iiifBaseUrl = sfConfig::get('app_iiif_base_url'); + + // Get IIIF identifier + $identifier = $this->getIIIFIdentifier($digitalObject); + $imageUrl = rtrim($iiifBaseUrl, '/') . '/' . $identifier; + + // Get image dimensions (you may need to adjust this based on your setup) + $width = 1000; // Default width + $height = 1000; // Default height + + // Try to get actual dimensions if available + if (file_exists($digitalObject->getAbsolutePath())) + { + $imageSize = @getimagesize($digitalObject->getAbsolutePath()); + if ($imageSize !== false) + { + $width = $imageSize[0]; + $height = $imageSize[1]; + } + } + + $canvas = array( + '@id' => $baseUrl . '/iiif/canvas/' . $digitalObject->id, + '@type' => 'sc:Canvas', + 'label' => $digitalObject->name ?: 'Image ' . ($index + 1), + 'width' => $width, + 'height' => $height, + 'images' => array( + array( + '@type' => 'oa:Annotation', + 'motivation' => 'sc:painting', + 'resource' => array( + '@id' => $imageUrl . '/full/full/0/default.jpg', + '@type' => 'dctypes:Image', + 'format' => 'image/jpeg', + 'width' => $width, + 'height' => $height, + 'service' => array( + '@context' => 'http://iiif.io/api/image/2/context.json', + '@id' => $imageUrl, + 'profile' => 'http://iiif.io/api/image/2/level2.json' + ) + ), + 'on' => $baseUrl . '/iiif/canvas/' . $digitalObject->id + ) + ) + ); + + return $canvas; + } + + /** + * Build metadata array + * + * @param QubitInformationObject $resource + * @return array + */ + protected function buildMetadata($resource) + { + $metadata = array(); + + // Add reference code + if ($refCode = $resource->referenceCode) + { + $metadata[] = array( + 'label' => 'Reference code', + 'value' => $refCode + ); + } + + // Add creation date + if ($dates = $resource->getDates()) + { + foreach ($dates as $date) + { + $metadata[] = array( + 'label' => 'Date', + 'value' => $date->getDate(array('cultureFallback' => true)) + ); + } + } + + // Add level of description + if ($levelOfDescription = $resource->getLevelOfDescription()) + { + $metadata[] = array( + 'label' => 'Level of description', + 'value' => $levelOfDescription->__toString() + ); + } + + return $metadata; + } + + /** + * Generate IIIF identifier from digital object + * + * @param QubitDigitalObject $digitalObject + * @return string + */ + protected function getIIIFIdentifier($digitalObject) + { + // Check for IIIF identifier property + foreach ($digitalObject->getProperties(null, 'iiifIdentifier') as $property) + { + return $property->value; + } + + // Use checksum if available + if (null !== $digitalObject->checksum) + { + return $digitalObject->checksum; + } + + // Use filename + $filename = pathinfo($digitalObject->path, PATHINFO_FILENAME); + return preg_replace('/[^a-zA-Z0-9_-]/', '_', $filename); + } +} diff --git a/plugins/arIiifPlugin/modules/iiif/actions/actions.class.php.bak b/plugins/arIiifPlugin/modules/iiif/actions/actions.class.php.bak new file mode 100644 index 0000000000..b06bb4e897 --- /dev/null +++ b/plugins/arIiifPlugin/modules/iiif/actions/actions.class.php.bak @@ -0,0 +1,365 @@ +resource = QubitInformationObject::getBySlug($request->slug); + + if (null === $this->resource) + { + $this->forward404(); + } + + // Check if manifests are enabled + if (!sfConfig::get('app_iiif_enable_manifests', false)) + { + $this->forward404(); + } + + // Get all digital objects for this information object + $this->digitalObjects = $this->getDigitalObjects($this->resource); + + if (empty($this->digitalObjects)) + { + $this->forward404(); + } + + // Set response content type + $this->getResponse()->setContentType('application/json'); + $this->getResponse()->setHttpHeader('Access-Control-Allow-Origin', '*'); + + // Build manifest + $manifest = $this->buildManifest($this->resource, $this->digitalObjects); + + $this->getResponse()->setContent(json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); + return sfView::NONE; + } + + /** + * Generate IIIF manifest for a single digital object + * + * @param sfWebRequest $request + */ + public function executeObjectManifest(sfWebRequest $request) + { + // Get digital object by ID + $this->resource = QubitDigitalObject::getById($request->id); + + if (null === $this->resource) + { + $this->forward404(); + } + + // Check if manifests are enabled + if (!sfConfig::get('app_iiif_enable_manifests', false)) + { + $this->forward404(); + } + + // Set response content type + $this->getResponse()->setContentType('application/json'); + $this->getResponse()->setHttpHeader('Access-Control-Allow-Origin', '*'); + + // Build manifest for single object + $manifest = $this->buildSingleObjectManifest($this->resource); + + $this->getResponse()->setContent(json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); + return sfView::NONE; + } + + /** + * Canvas endpoint + * + * @param sfWebRequest $request + */ + public function executeCanvas(sfWebRequest $request) + { + $this->resource = QubitInformationObject::getBySlug($request->slug); + + if (null === $this->resource) + { + $this->forward404(); + } + + // Get canvas index + $canvasIndex = (int)$request->canvas; + + // Get digital objects + $digitalObjects = $this->getDigitalObjects($this->resource); + + if (!isset($digitalObjects[$canvasIndex])) + { + $this->forward404(); + } + + $this->getResponse()->setContentType('application/json'); + $this->getResponse()->setHttpHeader('Access-Control-Allow-Origin', '*'); + + // Build canvas + $canvas = $this->buildCanvas($digitalObjects[$canvasIndex], $canvasIndex); + + $this->getResponse()->setContent(json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); + return sfView::NONE; + } + + /** + * Get digital objects for an information object + * + * @param QubitInformationObject $resource + * @return array + */ + protected function getDigitalObjects($resource) + { + $digitalObjects = array(); + + $criteria = new Criteria; + $criteria->add(QubitDigitalObject::OBJECT_ID, $resource->id); + $criteria->addAscendingOrderByColumn(QubitDigitalObject::SEQUENCE); + + foreach (QubitDigitalObject::get($criteria) as $digitalObject) + { + // Check if this object has a valid path or IIIF URL + if (null !== $digitalObject->path || $this->hasIIIFUrl($digitalObject)) + { + $digitalObjects[] = $digitalObject; + } + } + + return $digitalObjects; + } + + /** + * Check if digital object has IIIF URL + * + * @param QubitDigitalObject $digitalObject + * @return boolean + */ + protected function hasIIIFUrl($digitalObject) + { + foreach ($digitalObject->getProperties(null, 'iiifManifestUrl') as $property) + { + return true; + } + + return false; + } + + /** + * Build IIIF Presentation API 2.1 manifest + * + * @param QubitInformationObject $resource + * @param array $digitalObjects + * @return array + */ + protected function buildManifest($resource, $digitalObjects) + { + $baseUrl = $this->getContext()->getRequest()->getUriPrefix() . + $this->getContext()->getRequest()->getRelativeUrlRoot(); + + $manifestUrl = $baseUrl . '/iiif/' . $resource->slug . '/manifest'; + $iiifBaseUrl = sfConfig::get('app_iiif_base_url'); + + $manifest = array( + '@context' => 'http://iiif.io/api/presentation/2/context.json', + '@id' => $manifestUrl, + '@type' => 'sc:Manifest', + 'label' => $resource->getTitle(array('cultureFallback' => true)), + 'metadata' => $this->buildMetadata($resource), + 'description' => strip_tags($resource->getScopeAndContent(array('cultureFallback' => true))), + 'attribution' => $resource->getRepository(array('cultureFallback' => true)), + 'logo' => $baseUrl . '/uploads/r/repository/logo/logo.png', + 'sequences' => array( + array( + '@type' => 'sc:Sequence', + 'label' => 'Image sequence', + 'canvases' => array() + ) + ) + ); + + // Build canvases + foreach ($digitalObjects as $index => $digitalObject) + { + $manifest['sequences'][0]['canvases'][] = $this->buildCanvas($digitalObject, $index); + } + + return $manifest; + } + + /** + * Build manifest for single digital object + * + * @param QubitDigitalObject $digitalObject + * @return array + */ + protected function buildSingleObjectManifest($digitalObject) + { + $baseUrl = $this->getContext()->getRequest()->getUriPrefix() . + $this->getContext()->getRequest()->getRelativeUrlRoot(); + + $manifestUrl = $baseUrl . '/iiif/object/' . $digitalObject->id . '/manifest'; + + $manifest = array( + '@context' => 'http://iiif.io/api/presentation/2/context.json', + '@id' => $manifestUrl, + '@type' => 'sc:Manifest', + 'label' => $digitalObject->name, + 'sequences' => array( + array( + '@type' => 'sc:Sequence', + 'canvases' => array( + $this->buildCanvas($digitalObject, 0) + ) + ) + ) + ); + + return $manifest; + } + + /** + * Build canvas for a digital object + * + * @param QubitDigitalObject $digitalObject + * @param int $index + * @return array + */ + protected function buildCanvas($digitalObject, $index) + { + $baseUrl = $this->getContext()->getRequest()->getUriPrefix() . + $this->getContext()->getRequest()->getRelativeUrlRoot(); + + $iiifBaseUrl = sfConfig::get('app_iiif_base_url'); + + // Get IIIF identifier + $identifier = $this->getIIIFIdentifier($digitalObject); + $imageUrl = rtrim($iiifBaseUrl, '/') . '/' . $identifier; + + // Get image dimensions (you may need to adjust this based on your setup) + $width = 1000; // Default width + $height = 1000; // Default height + + // Try to get actual dimensions if available + if (file_exists($digitalObject->getAbsolutePath())) + { + $imageSize = @getimagesize($digitalObject->getAbsolutePath()); + if ($imageSize !== false) + { + $width = $imageSize[0]; + $height = $imageSize[1]; + } + } + + $canvas = array( + '@id' => $baseUrl . '/iiif/canvas/' . $digitalObject->id, + '@type' => 'sc:Canvas', + 'label' => $digitalObject->name ?: 'Image ' . ($index + 1), + 'width' => $width, + 'height' => $height, + 'images' => array( + array( + '@type' => 'oa:Annotation', + 'motivation' => 'sc:painting', + 'resource' => array( + '@id' => $imageUrl . '/full/full/0/default.jpg', + '@type' => 'dctypes:Image', + 'format' => 'image/jpeg', + 'width' => $width, + 'height' => $height, + 'service' => array( + '@context' => 'http://iiif.io/api/image/2/context.json', + '@id' => $imageUrl, + 'profile' => 'http://iiif.io/api/image/2/level2.json' + ) + ), + 'on' => $baseUrl . '/iiif/canvas/' . $digitalObject->id + ) + ) + ); + + return $canvas; + } + + /** + * Build metadata array + * + * @param QubitInformationObject $resource + * @return array + */ + protected function buildMetadata($resource) + { + $metadata = array(); + + // Add reference code + if ($refCode = $resource->referenceCode) + { + $metadata[] = array( + 'label' => 'Reference code', + 'value' => $refCode + ); + } + + // Add creation date + if ($dates = $resource->getDates()) + { + foreach ($dates as $date) + { + $metadata[] = array( + 'label' => 'Date', + 'value' => $date->getDate(array('cultureFallback' => true)) + ); + } + } + + // Add level of description + if ($levelOfDescription = $resource->getLevelOfDescription()) + { + $metadata[] = array( + 'label' => 'Level of description', + 'value' => $levelOfDescription->__toString() + ); + } + + return $metadata; + } + + /** + * Generate IIIF identifier from digital object + * + * @param QubitDigitalObject $digitalObject + * @return string + */ + protected function getIIIFIdentifier($digitalObject) + { + // Check for IIIF identifier property + foreach ($digitalObject->getProperties(null, 'iiifIdentifier') as $property) + { + return $property->value; + } + + // Use checksum if available + if (null !== $digitalObject->checksum) + { + return $digitalObject->checksum; + } + + // Use filename + $filename = pathinfo($digitalObject->path, PATHINFO_FILENAME); + return preg_replace('/[^a-zA-Z0-9_-]/', '_', $filename); + } +} diff --git a/plugins/arIiifPlugin/modules/iiif/templates/canvasSuccess.php b/plugins/arIiifPlugin/modules/iiif/templates/canvasSuccess.php new file mode 100644 index 0000000000..008cae2272 --- /dev/null +++ b/plugins/arIiifPlugin/modules/iiif/templates/canvasSuccess.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/plugins/arIiifPlugin/modules/iiif/templates/manifestSuccess.php b/plugins/arIiifPlugin/modules/iiif/templates/manifestSuccess.php new file mode 100644 index 0000000000..ae66651132 --- /dev/null +++ b/plugins/arIiifPlugin/modules/iiif/templates/manifestSuccess.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/plugins/arIiifPlugin/modules/iiif/templates/objectManifestSuccess.php b/plugins/arIiifPlugin/modules/iiif/templates/objectManifestSuccess.php new file mode 100644 index 0000000000..ae66651132 --- /dev/null +++ b/plugins/arIiifPlugin/modules/iiif/templates/objectManifestSuccess.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/plugins/arIiifPlugin/vendor/openseadragon/images/button_grouphover.png b/plugins/arIiifPlugin/vendor/openseadragon/images/button_grouphover.png new file mode 100644 index 0000000000000000000000000000000000000000..9db590ea2adb845fc875b2e3a1fc45ad2a5fc8c8 GIT binary patch literal 1506 zcmV<81s(c{P);M1%f1T;mr?<=Ha+c?L;^&`#KKSXUpPrTg1t>37V40yV4#or#e*E#rTU>{zSFhgW zP$<;V_kB_-7K@ZjCifmZc<{GZUw!qH4?q0yFcD>y%ups6Gl(rALXSQ6ShE{$xZ$3L z4IAEUSr)+w;$R3BLI_e&sZ@%#ZQJ(oyYIgH{>LAGypM=dPzK6LpkgVIxCoH&>eZ_k zckI~lb%x-<7(}_DLY?#9Fcd43${X2YXY(jFqV|dAZymF zxw%c7HZRz=O@%^%^7%Z&C?Fj~fd=BgbsUFcu^3gaUVU7jK7BGj{P4q8mEbx=DU8XL z@Q*+KI2Mk)6Ap(Ng6&rW8$*XuVC+!Mnl%YAtZv=9+mkZACHM@hS z2OvgA^n2>s1jkbbclp>7t1z)_*|KeF$?J7UcSbL0p*nTy{GT6yB;+^K-&jcj7^Oh? zw+zFp3%N&4n>L+AMAe`ukE0b(VVRtH?z!iBVtTr2346|5Q7cD3SHZtiK>Qqbxj};l zZHEmT)?I^f)HIo#aay--J&s*b^X(M@!+r`PAN;N*$hKUvh08y}xkZ++0pj2q=e8~H zS^883E;nx6nDb{S5k(Y?a>gMov}x*sr1g{WxUd|DLLrCj0tRD7eGP#NX zlgERK~Xvi?Ezli)#YZBFEZ|(Y0Lkw1Q`Z@t^{#@0RAxn{Vua;K6yyt~A&cOh0YhxN#qx-=S?KSl+qXfz86c z#X;7OYu~;-KSVXk%M!bY=h5e%e@<}y8?3JNL{tvNp^S9N(_w@rXEy?G(-G0$bzLs! zsx4fSIBM0ZMJG<2V3?K1k01Yth|VyK+Hk4dQ7~lcQK-W4y?gi088Bc#@ZfYh%{g?@ zj&ShyfnNqKhRVy!--E+EMP<^JG?X*Llze)eJbCg2lCEsircI;!_3KB~s#Rkk)vwMg z20$MQTFTQ;Kg}!XJ-GV^5uJuApoF&L^UvjsufrkPc49>wMBA^6Xxg=FS5-v==~Kt| zxu>Dy2R#TIDSGk67dhu%LVNj9f|N5zsVl}kaLN8RA~!-c9LH&dy~rJ~ec{xpQ>jar zEaC28jaGiW5;Oo=FRloci$0e)vuV=FYz+Rv^Yd625E!+2`^i&s$9?*jGbH$r+&xrs2seKkIE7AhWz3`Ra^#=ifM|V4z=Pu#lUIk zh#Vv#<&%B*`3jhEB07*qo IM6N<$g437j#Q*>R literal 0 HcmV?d00001 diff --git a/plugins/arIiifPlugin/vendor/openseadragon/images/button_hover.png b/plugins/arIiifPlugin/vendor/openseadragon/images/button_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..645c241b9fd4ceb3b2dc44ad9dc81c323ccdf803 GIT binary patch literal 1827 zcmV+;2i*9HP)Kn2s5j9y2q;GEZPKnIyKmyRNg-y0dZ~ zy?I(F=~JzDpuhQTH-vEJRrEXfjDOJ@iahXr_?mMvTyT9>WGIJlNQcP%n>_5X4l~sG zp`_?xN+?e-;B9Yv+sGT<@P-X(nhIkK?cTlnQ}$|$f$GZk>Wr-?AwirNc#$c8CDSsL4$;ZlOlku0Eh{$nAs8-ER2B}NEvOB z8m25k*GMsYtP{?xZ*O?|)1SV>rPJ|3%BO^)WYqTU+n*5~yCv=(m(nOLNu>m%!301M zGyq};{cl-X@v#gmh{(cPW`Gq9dXm7ThI+?Aa})dHEnBuc-pSkzAoLExL8{=jmaevn zLwAPBp#?S*u?PYovGV4)=73nSu?`^sFbDuMF);%YBnA>BhyjqvIO{Ciq}3Lc`ED2l z8`c4cyohv&)!rtNW!YHJTnKEVDY2MZUQhu1cqk~Mm9G$p`Tu8kQbLMmN@SL0Wl05E z&sB#+Xf+vHT3TX}^hKO3D@mG^lsKbO1l`jpaUz$K&~!Q-6s-7AD5zGewbUo#5z`IW zWI~c)oJmO{nHWSelS@|i-5=X4bS~JT@u^d%4x9`}(#@rwG#yP+)0xQ_KrmBW%EZ3@ zSlVbb^0P2|3T5n_ciwr^txw+2dEs1tKG|;t35HYvDFF%uAPEpyt^6wD!hjP2MqnO&h{*l|dTQ}R~I1LD>0aOK0 zaovGcUfM}fdCK!2cd9n2 zvoLc)Tpftee+Q-l33d`TA~2jtZ1Lc{?7r(CWBZz|_AagUegI9MO3#rF$rK+&>h*e4 z22tnY`rOv1J-HokjM7L$z*JYH;H21rGQm1dOAL?%X$jR)iyN!5{np=BA3WJy-qY*# zt_4tcEIK;59Urfj3_Fk$I-DAD>d*I#v06uCPut$B42+mp2Iat^9D)EQNJEGN22We_ z!~4VIAN_TBq`uhuTaqMKdXbi+Gn`7{9(ZW~TXK{gHKo+Fd#K+&H7Z{E;g>E=y?RG7 z`lwM|wkd%vKoSs&alkUG|7@46A8VK!wAL3h^U2(EvXpyP^jc&nzYliAj;f<3 zrJRZ5_@zRKCo=Qwqt@$atjw~p#O98JNQ^PZn0cS;Hv%~62XFiC6Di)1ul1-BIATvZ zN6AUe0jMx@>Ztoc5>Gcr@8KU+iW8DvD0Du;*UhmV-e1<{sZ6O!f_F; RjBo$|002ovPDHLkV1lbmc`X0{ literal 0 HcmV?d00001 diff --git a/plugins/arIiifPlugin/vendor/openseadragon/images/button_pressed.png b/plugins/arIiifPlugin/vendor/openseadragon/images/button_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..d5b1d7d0c94a08de3cc8a851523620f88df16db1 GIT binary patch literal 1895 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 literal 0 HcmV?d00001 diff --git a/plugins/arIiifPlugin/vendor/openseadragon/images/flip_grouphover.png b/plugins/arIiifPlugin/vendor/openseadragon/images/flip_grouphover.png new file mode 100644 index 0000000000000000000000000000000000000000..24c110c892c8f9210beefc92531111e6c8148329 GIT binary patch literal 4920 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 LSiP(Fsh|EA06U4g literal 0 HcmV?d00001 diff --git a/plugins/arIiifPlugin/vendor/openseadragon/images/flip_pressed.png b/plugins/arIiifPlugin/vendor/openseadragon/images/flip_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..026d55ec06395b5873780dfe0039c6b672a3fa3e GIT binary patch literal 4920 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 KMNUMnLSTZq6&5D| literal 0 HcmV?d00001 diff --git a/plugins/arIiifPlugin/vendor/openseadragon/images/fullpage_pressed.png b/plugins/arIiifPlugin/vendor/openseadragon/images/fullpage_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..6fa182aea98eb7884d7e82dc07f4975c02303564 GIT binary patch literal 2225 zcmV;i2u}BjP)X*utmM|~A_~PW% zS6{tvb93{=z|A%7-m<<@3W32?H;+ySOy9e1-MURT-+c4Z&p!Js1;8Dml+-Vgp^%|@ zVO)0EWy!0qy6Uhh$2fY`Hy_XJ+PbN>zq30Q6az_uKqSCTjbbCJvLjl@w71SWaK(nU z-QV1E&pnGi{q)l=069fLQ4EEG;X?EaM9dF9_+Z|=IkV4O^3DtU?OMKkRR8WCUQA~L z@_eZ)6^$TC0>nT}=S(k;F{`mkluw$pW7Ph~eD~@bZ+>*sO*btAkPW5WQbN3h3=7c} zrh2M_$G5gz@Xa$1oY40D()#{wol?)Z!3eJT4Z7{uo0h22%%IvZMN%_@gdkyLy+CyK zk=xx-)t}zgI_<#2cN=OqmbwyBemFu3WMN<=`{IY2sEo6B(H zDPsZ&3B85N*9akzh#b8j3x>lwMJi&rlb)g_jW!f`d3QKbMuowv2S9)yGWJ ztN>sRJ5WomCZ@(b&fToZ`g-8?_fcxcS|O%2lT$sG-d$%?yu5-gKXR<_VupP5+Ya70 z;N#*WYDI08lzz5=F|ndJtbs&!&1TB3-!3!TIxuK2k`?60f)xaTHB5wlOolR3!TN_ar2NCnO`yM>d;9i4z|TC6Y>|@;qj`iE5oWwcu8RqK>##t1)IU3}Or} zG3m1DaUb_xSu2S%oN>b{T1|{!`Bn#icU^|X$J*R!WdHg9T5zXMXF;5M{r&wOhNYB@ z9HhOyz01?}bfVrutOhJrFUeBv85Kmt0HzVj#w94xYJqqWb802terPs?kT~+Z@A2Au zdm)GrZ!yVfA{zYvSS?th*`#hyq}9V_qMKbvNg1(v_3EwdIlj$mt{@}9$*3Zxmq}up zkHKW}0;_u@ZS*+XkQLOI$zxWliP=-j5Dm8^>1Fug|Lt;4@i7(j#fH>2^{_*mUZ4;^ zCLMA{#DB2?9Voyp8(=2|$LoUtZAQI7#$1Oi7(} z)v^!O@azE47s?bA#c0ozzR!eTr_<@Ikj$IEN%{vJF|MJO`!Qtm5afe20b)?d9~csY zkU)W;=Pbk%jo4E;vGcg=mc84yJGH@e-HiZxB0}y^&qQUSkx@Cd412P9f8gaW)4Rq@ z8&ffERI(V@5W zeA6D^a^b($etOS~o91V8`K3aL9X}x=6!Ir8S;5Aq0l1-o(voD!baT)#S*)&{JrHZA6DRNC2DPdSa}=#j`H@W zrJ}`ugrSHCfkF(I_$%HL(SPzSk-s*-zrlY4x#}XU2!muN00000NkvXXu0mjf3ARyj literal 0 HcmV?d00001 diff --git a/plugins/arIiifPlugin/vendor/openseadragon/images/fullpage_rest.png b/plugins/arIiifPlugin/vendor/openseadragon/images/fullpage_rest.png new file mode 100644 index 0000000000000000000000000000000000000000..bfab64339211da4c3220a209dda18efb1ae99389 GIT binary patch literal 1309 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 VQ~vuQ5gh;k002ovPDHLkV1msc@dy9_ literal 0 HcmV?d00001 diff --git a/plugins/arIiifPlugin/vendor/openseadragon/images/home_pressed.png b/plugins/arIiifPlugin/vendor/openseadragon/images/home_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..00c349b0dd9ad581d2c48a6d7120ca0e266c4951 GIT binary patch literal 2138 zcmV-g2&MOlP) zr*iP%rM?nmX7uT`p7oybUkK8JGYWbJ7p6W;q6APw$1L!(rzEJH!QFR7f>Ojs_;86A z+KK=@gPf*BFbnF-U;gsQ>t6S|zIMA!UDqYcmoG1^TD7X?3%C-;$Mp$IouW){3H<{f z_(0~WtFC(1=;-J&CRGrwhYuCQ-eeZi4SFT)H1Yif~C3R96 z;=_Ci?ZY4baOTP@uY7UZ(q6Ic@rN#%Ik>OCGM$fjZBGzRKnMrZ6%v`3uFqSrXmY`& z&)c#mckJ<>|NQ6cR;*Yt1E3*kN!q@U7ZxI?Afn%Y|NYCBU4GfSH{5;wvyX1xd{*UH zfwfC@k2tPSrHVozhyVx$p(>+lB0`PfG*6s+?$}w+dF7M0+IF*|%zy9WfB*Gsb5Cs?tQ?vaYR&fMF~uEHO?OZ?cvjK9K27HtMe|~u zaINlme7a2R{8YM9I=bM(=e?LMSiIDg&r=?N2rpAere{|4KmPHL=U#sCMel#|pTB+M zv9&v+-b~HQQq>)`EZ#3AlDZ~hstQw6iK!^WfC2-Q8-xhM5rUSR9xu#VO{cJE;j>=Y z@&snLZQE83RT=MH+P+9PE9ako{&P3n`L|b0ZQdJ|f7ls~7~Vk26p54$MOPSA89<5r zC*ZXNcS^PpMZwi37mO%ea|CG?8n(N6uhurTS6p`4Wx0R+;~z%@4|1^lMX$^#68*aC zu6rIUO?+_diPaZ)6J@z1nm0Tzg3N+Ao9t6Hdq~&%&QGZ3f~a!q;i7)-C23|xHNss& zJO>b-pn`KsJrAVPfWhn-8|-6db~L|b%a%LyrtEt+yXIM6G;$6HAd8^LXB*MnIkdUxp+rNfX!{Y01Usr z?f|aaS5Q;W?$Z+I#1*5@P!v<49t0)hRWV3v3uKG}Fak1ELTHb&X7XbF<)dS<#@_ux zDHox4WRfP;vnE@$vq%+1L6@LR_jvhZQ~2iHhZq*e6l)|x6pK->)gbNMF=16_BD$_8 z0qCI@Dtawb=RFe@c3r3C0-QrTNO|2uqLo{N-!FfXeC7L(qEe}#6O6GSb0U;d)a!LT zx$Y3&_uU8C=A&C#b8HjZ(+3Ez6^JEThUa-kNQ4}(v`MX26B))yEFy@-1k{K}>-9-; z{zx0=el&x3eS9UlVVMjUT`+`drGy=Os_4c!i(~ld=NF68qmzVLHr3KXFjG*XxO1{S z-uS&+h+?tW%tmxO(x+0Z4QQ5t7IQJbA83yl2*$ZfqIl}IOVJ53awobGu_!K|uVXSR zP$|2VG65^5l3J8GGPBO9G*_a-C&$7$aH=R7(oV43~&@ zn;ZIt24Bq zWG13g2t-c`qDUE86$r*mzKtLK=`eouhl2=)a5=!6o#$=t_v7g(srC<-?pQs3NG?;p z+e-NG@G}!^7wrQF4s2aJZ*c9q7mvP5Ei@n^4ybA)Yt-=IPZvV5On?x0O&h%3p4(sk z>!qNoCPiErZWG+Df~g)XO+#Yw2!6DtxIUlHj|X}i`?#-z0Ls|dScz+W=EYZxo-;yA zai9TWacHWG;k1jPsExr$6GJgc!p3mI!BG6^a|2cb8Lc5DTc8bscr=THi6uur_2aD% z6$*tN0A?knfRrZ@$IDDx(#qv>o4$85dEkd1z38nYc`s$V1qfjSt}V9&p#MIb2>)>u ze)r2-3M?yw^3eIkw_myG0l7S50LqeDpzG_I8HDB@QYw||Tu^8AKH)z9rAvnTnHxd9 z1x`E=g@aH55Ds*<5Fh}+1<)c;8wR4WVT`BFnSS-Po9@XSEAFvvdoO@OS18c&iC!`Y zHOWMlVWHl1t2aGTI=bk>Mad;+Wzt3+40R6P%YNXgnS$qeHO_faa>Rd7tCEVp^+kF$YKO5nhDLfsV`FP7D zYG}|8&)RNiy!Fm-ygj*8c=-3}1`pu*+pxrcC3<}&qK4`HmB{}w{u>wk7w8WF@?bSV QcK`qY07*qoM6N<$f~LC{^Z)<= literal 0 HcmV?d00001 diff --git a/plugins/arIiifPlugin/vendor/openseadragon/images/home_rest.png b/plugins/arIiifPlugin/vendor/openseadragon/images/home_rest.png new file mode 100644 index 0000000000000000000000000000000000000000..6ac397da6208b3c05f89f49b5482e3340e6bf530 GIT binary patch literal 1258 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 literal 0 HcmV?d00001 diff --git a/plugins/arIiifPlugin/vendor/openseadragon/images/next_pressed.png b/plugins/arIiifPlugin/vendor/openseadragon/images/next_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..5297c52661475ec06ad3ca43c3494abd49cb1220 GIT binary patch literal 2411 zcmV-x36%DUP)`+p+jt9VuE#LM090CN2my$&*zntQXM&RBwT)OnHMTU9im9t;NT#;_~MH>0OJE6 z_>4I|K5FK2R&s1)q)#cuJ>^oVG+Qf`O4XxBE5YW?_jv%kC{sbPSo8~pg8yt%^jt*l zxZ@5Mr(OQ?mwy=e)_1@B#&svGTOYLQ`KiPE`u%pBfd~Wn)r(r%#e)YAK6=Hq*X}s` zwA0D}{0MJ&c-SqM%OQZETk5&UP=_cg9+iZzS+mCc$*+Gs^uc$%10@38Uet%?5eBYw0a=- zmECvW@}&b0PYf+iR*3sym@#CS;)b#rK@h3sFYwQs)l!JP-L z`R~8}wbKFSWH#GeSXgl55~>)8r|O|vtwsQhjT<+v86WKb;`ZBb_}rd5?jG^xn<~qM zKVVxb#Uc^Tv}Cjrk=7a^aTRc(T7D2Vrxtjlx+SZ<;G=JR^_$%v{q(2$%+pTWp74DY zl}tw^TNa@R&3m&F_lfbvFMd1o(GS1xlSdxB_g6%L6^U#;rX)PchXo9T2~HyVwuv464*B@ziS zH#aAL``e$q!E9H*dE}8t-rAg+VFQK{3`Y`aX%H8pBfu!S)r>K4P7zB+iog`WA`b#I zV}K^tgMgc0xeS_|m9}r+S zpF1>^ashM*BWOjYyH`H@&e!If(^GG*P8CK(t*QDAOGg=DQVK9r5EBASFc9y^@a2Yq z3ImvAKnEe(O%0_3Efm+jPteu2PS4C_hVqFG8%8su`wD0Z-){j}o-Fl*%tXCH8D#kC ze15z>S6&q^)>(>pkdlH-+aNn@la+NyCQUFyfH-@+?X_OIIaZk?iyIgwQ&%fhU7uB2 z`MwSVUt_+dGsErUj?X3Y`+&(nHI1luL^SH`3DXp9ejV80x91{lR>(z!qN2PhF7TmUOFSNBg z6Tocdl8)egK*AF3hERsFyrGgn&k9VF`+ktp&AP3tvj`eKHN%E->>TakNp{;rn+GJ3 zOeG+M5%&y1YX!y#rD6qlZaIM4w;bT_d;Kc*+5TiWJl70Wt))9fG=r8Yw6*~*l}2<| zFNr+maYok_wOTDCn4*Ni$PyZiTo!s&R++BS^$!(+MjL<~!D3{D7onCIO53PZJ>0wF zQ5xHjWgnK7vZbbuJLif5&m|yW!st2&>Mc`eH5${HpI>aJBy&?4lTyNGcG7@hfxSA( z@u!cD=)mHTl2iAlqBUS}!epg|3vM`uSFKLt3mY=}LrJOCY?NK$aVKps&*4$BT_0#_ zNC|jYSx+icYi353rc1N=0b1xEFp)Of+;K=tQ)8V)c=eE@MM8iZOveMg(leG|*epS- zJ~f7quTAQNuhFjh@KRuDQ&2V|*8XKbKm*Qn&1y(m183&cOe`OB0%Gr7mG{Q zf#UnhRdBSSv1YWk@!s;qr(Cz=y0t@g>0qT*0WcdMYy9ra=m;fwU+7@Y-FvLOcXhUJ z^V)p+z_a)#t!R$YFiw(G8abH@NQ7u}#8cl}CsMDI7% z=H|lu2>i{D9Ne38=&m=9<<`H>2-es^gDH!^B?EPx|I<@wAkIwaYZzL?&N(>D?Wt?G z9oe?;K;dvcXV(k!tyY(e?(n3{l!0jSa$cW3zp!J+)TUD)n&)TmBjrw6*YlA?N zhzVMfdVFWnE9KFlhVr!*A&^KrG@s1P{qKs&yKjB)@Sd@pIWt*r)c`aj-0ss*{#0jq z?RFc&2IW%Jp4igx0!#3<>j#F8OHfhi-%hsgFY5y*-&T6yq|5hC0D7;K#`I#tn+H&f=qc0Fp9AxF z>@CM}?5y3)6lO7$S~c>{PrfSk)~~&L_ziCvw?+qLm|~vCl+s{~0BPuAi!JP}xHH#2 zRNiyyebc)!zj$!KL0Ji7damkM0d%OxCGww(3@wj(EM$%6cxum7Eel}yEpHlo-P!?T zEX9#Ynk;9VT)JKuG~8fewxt&*7yX5Yw-%2AD31?YwV7JD*laF|G;Gp*jz<5HH{<{S002ovPDHLkV1jO%l3M@( literal 0 HcmV?d00001 diff --git a/plugins/arIiifPlugin/vendor/openseadragon/images/next_rest.png b/plugins/arIiifPlugin/vendor/openseadragon/images/next_rest.png new file mode 100644 index 0000000000000000000000000000000000000000..e3c5a3ca732014d06beb4fea48ba424ae9650a6d GIT binary patch literal 2027 zcmVHrK?Y}fL(f7Mk$*a7qo_255sbrGQ z?bGL?d$iAKDuf*s&F*lu@tO)r}iB2CrVdI`H7Z1Lx?`qqXktZl|N8!@Ya= zu5;(k9Vbp!@QKO9iEP`pO%G*H|M8E1Z28My{xWCElqr)6g+dEN(!P&>%*7r)eAsjL z?AhBNe)!?3_uhN&K9B2y_V)JL{rmSl8TLFv>P19|zd=Zh2@@uy|Ms`PwSDuO-<&^j z;>7v3ZFlRso&q{#0!)*ue1k$kwOaKC2L~S>IB?+f`t|G2?b@~L&ZSG222irr)6-KA z33*9E#*2s$bCb|y-+ue;1wZ@Q&wh{OOH+2L-84+)d7cC6s3KPpiE|r* zOJXWibv=|>7hMENb{E@Mot7GyMhjEoyM&ZZ?yKBmmT zzC?NYsJy5Xc5ppOMv*HD>CCB9r;etVlvtG;sUoZAW0@!qio{${5bzt>EnpV;uJGi^ zlQL=)@YNuVpEQ1SsX~e&P517=Uq-@MEEXd&unLXMPoOfHj0xH)Jr^nOSQskVTvGl0 z{S}&788w8Mjwvw>3ot1nhF+Odxh#s)QAxQi7<(w zh=!!Kp`jr~5=uEMCQ^{9jvYJh8q((&Ci!A$31f00=o4Oj#flY8RAZHK>5lTA0NjF9nf-@g5X?&wu2rAAre#KVThj~{=AUU8cwl`1lU7B?Xd0hdCk z;A1=+>yg>BXJ24pRZ)&=GC5A@B>1olmwk+PLJB0v&<6rm<#B+z#i3}pT%MQZ0|Q4M zR+pq^vO#jjh!QtRMwDRznP2|$mnX=xK8_7Kd8G4=D4o52{kqE$;|U9@p-}ALl^_Fw z075SN$i2yvCqDpFSbdgU7yzCm^`l3RTn*!SpgqGFr>LGmQH_I^j=5o8WeI=z=FOWm zhCPxHqLBC!_{k0&0H5lS7b6h63@KO25a*W2%nBPxEs*d%3jrnxiu}5alW#;_$P{<% z*kMs=kEFjcMo85`sLsPpZrw1I)Il|rcoq>76`qS|45rgx@`SEq z?b@{gs@$R_JjCCi)C#Bp_j$^Q`Bahv`znfGMV-t+*nLS_IY!t{JH3N$1qWUh2y%KafbdWx90P^Qgn2L*QE z3=?NiA;z z!yY4{%E=Kywgiv^1&{_oD1B9cT7!@q6ml^V)sTo2FX>PGCl2T#sgwYf(kTo@QgqZ5 z6Q;>8d9MhkF9&zbrO!A#mu!wBA^|@6pSUC;ff2$CiCMrD(AuM&I0~@`oEY2?{wMx> z`w3NwV1&>^MCQj3Cji3tUy!K;84IN1NT{ZVP~f$his3Wc{{d&lSLL-$7lZ%+002ov JPDHLkV1m9S(G>sy literal 0 HcmV?d00001 diff --git a/plugins/arIiifPlugin/vendor/openseadragon/images/previous_grouphover.png b/plugins/arIiifPlugin/vendor/openseadragon/images/previous_grouphover.png new file mode 100644 index 0000000000000000000000000000000000000000..5e0fda1b5f6263456ff4a17eb3200462e9df54fa GIT binary patch literal 1933 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 literal 0 HcmV?d00001 diff --git a/plugins/arIiifPlugin/vendor/openseadragon/images/previous_pressed.png b/plugins/arIiifPlugin/vendor/openseadragon/images/previous_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..75c7e7d253ba307c55b9b1bdb2d53bbe2dddbf33 GIT binary patch literal 2413 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 LNkvXXu0mjf369FO literal 0 HcmV?d00001 diff --git a/plugins/arIiifPlugin/vendor/openseadragon/images/rotateleft_grouphover.png b/plugins/arIiifPlugin/vendor/openseadragon/images/rotateleft_grouphover.png new file mode 100644 index 0000000000000000000000000000000000000000..302ac6285f316bea6a9445c2b992a79d21bb88c9 GIT binary patch literal 1731 zcmV;!20ZzRP)X+Wiylk&@larb^_2%}e zb5XZPifAV7)q-u>g0R=j4~b4h88~K@X0^=&v{_SJiS7wSCnG~}40-@ASBn&(EfNVJ zY1R~BDHfTGG*BTDy$pJP^2sNc4j(>zt1pA+rTx^@)O>&Hsi!_^2*iLcu0)8G*Bv1l zfrtzA1o}Mv^wZlHFJ63?Qfh3!e*IMc{{21tECNfVQlh=RT>)M)nXLNq%P()c>86{0 zz*alZ0dxX!AlV%u8G%SIpzoeNdtT|=x9^5w!-h#i!gmH$L|_sIBPm5v_4W0lp`l^d zh7B7o!*&bMW=O@lBP62`*|%@su0ewaO&B$5RLXH2p4!6$eIk5#U|MVcGrpr-*OmB= zgRm(Os$98p7%{9 zO(hZua*`xU#fYx1E-L5^9Xiy5kI`R!_0@H{Q7E?z`{) znu-wNKIB@;D8sh*!i5X(9x-Bs#A#Dhgz?|GbB8J}E|$f`MIvmYMvWF@$BxyVot=I~ zSxGHG!b9~5_;XJ_`Q+Cu0zxTb zu`Wr~Xe5NN1>koy{Al3w7*huXw#U?|rGGtRz zlOJn3BAJek4j#@s>7&tV|UO2S%NT0Hzs z3Kf^wzkh!W;Y`6Vn`5tZB)A%LGmv4wV4N9y1(h_)H-%2>hXd+}k3Ray#f7NPKKmRG zeMY?e^2_SO4?jpdrm|2%LkW+{k{p#nWin*(K#kubqxlDbq|}T%APqE5=AqxD&O7gX ziSpMaB_$q-pLN#R8uyX&%{O2B&I=0*X)^YNhLhCfgD^uSr%ajRq9R=uz<1w$_Y{XL!X6`RWm1N1?3rht`4;VaA3CcG zxm`G9xC9Z92$bSQ>AF1--fNPvSlmNSu!MaglP6Dhp&;(Hoeq*X>%$K}+-(h6fjZg= zH$1x=|M0^PUv1j7=}gQt13-qCp+t_b8e|YQ5@Wtl6^4ai__#NF_G||sRcr$o&KmBy z=bjtPfYl7N1T&3ACi6Seu3fv{!IX9;mG1H_Mc?LFw24k?^f`RJ>3{^vTgO3|Gjs!$tB!==8 z9Hu~`2|eXW&d(%5M4Evk66y~OG{pLE-n{udD6#^ueH{4y`|sa0rQ2!3(HimXAo_cg zA=S^Uea!D&t9hFCkS5a+;l1h4y-`|InoTAZ^^NlX^{)Nz{}xP7i0GUPv Z`vpbOG?l!-l_CHD002ovPDHLkV1goEL{R_$ literal 0 HcmV?d00001 diff --git a/plugins/arIiifPlugin/vendor/openseadragon/images/rotateleft_hover.png b/plugins/arIiifPlugin/vendor/openseadragon/images/rotateleft_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..e757d87a673323d6e8704e1ba4be0df689fdaf0c GIT binary patch literal 2094 zcmV+}2+{Y6P)BUZQC~f|Jt@~+qP{V+rn7b6SLD;Yu%MyovBn;rYe_sD^HB4 zzOV7E5R4a+zD<#iPJ#68-y4!Z4cuTETtn928S*3WlGj~>m3)q-< zAtVaJum_+|kT8%^qlC!c(wfh|=}pHUdi?S4)P=%cV2raM@QE=)5=|+Uw(UZiRI3|* z^Ru76`%Rzv^z8sThOWUkgob#O5E(=SEbfx{a;tB73rsVOd8|0m^L2g{zp1p~I$#f+mThb}tO7 z^{}w#o(`QgE8Cg3U|v)%Z#?GQbFTqVON2TpA@Fo%hBj9B)*t-fb29I(oLSktUT$CA z?KXDk{L{!yrJe#-9g-g=gfMrZh7U+HY-)^q4vg@C`NkDL|eCO zE~BAhEaDomq88)C&1N&z+i&a6v7Ls$GF!Olvddobk#BwL{-j0W@a|4`(;_=^GfOkI zYOV9cladqWHUnng@u1)vH%sFCK8DHIEkv}#ZLh&CyCJx2aTatL3wqpW3mb5{k3S}z za;Zs*#f1R8p~?&no@BZ_>AmQOAN;`6LZw))Qtoyhd_u>in9M~rTE1kvYPFhZHk)X* zTD!RKp_qL1>lR<#ZaMDkl4aQ?!Ga1$tHw~T8?iw6k3FKiN+pbxVjp|eD=z`yCNg|f zn+7thIBV7^q}vTpsUq4kMFZ}lH`|I&Jh&R)b^l_~XbED1bUyceumhHMovZh1k!ZUU zqO6rFcL?eYhIX5yQU;wjKiYGzy^a9z?Lk#W$|TS@3^@-1ts70ox{*+uCG{U5s*sV< z=?B!=N540Z5rUD~x)pTq{FHT&t5nz#ij}2eeh3l8+LV#1pr_*~n(n}`$e>N>5E;e9 ze1I?|g(bC3JBr6^BHFtl>f_bZsl?LhzjFrWE3WzOs=VcQiU(6P9T zg{8I4wc^v?8-~tMCkT>^l!>E|MPW#&)`A1Jh_%I=l*tX8$ww((efCym@emiDuv35W zg=_Rr-}#t6@5G&m<9M3wC7@Rfm_0iX!d8||w6F*S)0)R&M0!$1qvjz#LPqyLU}UJs zW`#uvB?N*gFkYiHUSm@?r^t&>E$Jhd_z3UFzya{mqpN896u-ZvfPS8=Sag3|bBhBY zq<^7S&SRY@q|z{Il%S(zs#`YSG}Y^I<$0FKhoEAh-z%YeC1ZS0+hFkvx!)jsU5PKRY1^*VsCPkPu&_f93o!Q=Pb^Nvch zi5q(X%bamC;eCmT5Ugm(8G(ERUNBOIzQ{w{ZIo*QAAQayEDU0xf$56%U(cR@0&eI9 zq}*)brWC6abzBopUhQinH*|2Rr!S?^a`Jo;2S5wI4nwkr>FdlUBtBIo70S$QdSH zd-W-wyLDsd0MF&P`uN2-_waehu`UobF$l48Xv!>pdFOU~`{qq(`!SAOpYX%-u$TQ>efhU*zMt&6e$tNC_^X5Qm$aFr zb(s-M*Flsa9+K()ee0$%R+I@&YD!DX>^ek@zoPulueJYo|AqJu|35Q++vpgOU5t^x Y0z3gJtqq~URsaA107*qoM6N<$g3o3lEC2ui literal 0 HcmV?d00001 diff --git a/plugins/arIiifPlugin/vendor/openseadragon/images/rotateleft_pressed.png b/plugins/arIiifPlugin/vendor/openseadragon/images/rotateleft_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..1480b1ae48975d491769388c758f1acd39cac296 GIT binary patch literal 2036 zcmVQwLSvU<2{b|{j0CzODU_6mh*)K= zkO{^tla|OREW*6uh8wnAVu>X-Iy8;zZjM#f*Ehy-Tx@S^`|hcypT6g{ z*It_fpgh($QhJ@?!hbR|xTJTIF4<{SB;_ug5A7YgJ6Fja*MK+n3! z?XY9pV!P~?%Q%kl`)|KLb;5}!JOp5f7*BgP9kh&2NEl8D!GWM(Lo}>`hXP(t4|>|$ zky&Y#{0bLdY|f+Gw%>mHkr4Wcp)x|y(^n<&jAWmF>ZvmqUU5oz1qF{jyoN=%{JS7@zF;gkq{z9tYo->L@1dI zVQ;tHcISr0Le&4_(+e!QZWD6L8ThkkW5!Gi)4sNmjD?y4ELiWMYnBbhBuEKT^%32& zQPQ>IHp-`SJCBW5+D4Q zLn%0tQD5r;6&%^d070Js4>ZJtR6n!ncG*4MnDh3V#l`pBdo2KNqPzP_NN8n7S>vLM zF4{s$>3Sc3w2)=x5DW@bg#k8MwGVO3k>Q0+1eDw5C4!V53F!9Z76rzjMmn=V3<8J;Jx>7sq8sr11) zN1FUF@bHKA_@FO`%Ef(TDgrQ&5a*C2Y&uzpViCRV?Y+w_x7_Ngw`K^vtc*en!%*`F z2B0y3djb4@ABA~uvSg1L~)R{J*!Zb}h_F0T8Hl2g~ zGy}y>2JW+e2K|^ss6Hz*$ubRPg3J*_F^3At0o?=`<*<+8gsnT^Ivjg%-GkeYpN^NV zo`^lS>G|i_xg7$=f<;s<=Am+d2$m}V6+s*c`c1ht5z5KPzYB(%#)Jg)jD%YsBU>HA zBmwCITCc>(JG5iFWd=}~r9;jGj-YX7`%U`+6>XkL$8op~1Rd|xa7X}D7ZKG@M_NWI z#FQyhew3L^qh4XbrXpE|T_K<|fw+%hRi^;GN78G6=NWhbXsU?-6-zaHFf0K($LEXK zgwkOe@~N;0O)A?fp> z1y{_{4Bi4DR76Rk^lcK#IQ;snukIT51EaNOt**e}r3SO5Mooe;iIlQoOU&r9(b;3- z*3+h=PDYR+pzEa>osP#Z&RV_0eyGz_@Dcz|5fJfcGQsbE{4tfDohN5#i#E zWHmse%#x#p1cU&*2q**$kNvWE?;l-@)aCPSKT_PLM2N)VD)G$dqb$xPfw^<%eq$Jh z);^qD>+RNhziWsMF52k1fJDfFFp>x&phyDUc^!{@(a?3*r;E$!J+@69;q}(m)<*yg zK#{mjA;JIC8kndcs$JJzzN)I~7!q5HG3HnX@2hYGbWLipV1l|ff>^JWQu;LH|2Z%) z@Pg-gGu4$CRE)9)9-B~(s8nJ((=^x9b$wMx`L7Ke7h)WZ;J>M}_K1SI5_y%qaw7kA z-{dGMS7k?iZX{(0p4z~9i9M4)`o3xGJ4#DomsyX1LMWnyP^fY=+Ky7k*g`6}B2*;L zypSS&HKKBR?f)Z_6p9j3L7Id>{D1$2NC!*j6lrmllcc}@|G^Syqrg&(8h-(dd{t2| SE`&q?0000w$yAt;kx`VInwrZwS0rKKa5&`gc)A=8N2}lOZ$EVC(23>C zm)GM_Fb3g7gjf9OHU~+D5?ue9>lx&dDg!TGhj1hl`sHg5`<^drcHz4WJ*?6 z)*!k)4pHIQ0urjv=d)H;R#>X5tCYKU@5wfsjeYpxhxX#)5+{XDgXuX$gg}zvLIaA5 zipDKlw(QRO_3LX5l@*1OKow>D`0+~%3JS)+VF;ly!)fNRV@Gr9>gr5&b+ufIv7(}4 zZNPwmAyg1K4UsyrgpkaV)oSJNH}=5?A8Z7fX1(NNL&f6|kqK#OX@e1S86?O#^$!)L zs#aB1@lYr%#UdvsTf>1WsYZE5>L8>MB1Pp+1~r4^FFQMXfT270HbdDEA{kJ=`|i70 zWo2cvK}f}I!xVosIK|;`rq$Qi$w&z)7N{0>;=~CPD$Z0=QW~Trreqd`!T|XQgG>aM zlZFo;-i4;wW>6+#R3-}K%3!nEtio9kWCAcZ;DE$7Jkv-GBiwE`+q!jY>du`z`r*(F zN^Bw#goR+FFsX!Rmj3^Khyct{;_dm`+DUkCX&O!cTGB-7m7+=@JCtf{F9qoT6Oa&mI)I7Ayd zbm;K%@_P!z(+UdmrKYAP7VF@vuf9xQvu1(`qrr(>YjwF?c9g$k$dDl%m1n}mVyd`r zGLmR)(E$imSX*10y`!VU1u_ml?1dLzWGIPdf5Bkd+)c}?KYZQ`MY-gY7s6t z6fog3{?5)$o73rZ>;5Qbkj&wDqlm{NLvO&X^p-9W=x;c{i)3xX&o!^U`g;9?4?a|m z->Wecs*yNxktv=~I-%w17Yk&5vj!Odw(6CskgcWI)(VJ6XxqM0RMym&!H zr`4W&?)fGt&<=Bwns^?;#OJ3^pJpg+pRx1m;IYhfB0%Wo&6^Yk>F(XTGF1U?7gdM8 z6Ct`G-Iy98jDtuz^_mqcR#t&v6;y45GF~Vw4H`6vLq%FAq~phrU!fX_w?^loyAY+3nAv8D%;p6Ad zo#U|1UAuNQ>pM-t*<@4(2qLz-&~e>A{q&QJ*mEQ;y*{drAVV`Lf{Jn>q^(f19%w>> zccHfgpr{4~*)PBR!qG6j8#Zh>-q*$_17r!ezVqkL-^G?T3i6s^Y}&MG(PvcpRPG?A zkwT;b6bRA?!Hm*|4I8FmG2>8zBVW9mH*elen;yYHsF%!rH$4IC%P+tD5K6KT3Cd>9 zoT*KkG)aR+*8}=aM$cf{wQJWH!ou(jtHprMFTecqxK1R&rkDHhl;uab((|{zT|e`C0oB%~i0m)#kSSRj?TL*O& zlKga#{O2Yk3~NBVstgj6_}uj8K2Zwrgk+NcMEUQ3*8czg7vkUl|4j0vem|11-vAy4 V+AcUF<%a+O002ovPDHLkV1ktsRHgs` literal 0 HcmV?d00001 diff --git a/plugins/arIiifPlugin/vendor/openseadragon/images/rotateright_grouphover.png b/plugins/arIiifPlugin/vendor/openseadragon/images/rotateright_grouphover.png new file mode 100644 index 0000000000000000000000000000000000000000..9e71371209a165941aeb234f59ab46ebd977e822 GIT binary patch literal 1800 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 literal 0 HcmV?d00001 diff --git a/plugins/arIiifPlugin/vendor/openseadragon/images/zoomout_grouphover.png b/plugins/arIiifPlugin/vendor/openseadragon/images/zoomout_grouphover.png new file mode 100644 index 0000000000000000000000000000000000000000..b588ecf77670d984c29ae63728b44eb7ad087ef6 GIT binary patch literal 977 zcmV;?11|iDP)Rx7s6&iK*kw65H}=1}$ulG4-;F=*CM3Ww zDt6$(FtutG&&*~pr@s7Y|2x0Y7c>S8z{L6cf{NEHJfie^Q4l-Jq?+7A_iuQ6BvC8_ zr7;!`*_vB2xJ0p!M#r`FD(oP-e0y`=w(uM+W#rsB{!0 zpAZoV#$s^eSx3{I3^oRs+Dr8pW$|RO@$^Iz&e$Rg2?PR445Ri;x(UX_u#=s!IKm~5 zO&<(Aa@cx@L;*foY$A#%Osqz-F&phE(;FO+!(}J^S;W5XUl<3NOu%CtNcCEmR>kcMB9G>o`UnkK|X49D> z`tduvM^T_88>OQd35(%>%o)C)o)V`WDWoUsnLKmHa9SuxGN|-yJW88>`jKt|^4gO? z4BjO7ANy&cgqNNTvXaHX0bjZ|C7lOrz>UDDfaFb>_z z>LKc8*3m~5)fNKWvI?SN#|=i$$ig8*R+PcPirbWrhb!`u_*GpsUn{9vaSs<~$*y|g)-*K{hNEHXu{nySbM7bLP!)<(Dn7&o95 zGMR8EZgSsDx!!`B)7bA2Q(bVTyz}mRe`70pF90-CsW?x_ne&cGMV@-1m~&}`P)Vu(B+s^JpVwXx4xgSQk9Km73X0brv=rDSh^ z${QwT5jWp_^A+8}&U4^}9=9s@3UtXKrWFSu4vImmG6Z==w-Tl$rpYKt#2HnS4z+l5 zZ|R`@S01x=?b-`|`O9D4mR`s*BLytyTHzLV@#4jo`!C&6sg0IFGM7Oj1%$B&LF7UZ z&Vpgo!kZ$#1`cF>lWwRvpiDT*SfI25D)bmd1!h9eVsqr}B20;9=eO2ttq(~gFiCizIV%k} z+$F5G>iFZ2-#;Vc?5?kqcNguq-+m`}!!P;a2*D%LrTvRyc1;)@}0EqwF zlE?xU1Ee(Q$QU`JbP`HMaY8E57>)ogThQy<>Ktw_9FwqTZdfV_n}xUg5x-l4I%=i6f_zQ zh~rp%@bpFelM5E8XlD&rH9^!(UaC7nsb%Fh5u8f~>-9RZIAVU>bT}$>I0tVg<}o&K z`}Xb79;H$Vn$0G(M{u~pf>0cS5LBq3KrwH|u5QWZyz%qj+SAk1^$3wVbRbAe#*vXT zCfO;gg!$G-_cOd(AbJRM1tkP}TGH|87-yvJxQ&qUScAtUuNxlOlMNv!So?ljjE|4^ zjq#4eFN9oBXzLm{e4@q=9<0N9K($tZTq{w{#X1dgJ)t^bBp^OI!$i`Y-A`+OJrPf) zrl!)T@ci#4vY3qGQcSYz!8YS++hGw6L4j~SU3Y< z4uZcd!H24TV`OA-2LQ-a#>^#SEb4&=9@x3hKA+e)xUzF~_vlPfA^ALq2*oafdn*3a&5y~Ktjse2&`5=(MYRu8du0+!)ZgEK=Qrq}6Muee!&@~H zmO?-vAAq&CVyRS)1R1mpE+bGG07^Dnpom~BRIs@PN8nbd+-czXGOu0xm-5cBYV)2j z44(#o$&65(sSNSCs+J5z(%LlCU@yh5&@XHG(e)XtB{h z+3t>f?oaN}FlMP+YH3bI@;=Dlc&j2Teo8Sz z!AdQ&xkN;XWimZToDyUR_tdIzm_I1Rv~`I|y5q1VU>QlPP-`QtMy6+aLrvTpZ*O^9 zgYV?@+A2k+=(pM4&Mnp6{HN>=lR;ZdyTp6(lZcr2Cz1Cy-u?mq3jpalfBHQLp8x;= M07*qoM6N<$g7xO3{Qv*} literal 0 HcmV?d00001 diff --git a/plugins/arIiifPlugin/vendor/openseadragon/images/zoomout_pressed.png b/plugins/arIiifPlugin/vendor/openseadragon/images/zoomout_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..679c5cdab467bd848b8623b86ffde3bd5abe9149 GIT binary patch literal 1997 zcmV;;2Qv7HP)kpI+MqnCl%GK{^AcNA#mXiLT6y8e- zVX&G!^{G!yKIb{l>1i|?EDS^Z=Rf~hxccg=%SIs71cuPiBDGeTcnRlaFMCs#OY#Lk5Mw4*otW6$D+vwfw7rKD^~LWO{+fI9+{-JO;0%=lbp?_&<1zC3-y z7r*$$+yC{ie=Pz)Ra4hAjF4;`#uYUWxzkldMAG#X=Dn`nW6XG#4%wTC8 z{Z^0Llo@&P4L|(qvoGI#SAXf^0$F8Wc5@L9SYFugxT;q;vd4B*m#}48p|UH1R0~D) zm*zW5g{jQW$2^f|Hf##@cv>uu0XT}1DhjRO&FrZn5D~v zD^$BBR4QBb?L%km#^I};wr}6QT>#LgNoX96FzsP{X3RMG$xnXr7+#ot`NWO4?2xlX z-6gi{a~zd)9AuVYXbBENi*UYz&~RjghzfN{#DElIQUaE$;Br6B`+K<8JG^xG@ZqJ^ zDIZ;jqM3;Wn!yLq{NJUtq|X z0^;YFWN%@5*XGTeHvvFW<7w>30*WFoGjDjq8-~i$7xq?X=Gwe^5OmotBy}U)=D2`w2}gy?gX<7G7Ea+$ig!gP`_!3nIiWI&6ow6qMj-8KQO(G)8b z3eXylepo-UbpUo-hzJBcO$BNla8P4u~?!3;G_t+6X2dM2R`qo6Z zPro~utO4_qlDJcYQBJU7)FY7qKucGy5ELqq?Ey3jHE7i9;B|*cNyK!I1D66-&@Wq# ztioi7l~Koz9lNl;XV1m;!|gll*;%mGg~+S`03?K^8iZvuV+l1QJV0UTW*=#vSrJWgF7>i^Qw~_R;mEZAwVY0|6hBM0#H6e z(o4Z|-(dcC-#&X$cT-cQ(Q>|t-41w@bUJN&ZEbyfM#Bw`uVvB-n%%=ajk`u1045L| zX+!&X2EKNOyy2?bCl1$YwJ887XqGi~lO+|E!3bhvVxpkz9&h)7;Vna~unwRKEJYxU zjQAfC%+aL{fEn>$Um~#>~R3d8JVh)ks6A~{P!M(h~epZ+kM;< zhBMtk$s_OqJ@ucBI!3~7)-}yi03d1+--5K$1ErCj`Def9&>t6;@~5SgGXRh`S*d9n zEi&;}5xsU)6tUozvlKq|$r}gyM3{tX9f&DF3xIJ1izig{kqK#`o?U#^GM8+y?a;kdiAqxSN2fs+T=95zKt>tH%!?zfimw zhT&>9a;t+jGFHO1$YAswtnoA{O`0**<$2x?T@E(uPdU)p)!Sh?bGf?zx0@HUQp&PY zDzBL|0?V3`DNRP=4&-aUs#qG&kci+SVn?$iB54{6HNK%5p?2@DD)AZOM#$DU5p0bW z+3?6T5|~E)2#uIkm+s&7)`%H|q4lmE8Ulm7pV!+fOSNA94XdFdm@KqNJOn?9L?iwu fk%ur4?q~cPu=JgC>T4o300000NkvXXu0mjf>sHZU literal 0 HcmV?d00001 diff --git a/plugins/arIiifPlugin/vendor/openseadragon/images/zoomout_rest.png b/plugins/arIiifPlugin/vendor/openseadragon/images/zoomout_rest.png new file mode 100644 index 0000000000000000000000000000000000000000..e3ac4abd825fd63e7bc20b18a4d51efa9dae14e4 GIT binary patch literal 1153 zcmV-{1b+L8P)2*9_UPD%ZCltSt617U5%%#aT4fu1mtAbzmaZ^D&-8S6RsE?`!)yHS5oX^0 zN?_Pg4PHUmW^GHuGyv;=C!?X>_npx&1BV4}zA_DI6lC|4HdnE2C~S=b=iKahQwbOB z_3B$8Bm`28&tYK9cv)f2a!uykN{ins})N|m2}yZ_5KD~Jt!)s`Bjv9!XyZsOK6 z_dSJ=5-|lLFalRh@K*JsFCYHwjg4rbjRXR+Ct_PjyqAwVcI<`DBnj145)3wTXhm)TN>FN3Ffu#8h_{NMexrsm5lTF5-+!hypqlg0ukPEe$j zOmxU`m3&h)gKy@MNz(BfbiE|N+pDJ604Wj;&S6_G+h4Qmv{ z$LkJUd-$AFjv^?Hz&5MkmnOap>qR6G8a2EaELeG$?RNlGS}93v8*a@{K9~LB?`RdO zXrPT0s-s~B``@ZHeZXFsW<3$x6oF3_)+|4{q4WdFsG1E-f{bRcu9#T0|FPpd3e&A8 zVtg`h?Rjrf{#C9)1r0<<`kKLkQf)&1w8t@%W1^KNq%aII-&q)I?|G*v{u%#@5^4y| z4oJgksH3Zt;?~E(#PXrO3#n2PM#g#0n<>oAeK_+_T=^yWSxc%2ds#N!i!IpjkwM;? z7&~eFfb+creZUM7Sz6={_B*ru2-2+E z*pT$+FYV~?)iRB(>7C(1lWOEP4&QC4%w@o^QpzBqdWv1Wn3&q^VzOJsu!H&^Vcl}W T`Qdz700000NkvXXu0mjfB_}SI literal 0 HcmV?d00001 diff --git a/plugins/arIiifPlugin/vendor/openseadragon/openseadragon.min.js b/plugins/arIiifPlugin/vendor/openseadragon/openseadragon.min.js new file mode 100644 index 0000000000..b2778cfaa0 --- /dev/null +++ b/plugins/arIiifPlugin/vendor/openseadragon/openseadragon.min.js @@ -0,0 +1,9 @@ +//! openseadragon 4.1.0 +//! Built on 2023-05-25 +//! Git commit: v4.1.0-0-8849681 +//! http://openseadragon.github.io +//! License: http://openseadragon.github.io/license/ + + +function OpenSeadragon(e){return new OpenSeadragon.Viewer(e)}!function(n){n.version={versionStr:"4.1.0",major:parseInt("4",10),minor:parseInt("1",10),revision:parseInt("0",10)};var t={"[object Boolean]":"boolean","[object Number]":"number","[object String]":"string","[object Function]":"function","[object AsyncFunction]":"function","[object Promise]":"promise","[object Array]":"array","[object Date]":"date","[object RegExp]":"regexp","[object Object]":"object"},i=Object.prototype.toString,o=Object.prototype.hasOwnProperty;n.isFunction=function(e){return"function"===n.type(e)};n.isArray=Array.isArray||function(e){return"array"===n.type(e)};n.isWindow=function(e){return e&&"object"==typeof e&&"setInterval"in e};n.type=function(e){return null==e?String(e):t[i.call(e)]||"object"};n.isPlainObject=function(e){if(!e||"object"!==OpenSeadragon.type(e)||e.nodeType||n.isWindow(e))return!1;if(e.constructor&&!o.call(e,"constructor")&&!o.call(e.constructor.prototype,"isPrototypeOf"))return!1;var t;for(var i in e)t=i;return void 0===t||o.call(e,t)};n.isEmptyObject=function(e){for(var t in e)return!1;return!0};n.freezeObject=function(e){Object.freeze?n.freezeObject=Object.freeze:n.freezeObject=function(e){return e};return n.freezeObject(e)};n.supportsCanvas=(e=document.createElement("canvas"),!(!n.isFunction(e.getContext)||!e.getContext("2d")));var e;n.isCanvasTainted=function(e){var t=!1;try{e.getContext("2d").getImageData(0,0,1,1)}catch(e){t=!0}return t};n.supportsAddEventListener=!(!document.documentElement.addEventListener||!document.addEventListener);n.supportsRemoveEventListener=!(!document.documentElement.removeEventListener||!document.removeEventListener);n.supportsEventListenerOptions=function(){var t=0;if(n.supportsAddEventListener)try{var e={get capture(){t++;return!1},get once(){t++;return!1},get passive(){t++;return!1}};window.addEventListener("test",null,e);window.removeEventListener("test",null,e)}catch(e){t=0}return 3<=t}();n.getCurrentPixelDensityRatio=function(){if(n.supportsCanvas){var e=document.createElement("canvas").getContext("2d");var t=window.devicePixelRatio||1;e=e.webkitBackingStorePixelRatio||e.mozBackingStorePixelRatio||e.msBackingStorePixelRatio||e.oBackingStorePixelRatio||e.backingStorePixelRatio||1;return Math.max(t,1)/e}return 1};n.pixelDensityRatio=n.getCurrentPixelDensityRatio()}(OpenSeadragon);!function(u){u.extend=function(){var e,t,i,n,o,r=arguments[0]||{},s=arguments.length,a=!1,l=1;if("boolean"==typeof r){a=r;r=arguments[1]||{};l=2}"object"==typeof r||OpenSeadragon.isFunction(r)||(r={});if(s===l){r=this;--l}for(;l=i.x&&t.x=i.y},getMousePosition:function(e){if("number"==typeof e.pageX)u.getMousePosition=function(e){var t=new u.Point;t.x=e.pageX;t.y=e.pageY;return t};else{if("number"!=typeof e.clientX)throw new Error("Unknown event mouse position, no known technique.");u.getMousePosition=function(e){var t=new u.Point;t.x=e.clientX+document.body.scrollLeft+document.documentElement.scrollLeft;t.y=e.clientY+document.body.scrollTop+document.documentElement.scrollTop;return t}}return u.getMousePosition(e)},getPageScroll:function(){var e=document.documentElement||{},t=document.body||{};if("number"==typeof window.pageXOffset)u.getPageScroll=function(){return new u.Point(window.pageXOffset,window.pageYOffset)};else if(t.scrollLeft||t.scrollTop)u.getPageScroll=function(){return new u.Point(document.body.scrollLeft,document.body.scrollTop)};else{if(!e.scrollLeft&&!e.scrollTop)return new u.Point(0,0);u.getPageScroll=function(){return new u.Point(document.documentElement.scrollLeft,document.documentElement.scrollTop)}}return u.getPageScroll()},setPageScroll:function(e){if(void 0!==window.scrollTo)u.setPageScroll=function(e){window.scrollTo(e.x,e.y)};else{var t=u.getPageScroll();if(t.x===e.x&&t.y===e.y)return;document.body.scrollLeft=e.x;document.body.scrollTop=e.y;var i=u.getPageScroll();if(i.x!==t.x&&i.y!==t.y){u.setPageScroll=function(e){document.body.scrollLeft=e.x;document.body.scrollTop=e.y};return}document.documentElement.scrollLeft=e.x;document.documentElement.scrollTop=e.y;if((i=u.getPageScroll()).x!==t.x&&i.y!==t.y){u.setPageScroll=function(e){document.documentElement.scrollLeft=e.x;document.documentElement.scrollTop=e.y};return}u.setPageScroll=function(e){}}u.setPageScroll(e)},getWindowSize:function(){var e=document.documentElement||{},t=document.body||{};if("number"==typeof window.innerWidth)u.getWindowSize=function(){return new u.Point(window.innerWidth,window.innerHeight)};else if(e.clientWidth||e.clientHeight)u.getWindowSize=function(){return new u.Point(document.documentElement.clientWidth,document.documentElement.clientHeight)};else{if(!t.clientWidth&&!t.clientHeight)throw new Error("Unknown window size, no known technique.");u.getWindowSize=function(){return new u.Point(document.body.clientWidth,document.body.clientHeight)}}return u.getWindowSize()},makeCenteredNode:function(e){e=u.getElement(e);var t=[u.makeNeutralElement("div"),u.makeNeutralElement("div"),u.makeNeutralElement("div")];u.extend(t[0].style,{display:"table",height:"100%",width:"100%"});u.extend(t[1].style,{display:"table-row"});u.extend(t[2].style,{display:"table-cell",verticalAlign:"middle",textAlign:"center"});t[0].appendChild(t[1]);t[1].appendChild(t[2]);t[2].appendChild(e);return t[0]},makeNeutralElement:function(e){var t=document.createElement(e),e=t.style;e.background="transparent none";e.border="none";e.margin="0px";e.padding="0px";e.position="static";return t},now:function(){Date.now?u.now=Date.now:u.now=function(){return(new Date).getTime()};return u.now()},makeTransparentImage:function(e){var t=u.makeNeutralElement("img");t.src=e;return t},setElementOpacity:function(e,t,i){e=u.getElement(e);i&&!u.Browser.alpha&&(t=Math.round(t));if(u.Browser.opacity)e.style.opacity=t<1?t:"";else if(t<1){t=Math.round(100*t);e.style.filter="alpha(opacity="+t+")"}else e.style.filter=""},setElementTouchActionNone:function(e){void 0!==(e=u.getElement(e)).style.touchAction?e.style.touchAction="none":void 0!==e.style.msTouchAction&&(e.style.msTouchAction="none")},setElementPointerEvents:function(e,t){void 0!==(e=u.getElement(e)).style&&void 0!==e.style.pointerEvents&&(e.style.pointerEvents=t)},setElementPointerEventsNone:function(e){u.setElementPointerEvents(e,"none")},addClass:function(e,t){(e=u.getElement(e)).className?-1===(" "+e.className+" ").indexOf(" "+t+" ")&&(e.className+=" "+t):e.className=t},indexOf:function(e,t,i){Array.prototype.indexOf?this.indexOf=function(e,t,i){return e.indexOf(t,i)}:this.indexOf=function(e,t,i){var n,o,i=i||0;if(!e)throw new TypeError;if(0===(o=e.length)||o<=i)return-1;for(n=i=i<0?o-Math.abs(i):i;nt.touches.length-r&&c.console.warn("Tracked touch contact count doesn't match event.touches.length");var a={originalEvent:t,eventType:"pointerdown",pointerType:"touch",isEmulated:!1};B(e,a);for(n=0;n\s*$/))n=m.parseXml(n);else if(n.match(/^\s*[{[].*[}\]]\s*$/))try{var e=m.parseJSON(n);n=e}catch(e){}function l(e,t){if(e.ready)r(e);else{e.addHandler("ready",function(){r(e)});e.addHandler("open-failed",function(e){s({message:e.message,source:t})})}}setTimeout(function(){if("string"===m.type(n))(n=new m.TileSource({url:n,crossOriginPolicy:(void 0!==o.crossOriginPolicy?o:i).crossOriginPolicy,ajaxWithCredentials:i.ajaxWithCredentials,ajaxHeaders:o.ajaxHeaders||i.ajaxHeaders,splitHashDataForPost:i.splitHashDataForPost,useCanvas:i.useCanvas,success:function(e){r(e.tileSource)}})).addHandler("open-failed",function(e){s(e)});else if(m.isPlainObject(n)||n.nodeType){void 0!==n.crossOriginPolicy||void 0===o.crossOriginPolicy&&void 0===i.crossOriginPolicy||(n.crossOriginPolicy=(void 0!==o.crossOriginPolicy?o:i).crossOriginPolicy);void 0===n.ajaxWithCredentials&&(n.ajaxWithCredentials=i.ajaxWithCredentials);void 0===n.useCanvas&&(n.useCanvas=i.useCanvas);if(m.isFunction(n.getTileUrl)){var e=new m.TileSource(n);e.getTileUrl=n.getTileUrl;r(e)}else{var t=m.TileSource.determineType(a,n);if(t){e=t.prototype.configure.apply(a,[n]);l(new t(e),n)}else s({message:"Unable to load TileSource",source:n})}}else l(n,n)})}(this,i.tileSource,i,function(e){o.tileSource=e;s()},function(e){e.options=i;t(e);s()})}function s(){var e,t;for(;n._loadQueue.length&&(e=n._loadQueue[0]).tileSource;){n._loadQueue.splice(0,1);if(e.options.replace){var i=n.world.getIndexOfItem(e.options.replaceItem);-1!==i&&(e.options.index=i);n.world.removeItem(e.options.replaceItem)}t=new m.TiledImage({viewer:n,source:e.tileSource,viewport:n.viewport,drawer:n.drawer,tileCache:n.tileCache,imageLoader:n.imageLoader,x:e.options.x,y:e.options.y,width:e.options.width,height:e.options.height,fitBounds:e.options.fitBounds,fitBoundsPlacement:e.options.fitBoundsPlacement,clip:e.options.clip,placeholderFillStyle:e.options.placeholderFillStyle,opacity:e.options.opacity,preload:e.options.preload,degrees:e.options.degrees,flipped:e.options.flipped,compositeOperation:e.options.compositeOperation,springStiffness:n.springStiffness,animationTime:n.animationTime,minZoomImageRatio:n.minZoomImageRatio,wrapHorizontal:n.wrapHorizontal,wrapVertical:n.wrapVertical,immediateRender:n.immediateRender,blendTime:n.blendTime,alwaysBlend:n.alwaysBlend,minPixelRatio:n.minPixelRatio,smoothTileEdgesMinZoom:n.smoothTileEdgesMinZoom,iOSDevice:n.iOSDevice,crossOriginPolicy:e.options.crossOriginPolicy,ajaxWithCredentials:e.options.ajaxWithCredentials,loadTilesWithAjax:e.options.loadTilesWithAjax,ajaxHeaders:e.options.ajaxHeaders,debugMode:n.debugMode,subPixelRoundingForTransparency:n.subPixelRoundingForTransparency});n.collectionMode&&n.world.setAutoRefigureSizes(!1);if(n.navigator){i=m.extend({},e.options,{replace:!1,originalTiledImage:t,tileSource:e.tileSource});n.navigator.addTiledImage(i)}n.world.addItem(t,{index:e.options.index});0===n._loadQueue.length&&r(e);1!==n.world.getItemCount()||n.preserveViewport||n.viewport.goHome(!0);e.options.success&&e.options.success({item:t})}}},addSimpleImage:function(e){m.console.assert(e,"[Viewer.addSimpleImage] options is required");m.console.assert(e.url,"[Viewer.addSimpleImage] options.url is required");e=m.extend({},e,{tileSource:{type:"image",url:e.url}});delete e.url;this.addTiledImage(e)},addLayer:function(t){var i=this;m.console.error("[Viewer.addLayer] this function is deprecated; use Viewer.addTiledImage() instead.");var e=m.extend({},t,{success:function(e){i.raiseEvent("add-layer",{options:t,drawer:e.item})},error:function(e){i.raiseEvent("add-layer-failed",e)}});this.addTiledImage(e);return this},getLayerAtLevel:function(e){m.console.error("[Viewer.getLayerAtLevel] this function is deprecated; use World.getItemAt() instead.");return this.world.getItemAt(e)},getLevelOfLayer:function(e){m.console.error("[Viewer.getLevelOfLayer] this function is deprecated; use World.getIndexOfItem() instead.");return this.world.getIndexOfItem(e)},getLayersCount:function(){m.console.error("[Viewer.getLayersCount] this function is deprecated; use World.getItemCount() instead.");return this.world.getItemCount()},setLayerLevel:function(e,t){m.console.error("[Viewer.setLayerLevel] this function is deprecated; use World.setItemIndex() instead.");return this.world.setItemIndex(e,t)},removeLayer:function(e){m.console.error("[Viewer.removeLayer] this function is deprecated; use World.removeItem() instead.");return this.world.removeItem(e)},forceRedraw:function(){c[this.hash].forceRedraw=!0;return this},forceResize:function(){c[this.hash].needsResize=!0;c[this.hash].forceResize=!0},bindSequenceControls:function(){var e=m.delegate(this,v),t=m.delegate(this,f),i=m.delegate(this,this.goToNextPage),n=m.delegate(this,this.goToPreviousPage),o=this.navImages,r=!0;if(this.showSequenceControl){(this.previousButton||this.nextButton)&&(r=!1);this.previousButton=new m.Button({element:this.previousButton?m.getElement(this.previousButton):null,clickTimeThreshold:this.clickTimeThreshold,clickDistThreshold:this.clickDistThreshold,tooltip:m.getString("Tooltips.PreviousPage"),srcRest:B(this.prefixUrl,o.previous.REST),srcGroup:B(this.prefixUrl,o.previous.GROUP),srcHover:B(this.prefixUrl,o.previous.HOVER),srcDown:B(this.prefixUrl,o.previous.DOWN),onRelease:n,onFocus:e,onBlur:t});this.nextButton=new m.Button({element:this.nextButton?m.getElement(this.nextButton):null,clickTimeThreshold:this.clickTimeThreshold,clickDistThreshold:this.clickDistThreshold,tooltip:m.getString("Tooltips.NextPage"),srcRest:B(this.prefixUrl,o.next.REST),srcGroup:B(this.prefixUrl,o.next.GROUP),srcHover:B(this.prefixUrl,o.next.HOVER),srcDown:B(this.prefixUrl,o.next.DOWN),onRelease:i,onFocus:e,onBlur:t});this.navPrevNextWrap||this.previousButton.disable();this.tileSources&&this.tileSources.length||this.nextButton.disable();if(r){this.paging=new m.ButtonGroup({buttons:[this.previousButton,this.nextButton],clickTimeThreshold:this.clickTimeThreshold,clickDistThreshold:this.clickDistThreshold});this.pagingControl=this.paging.element;this.toolbar?this.toolbar.addControl(this.pagingControl,{anchor:m.ControlAnchor.BOTTOM_RIGHT}):this.addControl(this.pagingControl,{anchor:this.sequenceControlAnchor||m.ControlAnchor.TOP_LEFT})}}return this},bindStandardControls:function(){var e=m.delegate(this,L),t=m.delegate(this,M),i=m.delegate(this,N),n=m.delegate(this,F),o=m.delegate(this,A),r=m.delegate(this,U),s=m.delegate(this,V),a=m.delegate(this,j),l=m.delegate(this,G),h=m.delegate(this,q),c=m.delegate(this,v),u=m.delegate(this,f),d=this.navImages,p=[],g=!0;if(this.showNavigationControl){(this.zoomInButton||this.zoomOutButton||this.homeButton||this.fullPageButton||this.rotateLeftButton||this.rotateRightButton||this.flipButton)&&(g=!1);if(this.showZoomControl){p.push(this.zoomInButton=new m.Button({element:this.zoomInButton?m.getElement(this.zoomInButton):null,clickTimeThreshold:this.clickTimeThreshold,clickDistThreshold:this.clickDistThreshold,tooltip:m.getString("Tooltips.ZoomIn"),srcRest:B(this.prefixUrl,d.zoomIn.REST),srcGroup:B(this.prefixUrl,d.zoomIn.GROUP),srcHover:B(this.prefixUrl,d.zoomIn.HOVER),srcDown:B(this.prefixUrl,d.zoomIn.DOWN),onPress:e,onRelease:t,onClick:i,onEnter:e,onExit:t,onFocus:c,onBlur:u}));p.push(this.zoomOutButton=new m.Button({element:this.zoomOutButton?m.getElement(this.zoomOutButton):null,clickTimeThreshold:this.clickTimeThreshold,clickDistThreshold:this.clickDistThreshold,tooltip:m.getString("Tooltips.ZoomOut"),srcRest:B(this.prefixUrl,d.zoomOut.REST),srcGroup:B(this.prefixUrl,d.zoomOut.GROUP),srcHover:B(this.prefixUrl,d.zoomOut.HOVER),srcDown:B(this.prefixUrl,d.zoomOut.DOWN),onPress:n,onRelease:t,onClick:o,onEnter:n,onExit:t,onFocus:c,onBlur:u}))}this.showHomeControl&&p.push(this.homeButton=new m.Button({element:this.homeButton?m.getElement(this.homeButton):null,clickTimeThreshold:this.clickTimeThreshold,clickDistThreshold:this.clickDistThreshold,tooltip:m.getString("Tooltips.Home"),srcRest:B(this.prefixUrl,d.home.REST),srcGroup:B(this.prefixUrl,d.home.GROUP),srcHover:B(this.prefixUrl,d.home.HOVER),srcDown:B(this.prefixUrl,d.home.DOWN),onRelease:r,onFocus:c,onBlur:u}));this.showFullPageControl&&p.push(this.fullPageButton=new m.Button({element:this.fullPageButton?m.getElement(this.fullPageButton):null,clickTimeThreshold:this.clickTimeThreshold,clickDistThreshold:this.clickDistThreshold,tooltip:m.getString("Tooltips.FullPage"),srcRest:B(this.prefixUrl,d.fullpage.REST),srcGroup:B(this.prefixUrl,d.fullpage.GROUP),srcHover:B(this.prefixUrl,d.fullpage.HOVER),srcDown:B(this.prefixUrl,d.fullpage.DOWN),onRelease:s,onFocus:c,onBlur:u}));if(this.showRotationControl){p.push(this.rotateLeftButton=new m.Button({element:this.rotateLeftButton?m.getElement(this.rotateLeftButton):null,clickTimeThreshold:this.clickTimeThreshold,clickDistThreshold:this.clickDistThreshold,tooltip:m.getString("Tooltips.RotateLeft"),srcRest:B(this.prefixUrl,d.rotateleft.REST),srcGroup:B(this.prefixUrl,d.rotateleft.GROUP),srcHover:B(this.prefixUrl,d.rotateleft.HOVER),srcDown:B(this.prefixUrl,d.rotateleft.DOWN),onRelease:a,onFocus:c,onBlur:u}));p.push(this.rotateRightButton=new m.Button({element:this.rotateRightButton?m.getElement(this.rotateRightButton):null,clickTimeThreshold:this.clickTimeThreshold,clickDistThreshold:this.clickDistThreshold,tooltip:m.getString("Tooltips.RotateRight"),srcRest:B(this.prefixUrl,d.rotateright.REST),srcGroup:B(this.prefixUrl,d.rotateright.GROUP),srcHover:B(this.prefixUrl,d.rotateright.HOVER),srcDown:B(this.prefixUrl,d.rotateright.DOWN),onRelease:l,onFocus:c,onBlur:u}))}this.showFlipControl&&p.push(this.flipButton=new m.Button({element:this.flipButton?m.getElement(this.flipButton):null,clickTimeThreshold:this.clickTimeThreshold,clickDistThreshold:this.clickDistThreshold,tooltip:m.getString("Tooltips.Flip"),srcRest:B(this.prefixUrl,d.flip.REST),srcGroup:B(this.prefixUrl,d.flip.GROUP),srcHover:B(this.prefixUrl,d.flip.HOVER),srcDown:B(this.prefixUrl,d.flip.DOWN),onRelease:h,onFocus:c,onBlur:u}));if(g){this.buttonGroup=new m.ButtonGroup({buttons:p,clickTimeThreshold:this.clickTimeThreshold,clickDistThreshold:this.clickDistThreshold});this.navControl=this.buttonGroup.element;this.addHandler("open",m.delegate(this,W));(this.toolbar||this).addControl(this.navControl,{anchor:this.navigationControlAnchor||m.ControlAnchor.TOP_LEFT})}else this.customButtons=p}return this},currentPage:function(){return this._sequenceIndex},goToPage:function(e){if(this.tileSources&&0<=e&&e=this.tileSources.length&&(e=0);this.goToPage(e)},isAnimating:function(){return c[this.hash].animating}});function r(e){e=m.getElement(e);return new m.Point(0===e.clientWidth?1:e.clientWidth,0===e.clientHeight?1:e.clientHeight)}function h(e,t){if(t instanceof m.Overlay)return t;var i=null;if(t.element)i=m.getElement(t.element);else{var n=t.id||"openseadragon-overlay-"+Math.floor(1e7*Math.random());(i=m.getElement(t.id))||((i=document.createElement("a")).href="#/overlay/"+n);i.id=n;m.addClass(i,t.className||"openseadragon-overlay")}var o=t.location;var r=t.width;var s=t.height;if(!o){n=t.x;var a=t.y;if(void 0!==t.px){e=e.viewport.imageToViewportRectangle(new m.Rect(t.px,t.py,r||0,s||0));n=e.x;a=e.y;r=void 0!==r?e.width:void 0;s=void 0!==s?e.height:void 0}o=new m.Point(n,a)}a=t.placement;a&&"string"===m.type(a)&&(a=m.Placement[t.placement.toUpperCase()]);return new m.Overlay({element:i,location:o,placement:a,onDraw:t.onDraw,checkResize:t.checkResize,width:r,height:s,rotationMode:t.rotationMode})}function s(e,t){var i;for(i=e.length-1;0<=i;i--)if(e[i].element===t)return i;return-1}function a(e,t){return m.requestAnimationFrame(function(){t(e)})}function l(e){m.requestAnimationFrame(function(){!function(e){var t,i,n;if(e.controlsShouldFade){t=m.now();t=t-e.controlsFadeBeginTime;i=1-t/e.controlsFadeLength;i=Math.min(1,i);i=Math.max(0,i);for(n=e.controls.length-1;0<=n;n--)e.controls[n].autoFade&&e.controls[n].setOpacity(i);0=t.flickMinSpeed){var n=0;this.panHorizontal&&(n=t.flickMomentum*e.speed*Math.cos(e.direction));i=0;this.panVertical&&(i=t.flickMomentum*e.speed*Math.sin(e.direction));e=this.viewport.pixelFromPoint(this.viewport.getCenter(!0));i=this.viewport.pointFromPixel(new m.Point(e.x-n,e.y-i));this.viewport.panTo(i,!1)}this.viewport.applyConstraints()}t.dblClickDragToZoom&&!0===c[this.hash].draggingToZoom&&(c[this.hash].draggingToZoom=!1)}function S(e){this.raiseEvent("canvas-enter",{tracker:e.eventSource,pointerType:e.pointerType,position:e.position,buttons:e.buttons,pointers:e.pointers,insideElementPressed:e.insideElementPressed,buttonDownAny:e.buttonDownAny,originalEvent:e.originalEvent})}function E(e){this.raiseEvent("canvas-exit",{tracker:e.eventSource,pointerType:e.pointerType,position:e.position,buttons:e.buttons,pointers:e.pointers,insideElementPressed:e.insideElementPressed,buttonDownAny:e.buttonDownAny,originalEvent:e.originalEvent})}function P(e){this.raiseEvent("canvas-press",{tracker:e.eventSource,pointerType:e.pointerType,position:e.position,insideElementPressed:e.insideElementPressed,insideElementReleased:e.insideElementReleased,originalEvent:e.originalEvent});if(this.gestureSettingsByDeviceType(e.pointerType).dblClickDragToZoom){var t=c[this.hash].lastClickTime;e=m.now();if(null!==t){e-tthis.minScrollDeltaTime){this._lastScrollTime=n;t={tracker:e.eventSource,position:e.position,scroll:e.scroll,shift:e.shift,originalEvent:e.originalEvent,preventDefaultAction:!1,preventDefault:!0};this.raiseEvent("canvas-scroll",t);if(!t.preventDefaultAction&&this.viewport){this.viewport.flipped&&(e.position.x=this.viewport.getContainerSize().x-e.position.x);if((i=this.gestureSettingsByDeviceType(e.pointerType)).scrollToZoom){n=Math.pow(this.zoomPerScroll,e.scroll);this.viewport.zoomBy(n,i.zoomToRefPoint?this.viewport.pointFromPixel(e.position,!0):null);this.viewport.applyConstraints()}}e.preventDefault=t.preventDefault}else e.preventDefault=!0}function k(e){c[this.hash].mouseInside=!0;n(this);this.raiseEvent("container-enter",{tracker:e.eventSource,pointerType:e.pointerType,position:e.position,buttons:e.buttons,pointers:e.pointers,insideElementPressed:e.insideElementPressed,buttonDownAny:e.buttonDownAny,originalEvent:e.originalEvent})}function H(e){if(e.pointers<1){c[this.hash].mouseInside=!1;c[this.hash].animating||u(this)}this.raiseEvent("container-exit",{tracker:e.eventSource,pointerType:e.pointerType,position:e.position,buttons:e.buttons,pointers:e.pointers,insideElementPressed:e.insideElementPressed,buttonDownAny:e.buttonDownAny,originalEvent:e.originalEvent})}function z(e){!function(e){if(!e._opening&&c[e.hash]){if(e.autoResize||c[e.hash].forceResize){if(e._autoResizePolling){i=r(e.container);var t=c[e.hash].prevContainerSize;i.equals(t)||(c[e.hash].needsResize=!0)}c[e.hash].needsResize&&function(e,t){var i=e.viewport;var n=i.getZoom();var o=i.getCenter();i.resize(t,e.preserveImageSizeOnResize);i.panTo(o,!0);var r;if(e.preserveImageSizeOnResize)r=c[e.hash].prevContainerSize.x/t.x;else{var s=new m.Point(0,0);o=new m.Point(c[e.hash].prevContainerSize.x,c[e.hash].prevContainerSize.y).distanceTo(s);s=new m.Point(t.x,t.y).distanceTo(s);r=s/o*c[e.hash].prevContainerSize.x/t.x}i.zoomTo(n*r,null,!0);c[e.hash].prevContainerSize=t;c[e.hash].forceRedraw=!0;c[e.hash].needsResize=!1;c[e.hash].forceResize=!1}(e,i||r(e.container))}t=e.viewport.update();var i=e.world.update()||t;t&&e.raiseEvent("viewport-change");e.referenceStrip&&(i=e.referenceStrip.update(e.viewport)||i);t=c[e.hash].animating;if(!t&&i){e.raiseEvent("animation-start");n(e)}t=t&&!i;t&&(c[e.hash].animating=!1);if(i||t||c[e.hash].forceRedraw||e.world.needsDraw()){!function(e){e.imageLoader.clear();e.drawer.clear();e.world.draw();e.raiseEvent("update-viewport",{})}(e);e._drawOverlays();e.navigator&&e.navigator.update(e.viewport);c[e.hash].forceRedraw=!1;i&&e.raiseEvent("animation")}if(t){e.raiseEvent("animation-finish");c[e.hash].mouseInside||u(e)}c[e.hash].animating=i}}(e);e.isOpen()?e._updateRequestId=a(e,z):e._updateRequestId=!1}function B(e,t){return e?e+t:t}function L(){c[this.hash].lastZoomTime=m.now();c[this.hash].zoomFactor=this.zoomPerSecond;c[this.hash].zooming=!0;i(this)}function F(){c[this.hash].lastZoomTime=m.now();c[this.hash].zoomFactor=1/this.zoomPerSecond;c[this.hash].zooming=!0;i(this)}function M(){c[this.hash].zooming=!1}function i(e){m.requestAnimationFrame(m.delegate(e,t))}function t(){var e,t;if(c[this.hash].zooming&&this.viewport){t=(e=m.now())-c[this.hash].lastZoomTime;t=Math.pow(c[this.hash].zoomFactor,t/1e3);this.viewport.zoomBy(t);this.viewport.applyConstraints();c[this.hash].lastZoomTime=e;i(this)}}function N(){if(this.viewport){c[this.hash].zooming=!1;this.viewport.zoomBy(+this.zoomPerClick);this.viewport.applyConstraints()}}function A(){if(this.viewport){c[this.hash].zooming=!1;this.viewport.zoomBy(1/this.zoomPerClick);this.viewport.applyConstraints()}}function W(){if(this.buttonGroup){this.buttonGroup.emulateEnter();this.buttonGroup.emulateLeave()}}function U(){this.viewport&&this.viewport.goHome()}function V(){this.isFullPage()&&!m.isFullScreen()?this.setFullPage(!1):this.setFullScreen(!this.isFullPage());this.buttonGroup&&this.buttonGroup.emulateLeave();this.fullPageButton.element.focus();this.viewport&&this.viewport.applyConstraints()}function j(){if(this.viewport){var e=this.viewport.getRotation();this.viewport.flipped?e+=this.rotationIncrement:e-=this.rotationIncrement;this.viewport.setRotation(e)}}function G(){if(this.viewport){var e=this.viewport.getRotation();this.viewport.flipped?e-=this.rotationIncrement:e+=this.rotationIncrement;this.viewport.setRotation(e)}}function q(){this.viewport.toggleFlip()}}(OpenSeadragon);!function(r){r.Navigator=function(i){var e,t=i.viewer,n=this;if(i.element||i.id){if(i.element){i.id&&r.console.warn("Given option.id for Navigator was ignored since option.element was provided and is being used instead.");i.element.id?i.id=i.element.id:i.id="navigator-"+r.now();this.element=i.element}else this.element=document.getElementById(i.id);i.controlOptions={anchor:r.ControlAnchor.NONE,attachToViewer:!1,autoFade:!1}}else{i.id="navigator-"+r.now();this.element=r.makeNeutralElement("div");i.controlOptions={anchor:r.ControlAnchor.TOP_RIGHT,attachToViewer:!0,autoFade:i.autoFade};if(i.position)if("BOTTOM_RIGHT"===i.position)i.controlOptions.anchor=r.ControlAnchor.BOTTOM_RIGHT;else if("BOTTOM_LEFT"===i.position)i.controlOptions.anchor=r.ControlAnchor.BOTTOM_LEFT;else if("TOP_RIGHT"===i.position)i.controlOptions.anchor=r.ControlAnchor.TOP_RIGHT;else if("TOP_LEFT"===i.position)i.controlOptions.anchor=r.ControlAnchor.TOP_LEFT;else if("ABSOLUTE"===i.position){i.controlOptions.anchor=r.ControlAnchor.ABSOLUTE;i.controlOptions.top=i.top;i.controlOptions.left=i.left;i.controlOptions.height=i.height;i.controlOptions.width=i.width}}this.element.id=i.id;this.element.className+=" navigator";(i=r.extend(!0,{sizeRatio:r.DEFAULT_SETTINGS.navigatorSizeRatio},i,{element:this.element,tabIndex:-1,showNavigator:!1,mouseNavEnabled:!1,showNavigationControl:!1,showSequenceControl:!1,immediateRender:!0,blendTime:0,animationTime:i.animationTime,autoResize:!1,minZoomImageRatio:1,background:i.background,opacity:i.opacity,borderColor:i.borderColor,displayRegionColor:i.displayRegionColor})).minPixelRatio=this.minPixelRatio=t.minPixelRatio;r.setElementTouchActionNone(this.element);this.borderWidth=2;this.fudge=new r.Point(1,1);this.totalBorderWidths=new r.Point(2*this.borderWidth,2*this.borderWidth).minus(this.fudge);i.controlOptions.anchor!==r.ControlAnchor.NONE&&function(e,t){e.margin="0px";e.border=t+"px solid "+i.borderColor;e.padding="0px";e.background=i.background;e.opacity=i.opacity;e.overflow="hidden"}(this.element.style,this.borderWidth);this.displayRegion=r.makeNeutralElement("div");this.displayRegion.id=this.element.id+"-displayregion";this.displayRegion.className="displayregion";!function(e,t){e.position="relative";e.top="0px";e.left="0px";e.fontSize="0px";e.overflow="hidden";e.border=t+"px solid "+i.displayRegionColor;e.margin="0px";e.padding="0px";e.background="transparent";e.float="left";e.cssFloat="left";e.styleFloat="left";e.zIndex=999999999;e.cursor="default";e.boxSizing="content-box"}(this.displayRegion.style,this.borderWidth);r.setElementPointerEventsNone(this.displayRegion);r.setElementTouchActionNone(this.displayRegion);this.displayRegionContainer=r.makeNeutralElement("div");this.displayRegionContainer.id=this.element.id+"-displayregioncontainer";this.displayRegionContainer.className="displayregioncontainer";this.displayRegionContainer.style.width="100%";this.displayRegionContainer.style.height="100%";r.setElementPointerEventsNone(this.displayRegionContainer);r.setElementTouchActionNone(this.displayRegionContainer);t.addControl(this.element,i.controlOptions);this._resizeWithViewer=i.controlOptions.anchor!==r.ControlAnchor.ABSOLUTE&&i.controlOptions.anchor!==r.ControlAnchor.NONE;if(i.width&&i.height){this.setWidth(i.width);this.setHeight(i.height)}else if(this._resizeWithViewer){e=r.getElementSize(t.element);this.element.style.height=Math.round(e.y*i.sizeRatio)+"px";this.element.style.width=Math.round(e.x*i.sizeRatio)+"px";this.oldViewerSize=e;e=r.getElementSize(this.element);this.elementArea=e.x*e.y}this.oldContainerSize=new r.Point(0,0);r.Viewer.apply(this,[i]);this.displayRegionContainer.appendChild(this.displayRegion);this.element.getElementsByTagName("div")[0].appendChild(this.displayRegionContainer);function o(e,t){c(n.displayRegionContainer,e);c(n.displayRegion,-e);n.viewport.setRotation(e,t)}if(i.navigatorRotate){o(i.viewer.viewport?i.viewer.viewport.getRotation():i.viewer.degrees||0,!0);i.viewer.addHandler("rotate",function(e){o(e.degrees,e.immediately)})}this.innerTracker.destroy();this.innerTracker=new r.MouseTracker({userData:"Navigator.innerTracker",element:this.element,dragHandler:r.delegate(this,a),clickHandler:r.delegate(this,s),releaseHandler:r.delegate(this,l),scrollHandler:r.delegate(this,h),preProcessEventHandler:function(e){"wheel"===e.eventType&&(e.preventDefault=!0)}});this.outerTracker.userData="Navigator.outerTracker";r.setElementPointerEventsNone(this.canvas);r.setElementPointerEventsNone(this.container);this.addHandler("reset-size",function(){n.viewport&&n.viewport.goHome(!0)});t.world.addHandler("item-index-change",function(t){window.setTimeout(function(){var e=n.world.getItemAt(t.previousIndex);n.world.setItemIndex(e,t.newIndex)},1)});t.world.addHandler("remove-item",function(e){e=e.item;e=n._getMatchingItem(e);e&&n.world.removeItem(e)});this.update(t.viewport)};r.extend(r.Navigator.prototype,r.EventSource.prototype,r.Viewer.prototype,{updateSize:function(){if(this.viewport){var e=new r.Point(0===this.container.clientWidth?1:this.container.clientWidth,0===this.container.clientHeight?1:this.container.clientHeight);if(!e.equals(this.oldContainerSize)){this.viewport.resize(e,!0);this.viewport.goHome(!0);this.oldContainerSize=e;this.drawer.clear();this.world.draw()}}},setWidth:function(e){this.width=e;this.element.style.width="number"==typeof e?e+"px":e;this._resizeWithViewer=!1;this.updateSize()},setHeight:function(e){this.height=e;this.element.style.height="number"==typeof e?e+"px":e;this._resizeWithViewer=!1;this.updateSize()},setFlip:function(e){this.viewport.setFlip(e);this.setDisplayTransform(this.viewer.viewport.getFlip()?"scale(-1,1)":"scale(1,1)");return this},setDisplayTransform:function(e){i(this.displayRegion,e);i(this.canvas,e);i(this.element,e)},update:function(e){var t,i;t=r.getElementSize(this.viewer.element);if(this._resizeWithViewer&&t.x&&t.y&&!t.equals(this.oldViewerSize)){this.oldViewerSize=t;if(this.maintainSizeRatio||!this.elementArea){i=t.x*this.sizeRatio;o=t.y*this.sizeRatio}else{i=Math.sqrt(this.elementArea*(t.x/t.y));o=this.elementArea/i}this.element.style.width=Math.round(i)+"px";this.element.style.height=Math.round(o)+"px";this.elementArea||(this.elementArea=i*o);this.updateSize()}if(e&&this.viewport){i=e.getBoundsNoRotate(!0);o=this.viewport.pixelFromPointNoRotate(i.getTopLeft(),!1);i=this.viewport.pixelFromPointNoRotate(i.getBottomRight(),!1).minus(this.totalBorderWidths);if(!this.navigatorRotate){var n=e.getRotation(!0);c(this.displayRegion,-n)}e=this.displayRegion.style;e.display=this.world.getItemCount()?"block":"none";e.top=o.y.toFixed(2)+"px";e.left=o.x.toFixed(2)+"px";n=i.x-o.x;var o=i.y-o.y;e.width=Math.round(Math.max(n,0))+"px";e.height=Math.round(Math.max(o,0))+"px"}},addTiledImage:function(e){var n=this;var o=e.originalTiledImage;delete e.original;e=r.extend({},e,{success:function(e){var t=e.item;t._originalForNavigator=o;n._matchBounds(t,o,!0);n._matchOpacity(t,o);n._matchCompositeOperation(t,o);function i(){n._matchBounds(t,o)}o.addHandler("bounds-change",i);o.addHandler("clip-change",i);o.addHandler("opacity-change",function(){n._matchOpacity(t,o)});o.addHandler("composite-operation-change",function(){n._matchCompositeOperation(t,o)})}});return r.Viewer.prototype.addTiledImage.apply(this,[e])},destroy:function(){return r.Viewer.prototype.destroy.apply(this)},_getMatchingItem:function(e){var t=this.world.getItemCount();var i;for(var n=0;n=1/this.aspectRatio-1e-15&&(n=this.getNumTiles(e).y-1);return new h.Point(i,n)},getTileBounds:function(e,t,i,n){var o=this.dimensions.times(this.getLevelScale(e)),r=this.getTileWidth(e),s=this.getTileHeight(e),a=0===t?0:r*t-this.tileOverlap,e=0===i?0:s*i-this.tileOverlap,t=r+(0===t?1:2)*this.tileOverlap,s=s+(0===i?1:2)*this.tileOverlap,i=1/o.x;t=Math.min(t,o.x-a);s=Math.min(s,o.y-e);return n?new h.Rect(0,0,t,s):new h.Rect(a*i,e*i,t*i,s*i)},getImageInfo:function(n){var t,i,e,o,r,s=this;n&&-1<(r=(o=(e=n.split("/"))[e.length-1]).lastIndexOf("."))&&(e[e.length-1]=o.slice(0,r));var a=null;if(this.splitHashDataForPost){var l=n.indexOf("#");if(-1!==l){a=n.substring(l+1);n=n.substr(0,l)}}t=function(e){"string"==typeof e&&(e=h.parseXml(e));var t=h.TileSource.determineType(s,e,n);if(t){void 0===(i=t.prototype.configure.apply(s,[e,n,a])).ajaxWithCredentials&&(i.ajaxWithCredentials=s.ajaxWithCredentials);i=new t(i);s.ready=!0;s.raiseEvent("ready",{tileSource:i})}else s.raiseEvent("open-failed",{message:"Unable to load TileSource",source:n})};if(n.match(/\.js$/)){l=n.split("/").pop().replace(".js","");h.jsonp({url:n,async:!1,callbackName:l,callback:t})}else h.makeAjaxRequest({url:n,postData:a,withCredentials:this.ajaxWithCredentials,headers:this.ajaxHeaders,success:function(e){e=function(t){var e,i,n=t.responseText,o=t.status;{if(!t)throw new Error(h.getString("Errors.Security"));if(200!==t.status&&0!==t.status){o=t.status;e=404===o?"Not Found":t.statusText;throw new Error(h.getString("Errors.Status",o,e))}}if(n.match(/^\s*<.*/))try{i=t.responseXML&&t.responseXML.documentElement?t.responseXML:h.parseXml(n)}catch(e){i=t.responseText}else if(n.match(/\s*[{[].*/))try{i=h.parseJSON(n)}catch(e){i=n}else i=n;return i}(e);t(e)},error:function(e,t){var i;try{i="HTTP "+e.status+" attempting to load TileSource: "+n}catch(e){i=(void 0!==t&&t.toString?t.toString():"Unknown error")+" attempting to load TileSource: "+n}h.console.error(i);s.raiseEvent("open-failed",{message:i,source:n,postData:a})}})},supports:function(e,t){return!1},configure:function(e,t,i){throw new Error("Method not implemented.")},getTileUrl:function(e,t,i){throw new Error("Method not implemented.")},getTilePostData:function(e,t,i){return null},getTileAjaxHeaders:function(e,t,i){return{}},getTileHashKey:function(e,t,i,n,o,r){function s(e){return o?e+"+"+JSON.stringify(o):e}return s("string"!=typeof n?e+"/"+t+"_"+i:n)},tileExists:function(e,t,i){var n=this.getNumTiles(e);return e>=this.minLevel&&e<=this.maxLevel&&0<=t&&0<=i&&tthis.maxLevel)return!1;if(!h||!h.length)return!0;for(l=h.length-1;0<=l;l--)if(!(e<(n=h[l]).minLevel||e>n.maxLevel)){a=this.getLevelScale(e);o=n.x*a;r=n.y*a;s=o+n.width*a;a=r+n.height*a;o=Math.floor(o/this._tileWidth);r=Math.floor(r/this._tileWidth);s=Math.ceil(s/this._tileWidth);a=Math.ceil(a/this._tileWidth);if(o<=t&&t=this.minLevel&&e<=this.maxLevel?this.levels[e].width/this.levels[this.maxLevel].width:t}return h.TileSource.prototype.getLevelScale.call(this,e)},getNumTiles:function(e){if(this.emulateLegacyImagePyramid)return this.getLevelScale(e)?new h.Point(1,1):new h.Point(0,0);if(this.levelSizes){var t=this.levelSizes[e];var i=Math.ceil(t.width/this.getTileWidth(e)),t=Math.ceil(t.height/this.getTileHeight(e));return new h.Point(i,t)}return h.TileSource.prototype.getNumTiles.call(this,e)},getTileAtPoint:function(e,t){if(this.emulateLegacyImagePyramid)return new h.Point(0,0);if(this.levelSizes){var i=0<=t.x&&t.x<=1&&0<=t.y&&t.y<=1/this.aspectRatio;h.console.assert(i,"[TileSource.getTileAtPoint] must be called with a valid point.");var n=this.levelSizes[e].width;i=t.x*n;n=t.y*n;i=Math.floor(i/this.getTileWidth(e));n=Math.floor(n/this.getTileHeight(e));1<=t.x&&(i=this.getNumTiles(e).x-1);t.y>=1/this.aspectRatio-1e-15&&(n=this.getNumTiles(e).y-1);return new h.Point(i,n)}return h.TileSource.prototype.getTileAtPoint.call(this,e,t)},getTileUrl:function(e,t,i){if(this.emulateLegacyImagePyramid){var n=null;return n=0=this.minLevel&&e<=this.maxLevel?this.levels[e].url:n}var o,r,s,a,l,h,c,u,d=Math.pow(.5,this.maxLevel-e);if(this.levelSizes){o=this.levelSizes[e].width;r=this.levelSizes[e].height}else{o=Math.ceil(this.width*d);r=Math.ceil(this.height*d)}c=this.getTileWidth(e);u=this.getTileHeight(e);a=Math.round(c/d);l=Math.round(u/d);n=1===this.version?"native."+this.tileFormat:"default."+this.tileFormat;if(oe.tileSize||parseInt(t.y,10)>e.tileSize;){t.x=Math.floor(t.x/2);t.y=Math.floor(t.y/2);e.imageSizes.push({x:t.x,y:t.y});e.gridSize.push(this._getGridSize(t.x,t.y,e.tileSize))}e.imageSizes.reverse();e.gridSize.reverse();e.minLevel=0;e.maxLevel=e.gridSize.length-1;OpenSeadragon.TileSource.apply(this,[e])};e.extend(e.ZoomifyTileSource.prototype,e.TileSource.prototype,{_getGridSize:function(e,t,i){return{x:Math.ceil(e/i),y:Math.ceil(t/i)}},_calculateAbsoluteTileNumber:function(e,t,i){var n=0;var o={};for(var r=0;r");return n.sort(function(e,t){return e.height-t.height})}(t.levels);if(0=this.minLevel&&e<=this.maxLevel?this.levels[e].width/this.levels[this.maxLevel].width:t},getNumTiles:function(e){return this.getLevelScale(e)?new a.Point(1,1):new a.Point(0,0)},getTileUrl:function(e,t,i){var n=null;return n=0=this.minLevel&&e<=this.maxLevel?this.levels[e].url:n}})}(OpenSeadragon);!function(a){a.ImageTileSource=function(e){e=a.extend({buildPyramid:!0,crossOriginPolicy:!1,ajaxWithCredentials:!1,useCanvas:!0},e);a.TileSource.apply(this,[e])};a.extend(a.ImageTileSource.prototype,a.TileSource.prototype,{supports:function(e,t){return e.type&&"image"===e.type},configure:function(e,t,i){return e},getImageInfo:function(e){var t=this._image=new Image;var i=this;this.crossOriginPolicy&&(t.crossOrigin=this.crossOriginPolicy);this.ajaxWithCredentials&&(t.useCredentials=this.ajaxWithCredentials);a.addEvent(t,"load",function(){i.width=t.naturalWidth;i.height=t.naturalHeight;i.aspectRatio=i.width/i.height;i.dimensions=new a.Point(i.width,i.height);i._tileWidth=i.width;i._tileHeight=i.height;i.tileOverlap=0;i.minLevel=0;i.levels=i._buildLevels();i.maxLevel=i.levels.length-1;i.ready=!0;i.raiseEvent("ready",{tileSource:i})});a.addEvent(t,"error",function(){i.raiseEvent("open-failed",{message:"Error loading image at "+e,source:e})});t.src=e},getLevelScale:function(e){var t=NaN;return t=e>=this.minLevel&&e<=this.maxLevel?this.levels[e].width/this.levels[this.maxLevel].width:t},getNumTiles:function(e){return this.getLevelScale(e)?new a.Point(1,1):new a.Point(0,0)},getTileUrl:function(e,t,i){var n=null;return n=e>=this.minLevel&&e<=this.maxLevel?this.levels[e].url:n},getContext2D:function(e,t,i){var n=null;return n=e>=this.minLevel&&e<=this.maxLevel?this.levels[e].context2D:n},destroy:function(){this._freeupCanvasMemory()},_buildLevels:function(){var e=[{url:this._image.src,width:this._image.naturalWidth,height:this._image.naturalHeight}];if(!this.buildPyramid||!a.supportsCanvas||!this.useCanvas){delete this._image;return e}var t=this._image.naturalWidth;var i=this._image.naturalHeight;var n=document.createElement("canvas");var o=n.getContext("2d");n.width=t;n.height=i;o.drawImage(this._image,0,0,t,i);e[0].context2D=o;delete this._image;if(a.isCanvasTainted(n))return e;for(;2<=t&&2<=i;){t=Math.floor(t/2);i=Math.floor(i/2);var r=document.createElement("canvas");var s=r.getContext("2d");r.width=t;r.height=i;s.drawImage(n,0,0,t,i);e.splice(0,0,{context2D:s,width:t,height:i});n=r;o=s}return e},_freeupCanvasMemory:function(){for(var e=0;e=i.ButtonState.GROUP&&e.currentState===i.ButtonState.REST){!function(e){e.shouldFade=!1;e.imgGroup&&i.setElementOpacity(e.imgGroup,1,!0)}(e);e.currentState=i.ButtonState.GROUP}if(t>=i.ButtonState.HOVER&&e.currentState===i.ButtonState.GROUP){e.imgHover&&(e.imgHover.style.visibility="");e.currentState=i.ButtonState.HOVER}if(t>=i.ButtonState.DOWN&&e.currentState===i.ButtonState.HOVER){e.imgDown&&(e.imgDown.style.visibility="");e.currentState=i.ButtonState.DOWN}}}function r(e,t){if(!e.element.disabled){if(t<=i.ButtonState.HOVER&&e.currentState===i.ButtonState.DOWN){e.imgDown&&(e.imgDown.style.visibility="hidden");e.currentState=i.ButtonState.HOVER}if(t<=i.ButtonState.GROUP&&e.currentState===i.ButtonState.HOVER){e.imgHover&&(e.imgHover.style.visibility="hidden");e.currentState=i.ButtonState.GROUP}if(t<=i.ButtonState.REST&&e.currentState===i.ButtonState.GROUP){!function(e){e.shouldFade=!0;e.fadeBeginTime=i.now()+e.fadeDelay;window.setTimeout(function(){n(e)},e.fadeDelay)}(e);e.currentState=i.ButtonState.REST}}}}(OpenSeadragon);!function(o){o.ButtonGroup=function(e){o.extend(!0,this,{buttons:[],clickTimeThreshold:o.DEFAULT_SETTINGS.clickTimeThreshold,clickDistThreshold:o.DEFAULT_SETTINGS.clickDistThreshold,labelText:""},e);var t,i=this.buttons.concat([]),n=this;this.element=e.element||o.makeNeutralElement("div");if(!e.group){this.element.style.display="inline-block";for(t=0;tu&&(u=m.x);m.yp&&(p=m.y)}return new v.Rect(c,d,u-c,p-d)},_getSegments:function(){var e=this.getTopLeft();var t=this.getTopRight();var i=this.getBottomLeft();var n=this.getBottomRight();return[[e,t],[t,n],[n,i],[i,e]]},rotate:function(e,t){if(0===(e=v.positiveModulo(e,360)))return this.clone();t=t||this.getCenter();var i=this.getTopLeft().rotate(e,t);e=this.getTopRight().rotate(e,t).minus(i);e=e.apply(function(e){return Math.abs(e)<1e-15?0:e});t=Math.atan(e.y/e.x);e.x<0?t+=Math.PI:e.y<0&&(t+=2*Math.PI);return new v.Rect(i.x,i.y,this.width,this.height,t/Math.PI*180)},getBoundingBox:function(){if(0===this.degrees)return this.clone();var e=this.getTopLeft();var t=this.getTopRight();var i=this.getBottomLeft();var n=this.getBottomRight();var o=Math.min(e.x,t.x,i.x,n.x);var r=Math.max(e.x,t.x,i.x,n.x);var s=Math.min(e.y,t.y,i.y,n.y);n=Math.max(e.y,t.y,i.y,n.y);return new v.Rect(o,s,r-o,n-s)},getIntegerBoundingBox:function(){var e=this.getBoundingBox();var t=Math.floor(e.x);var i=Math.floor(e.y);var n=Math.ceil(e.width+e.x-t);e=Math.ceil(e.height+e.y-i);return new v.Rect(t,i,n,e)},containsPoint:function(e,t){t=t||0;var i=this.getTopLeft();var n=this.getTopRight();var o=this.getBottomLeft();var r=n.minus(i);var s=o.minus(i);return(e.x-i.x)*r.x+(e.y-i.y)*r.y>=-t&&(e.x-n.x)*r.x+(e.y-n.y)*r.y<=t&&(e.x-i.x)*s.x+(e.y-i.y)*s.y>=-t&&(e.x-o.x)*s.x+(e.y-o.y)*s.y<=t},toString:function(){return"["+Math.round(100*this.x)/100+", "+Math.round(100*this.y)/100+", "+Math.round(100*this.width)/100+"x"+Math.round(100*this.height)/100+", "+Math.round(100*this.degrees)/100+"deg]"}}}(OpenSeadragon);!function(h){var s={};h.ReferenceStrip=function(e){var t,i,n,o=e.viewer,r=h.getElementSize(o.element);if(!e.id){e.id="referencestrip-"+h.now();this.element=h.makeNeutralElement("div");this.element.id=e.id;this.element.className="referencestrip"}e=h.extend(!0,{sizeRatio:h.DEFAULT_SETTINGS.referenceStripSizeRatio,position:h.DEFAULT_SETTINGS.referenceStripPosition,scroll:h.DEFAULT_SETTINGS.referenceStripScroll,clickTimeThreshold:h.DEFAULT_SETTINGS.clickTimeThreshold},e,{element:this.element});h.extend(this,e);s[this.id]={animating:!1};this.minPixelRatio=this.viewer.minPixelRatio;this.element.tabIndex=0;(i=this.element.style).marginTop="0px";i.marginRight="0px";i.marginBottom="0px";i.marginLeft="0px";i.left="0px";i.bottom="0px";i.border="0px";i.background="#000";i.position="relative";h.setElementTouchActionNone(this.element);h.setElementOpacity(this.element,.8);this.viewer=o;this.tracker=new h.MouseTracker({userData:"ReferenceStrip.tracker",element:this.element,clickHandler:h.delegate(this,a),dragHandler:h.delegate(this,l),scrollHandler:h.delegate(this,c),enterHandler:h.delegate(this,d),leaveHandler:h.delegate(this,p),keyDownHandler:h.delegate(this,g),keyHandler:h.delegate(this,m),preProcessEventHandler:function(e){"wheel"===e.eventType&&(e.preventDefault=!0)}});if(e.width&&e.height){this.element.style.width=e.width+"px";this.element.style.height=e.height+"px";o.addControl(this.element,{anchor:h.ControlAnchor.BOTTOM_LEFT})}else if("horizontal"===e.scroll){this.element.style.width=r.x*e.sizeRatio*o.tileSources.length+12*o.tileSources.length+"px";this.element.style.height=r.y*e.sizeRatio+"px";o.addControl(this.element,{anchor:h.ControlAnchor.BOTTOM_LEFT})}else{this.element.style.height=r.y*e.sizeRatio*o.tileSources.length+12*o.tileSources.length+"px";this.element.style.width=r.x*e.sizeRatio+"px";o.addControl(this.element,{anchor:h.ControlAnchor.TOP_LEFT})}this.panelWidth=r.x*this.sizeRatio+8;this.panelHeight=r.y*this.sizeRatio+8;this.panels=[];this.miniViewers={};for(n=0;ns+n.x-this.panelWidth){t=Math.min(t,o-n.x);this.element.style.marginLeft=-t+"px";u(this,n.x,-t)}else if(ta+n.y-this.panelHeight){t=Math.min(t,r-n.y);this.element.style.marginTop=-t+"px";u(this,n.y,-t)}else if(t-(n-r.x)){this.element.style.marginLeft=t+2*e.delta.x+"px";u(this,r.x,t+2*e.delta.x)}}else if(-e.delta.x<0&&t<0){this.element.style.marginLeft=t+2*e.delta.x+"px";u(this,r.x,t+2*e.delta.x)}}else if(0<-e.delta.y){if(i>-(o-r.y)){this.element.style.marginTop=i+2*e.delta.y+"px";u(this,r.y,i+2*e.delta.y)}}else if(-e.delta.y<0&&i<0){this.element.style.marginTop=i+2*e.delta.y+"px";u(this,r.y,i+2*e.delta.y)}}}function c(e){if(this.element){var t=Number(this.element.style.marginLeft.replace("px","")),i=Number(this.element.style.marginTop.replace("px","")),n=Number(this.element.style.width.replace("px","")),o=Number(this.element.style.height.replace("px","")),r=h.getElementSize(this.viewer.canvas);if("horizontal"===this.scroll){if(0-(n-r.x)){this.element.style.marginLeft=t-60*e.scroll+"px";u(this,r.x,t-60*e.scroll)}}else if(e.scroll<0&&t<0){this.element.style.marginLeft=t-60*e.scroll+"px";u(this,r.x,t-60*e.scroll)}}else if(e.scroll<0){if(i>r.y-o){this.element.style.marginTop=i+60*e.scroll+"px";u(this,r.y,i+60*e.scroll)}}else if(0=this.target.time?t:e+(t-e)*(n=this.springStiffness,i=(this.current.time-this.start.time)/(this.target.time-this.start.time),(1-Math.exp(n*-i))/(1-Math.exp(-n)));var i;var n=this.current.value;this._exponential?this.current.value=Math.exp(i):this.current.value=i;return n!==this.current.value},isAtTargetValue:function(){return this.current.value===this.target.value}}}(OpenSeadragon);!function(n){n.ImageJob=function(e){n.extend(!0,this,{timeout:n.DEFAULT_SETTINGS.timeout,jobId:null,tries:0},e);this.data=null;this.userData={};this.errorMsg=null};n.ImageJob.prototype={start:function(){this.tries++;var e=this;var t=this.abort;this.jobId=window.setTimeout(function(){e.finish(null,null,"Image load exceeded timeout ("+e.timeout+" ms)")},this.timeout);this.abort=function(){e.source.downloadTileAbort(e);"function"==typeof t&&t()};this.source.downloadTileStart(this)},finish:function(e,t,i){this.data=e;this.request=t;this.errorMsg=i;this.jobId&&window.clearTimeout(this.jobId);this.callback(this)}};n.ImageLoader=function(e){n.extend(!0,this,{jobLimit:n.DEFAULT_SETTINGS.imageLoaderLimit,timeout:n.DEFAULT_SETTINGS.timeout,jobQueue:[],failedTiles:[],jobsInProgress:0},e)};n.ImageLoader.prototype={addJob:function(t){if(!t.source){n.console.error("ImageLoader.prototype.addJob() requires [options.source]. TileSource since new API defines how images are fetched. Creating a dummy TileSource.");var e=n.TileSource.prototype;t.source={downloadTileStart:e.downloadTileStart,downloadTileAbort:e.downloadTileAbort}}var i=this,e={src:t.src,tile:t.tile||{},source:t.source,loadWithAjax:t.loadWithAjax,ajaxHeaders:t.loadWithAjax?t.ajaxHeaders:null,crossOriginPolicy:t.crossOriginPolicy,ajaxWithCredentials:t.ajaxWithCredentials,postData:t.postData,callback:function(e){!function(e,t,i){""!==t.errorMsg&&(null===t.data||void 0===t.data)&&t.tries<1+e.tileRetryMax&&e.failedTiles.push(t);var n;e.jobsInProgress--;if((!e.jobLimit||e.jobsInProgressthis.canvas.width&&(r.width=this.canvas.width-r.x);if(r.y<0){r.height+=r.y;r.y=0}r.y+r.height>this.canvas.height&&(r.height=this.canvas.height-r.y);this.context.drawImage(this.sketchCanvas,r.x,r.y,r.width,r.height,r.x,r.y,r.width,r.height)}else{t=o.scale||1;e=(i=o.translate)instanceof a.Point?i:new a.Point(0,0);n=0;r=0;if(i){o=this.sketchCanvas.width-this.canvas.width;i=this.sketchCanvas.height-this.canvas.height;n=Math.round(o/2);r=Math.round(i/2)}this.context.drawImage(this.sketchCanvas,e.x-n*t,e.y-r*t,(this.canvas.width+2*n)*t,(this.canvas.height+2*r)*t,-n,-r,this.canvas.width+2*n,this.canvas.height+2*r)}this.context.restore()}},drawDebugInfo:function(e,t,i,n){if(this.useCanvas){var o=this.viewer.world.getIndexOfItem(n)%this.debugGridColor.length;var r=this.context;r.save();r.lineWidth=2*a.pixelDensityRatio;r.font="small-caps bold "+13*a.pixelDensityRatio+"px arial";r.strokeStyle=this.debugGridColor[o];r.fillStyle=this.debugGridColor[o];this.viewport.getRotation(!0)%360!=0&&this._offsetForRotation({degrees:this.viewport.getRotation(!0)});n.getRotation(!0)%360!=0&&this._offsetForRotation({degrees:n.getRotation(!0),point:n.viewport.pixelFromPointNoRotate(n._getRotationPoint(!0),!0)});n.viewport.getRotation(!0)%360==0&&n.getRotation(!0)%360==0&&n._drawer.viewer.viewport.getFlip()&&n._drawer._flip();r.strokeRect(e.position.x*a.pixelDensityRatio,e.position.y*a.pixelDensityRatio,e.size.x*a.pixelDensityRatio,e.size.y*a.pixelDensityRatio);var s=(e.position.x+e.size.x/2)*a.pixelDensityRatio;o=(e.position.y+e.size.y/2)*a.pixelDensityRatio;r.translate(s,o);r.rotate(Math.PI/180*-this.viewport.getRotation(!0));r.translate(-s,-o);if(0===e.x&&0===e.y){r.fillText("Zoom: "+this.viewport.getZoom(),e.position.x*a.pixelDensityRatio,(e.position.y-30)*a.pixelDensityRatio);r.fillText("Pan: "+this.viewport.getBounds().toString(),e.position.x*a.pixelDensityRatio,(e.position.y-20)*a.pixelDensityRatio)}r.fillText("Level: "+e.level,(e.position.x+10)*a.pixelDensityRatio,(e.position.y+20)*a.pixelDensityRatio);r.fillText("Column: "+e.x,(e.position.x+10)*a.pixelDensityRatio,(e.position.y+30)*a.pixelDensityRatio);r.fillText("Row: "+e.y,(e.position.x+10)*a.pixelDensityRatio,(e.position.y+40)*a.pixelDensityRatio);r.fillText("Order: "+i+" of "+t,(e.position.x+10)*a.pixelDensityRatio,(e.position.y+50)*a.pixelDensityRatio);r.fillText("Size: "+e.size.toString(),(e.position.x+10)*a.pixelDensityRatio,(e.position.y+60)*a.pixelDensityRatio);r.fillText("Position: "+e.position.toString(),(e.position.x+10)*a.pixelDensityRatio,(e.position.y+70)*a.pixelDensityRatio);this.viewport.getRotation(!0)%360!=0&&this._restoreRotationChanges();n.getRotation(!0)%360!=0&&this._restoreRotationChanges();n.viewport.getRotation(!0)%360==0&&n.getRotation(!0)%360==0&&n._drawer.viewer.viewport.getFlip()&&n._drawer._flip();r.restore()}},debugRect:function(e){if(this.useCanvas){var t=this.context;t.save();t.lineWidth=2*a.pixelDensityRatio;t.strokeStyle=this.debugGridColor[0];t.fillStyle=this.debugGridColor[0];t.strokeRect(e.x*a.pixelDensityRatio,e.y*a.pixelDensityRatio,e.width*a.pixelDensityRatio,e.height*a.pixelDensityRatio);t.restore()}},setImageSmoothingEnabled:function(e){if(this.useCanvas){this._imageSmoothingEnabled=e;this._updateImageSmoothingEnabled(this.context);this.viewer.forceRedraw()}},_updateImageSmoothingEnabled:function(e){e.msImageSmoothingEnabled=this._imageSmoothingEnabled;e.imageSmoothingEnabled=this._imageSmoothingEnabled},getCanvasSize:function(e){e=this._getContext(e).canvas;return new a.Point(e.width,e.height)},getCanvasCenter:function(){return new a.Point(this.canvas.width/2,this.canvas.height/2)},_offsetForRotation:function(e){var t=e.point?e.point.times(a.pixelDensityRatio):this.getCanvasCenter();var i=this._getContext(e.useSketch);i.save();i.translate(t.x,t.y);if(this.viewer.viewport.flipped){i.rotate(Math.PI/180*-e.degrees);i.scale(-1,1)}else i.rotate(Math.PI/180*e.degrees);i.translate(-t.x,-t.y)},_flip:function(e){var t=(e=e||{}).point?e.point.times(a.pixelDensityRatio):this.getCanvasCenter();e=this._getContext(e.useSketch);e.translate(t.x,0);e.scale(-1,1);e.translate(-t.x,0)},_restoreRotationChanges:function(e){this._getContext(e).restore()},_calculateCanvasSize:function(){var e=a.pixelDensityRatio;var t=this.viewport.getContainerSize();return{x:Math.round(t.x*e),y:Math.round(t.y*e)}},_calculateSketchCanvasSize:function(){var e=this._calculateCanvasSize();if(0===this.viewport.getRotation())return e;e=Math.ceil(Math.sqrt(e.x*e.x+e.y*e.y));return{x:e,y:e}}}}(OpenSeadragon);!function(h){h.Viewport=function(e){var t=arguments;if((e=t.length&&t[0]instanceof h.Point?{containerSize:t[0],contentSize:t[1],config:t[2]}:e).config){h.extend(!0,e,e.config);delete e.config}this._margins=h.extend({left:0,top:0,right:0,bottom:0},e.margins||{});delete e.margins;e.initialDegrees=e.degrees;delete e.degrees;h.extend(!0,this,{containerSize:null,contentSize:null,zoomPoint:null,rotationPivot:null,viewer:null,springStiffness:h.DEFAULT_SETTINGS.springStiffness,animationTime:h.DEFAULT_SETTINGS.animationTime,minZoomImageRatio:h.DEFAULT_SETTINGS.minZoomImageRatio,maxZoomPixelRatio:h.DEFAULT_SETTINGS.maxZoomPixelRatio,visibilityRatio:h.DEFAULT_SETTINGS.visibilityRatio,wrapHorizontal:h.DEFAULT_SETTINGS.wrapHorizontal,wrapVertical:h.DEFAULT_SETTINGS.wrapVertical,defaultZoomLevel:h.DEFAULT_SETTINGS.defaultZoomLevel,minZoomLevel:h.DEFAULT_SETTINGS.minZoomLevel,maxZoomLevel:h.DEFAULT_SETTINGS.maxZoomLevel,initialDegrees:h.DEFAULT_SETTINGS.degrees,flipped:h.DEFAULT_SETTINGS.flipped,homeFillsViewer:h.DEFAULT_SETTINGS.homeFillsViewer,silenceMultiImageWarnings:h.DEFAULT_SETTINGS.silenceMultiImageWarnings},e);this._updateContainerInnerSize();this.centerSpringX=new h.Spring({initial:0,springStiffness:this.springStiffness,animationTime:this.animationTime});this.centerSpringY=new h.Spring({initial:0,springStiffness:this.springStiffness,animationTime:this.animationTime});this.zoomSpring=new h.Spring({exponential:!0,initial:1,springStiffness:this.springStiffness,animationTime:this.animationTime});this.degreesSpring=new h.Spring({initial:e.initialDegrees,springStiffness:this.springStiffness,animationTime:this.animationTime});this._oldCenterX=this.centerSpringX.current.value;this._oldCenterY=this.centerSpringY.current.value;this._oldZoom=this.zoomSpring.current.value;this._oldDegrees=this.degreesSpring.current.value;this._setContentBounds(new h.Rect(0,0,1,1),1);this.goHome(!0);this.update()};h.Viewport.prototype={get degrees(){h.console.warn("Accessing [Viewport.degrees] is deprecated. Use viewport.getRotation instead.");return this.getRotation()},set degrees(e){h.console.warn("Setting [Viewport.degrees] is deprecated. Use viewport.rotateTo, viewport.rotateBy, or viewport.setRotation instead.");this.rotateTo(e)},resetContentSize:function(e){h.console.assert(e,"[Viewport.resetContentSize] contentSize is required");h.console.assert(e instanceof h.Point,"[Viewport.resetContentSize] contentSize must be an OpenSeadragon.Point");h.console.assert(0i.width?this.visibilityRatio*i.width:this.visibilityRatio*t.width;r=i.x-r+a;s=s-t.x-a;if(a>i.width){t.x+=(r+s)/2;n=!0}else if(s<0){t.x+=s;n=!0}else if(0i.height?this.visibilityRatio*i.height:this.visibilityRatio*t.height;l=i.y-l+r;s=s-t.y-r;if(r>i.height){t.y+=(l+s)/2;o=!0}else if(s<0){t.y+=s;o=!0}else if(0=o?s.height=s.width/o:s.width=s.height*o;s.x=r.x-s.width/2;s.y=r.y-s.height/2;var a=1/s.width;if(i){this.panTo(r,!0);this.zoomTo(a,null,!0);n&&this.applyConstraints(!0);return this}var l=this.getCenter(!0);t=this.getZoom(!0);this.panTo(l,!0);this.zoomTo(t,null,!0);e=this.getBounds();o=this.getZoom();if(0===o||Math.abs(a/o-1)<1e-8){this.zoomTo(a,null,!0);this.panTo(r,i);n&&this.applyConstraints(!1);return this}if(n){this.panTo(r,!1);a=this._applyZoomConstraints(a);this.zoomTo(a,null,!1);r=this.getConstrainedBounds();this.panTo(l,!0);this.zoomTo(t,null,!0);this.fitBounds(r)}else{o=s.rotate(-this.getRotation()).getTopLeft().times(a).minus(e.getTopLeft().times(o)).divide(a-o);this.zoomTo(a,o,i)}return this},fitBounds:function(e,t){return this._fitBounds(e,{immediately:t,constraints:!1})},fitBoundsWithConstraints:function(e,t){return this._fitBounds(e,{immediately:t,constraints:!0})},fitVertically:function(e){var t=new h.Rect(this._contentBounds.x+this._contentBounds.width/2,this._contentBounds.y,0,this._contentBounds.height);return this.fitBounds(t,e)},fitHorizontally:function(e){var t=new h.Rect(this._contentBounds.x,this._contentBounds.y+this._contentBounds.height/2,this._contentBounds.width,0);return this.fitBounds(t,e)},getConstrainedBounds:function(e){e=this.getBounds(e);return this._applyBoundaryConstraints(e)},panBy:function(e,t){var i=new h.Point(this.centerSpringX.target.value,this.centerSpringY.target.value);return this.panTo(i.plus(e),t)},panTo:function(e,t){if(t){this.centerSpringX.resetTo(e.x);this.centerSpringY.resetTo(e.y)}else{this.centerSpringX.springTo(e.x);this.centerSpringY.springTo(e.y)}this.viewer&&this.viewer.raiseEvent("pan",{center:e,immediately:t});return this},zoomBy:function(e,t,i){return this.zoomTo(this.zoomSpring.target.value*e,t,i)},zoomTo:function(e,t,i){var n=this;this.zoomPoint=t instanceof h.Point&&!isNaN(t.x)&&!isNaN(t.y)?t:null;i?this._adjustCenterSpringsForZoomPoint(function(){n.zoomSpring.resetTo(e)}):this.zoomSpring.springTo(e);this.viewer&&this.viewer.raiseEvent("zoom",{zoom:e,refPoint:t,immediately:i});return this},setRotation:function(e,t){return this.rotateTo(e,null,t)},getRotation:function(e){return(e?this.degreesSpring.current:this.degreesSpring.target).value},setRotationWithPivot:function(e,t,i){return this.rotateTo(e,t,i)},rotateTo:function(e,t,i){if(!this.viewer||!this.viewer.drawer.canRotate())return this;if(this.degreesSpring.target.value===e&&this.degreesSpring.isAtTargetValue())return this;this.rotationPivot=t instanceof h.Point&&!isNaN(t.x)&&!isNaN(t.y)?t:null;if(i)if(this.rotationPivot){if(!(e-this._oldDegrees)){this.rotationPivot=null;return this}this._rotateAboutPivot(e)}else this.degreesSpring.resetTo(e);else{var n=h.positiveModulo(this.degreesSpring.current.value,360);var o=h.positiveModulo(e,360);t=o-n;180o){r=this._clip.x/this._clip.height*e.height;s=this._clip.y/this._clip.height*e.height}else{r=this._clip.x/this._clip.width*e.width;s=this._clip.y/this._clip.width*e.width}}if(e.getAspectRatio()>o){var l=e.height/t;t=0;n.isHorizontallyCentered?t=(e.width-e.height*o)/2:n.isRight&&(t=e.width-e.height*o);this.setPosition(new y.Point(e.x-r+t,e.y-s),i);this.setHeight(l,i)}else{l=e.width/a;a=0;n.isVerticallyCentered?a=(e.height-e.width/o)/2:n.isBottom&&(a=e.height-e.width/o);this.setPosition(new y.Point(e.x-r,e.y-s+a),i);this.setWidth(l,i)}},getClip:function(){return this._clip?this._clip.clone():null},setClip:function(e){y.console.assert(!e||e instanceof y.Rect,"[TiledImage.setClip] newClip must be an OpenSeadragon.Rect or null");e instanceof y.Rect?this._clip=e.clone():this._clip=null;this._needsDraw=!0;this.raiseEvent("clip-change")},getFlip:function(){return!!this.flipped},setFlip:function(e){this.flipped=!!e;this._needsDraw=!0;this._raiseBoundsChange()},getOpacity:function(){return this.opacity},setOpacity:function(e){if(e!==this.opacity){this.opacity=e;this._needsDraw=!0;this.raiseEvent("opacity-change",{opacity:this.opacity})}},getPreload:function(){return this._preload},setPreload:function(e){this._preload=!!e;this._needsDraw=!0},getRotation:function(e){return(e?this._degreesSpring.current:this._degreesSpring.target).value},setRotation:function(e,t){if(this._degreesSpring.target.value!==e||!this._degreesSpring.isAtTargetValue()){t?this._degreesSpring.resetTo(e):this._degreesSpring.springTo(e);this._needsDraw=!0;this._raiseBoundsChange()}},_getRotationPoint:function(e){return this.getBoundsNoRotate(e).getCenter()},getCompositeOperation:function(){return this.compositeOperation},setCompositeOperation:function(e){if(e!==this.compositeOperation){this.compositeOperation=e;this._needsDraw=!0;this.raiseEvent("composite-operation-change",{compositeOperation:this.compositeOperation})}},setAjaxHeaders:function(e,t){if(y.isPlainObject(e=null===e?{}:e)){this._ownAjaxHeaders=e;this._updateAjaxHeaders(t)}else console.error("[TiledImage.setAjaxHeaders] Ignoring invalid headers, must be a plain object")},_updateAjaxHeaders:function(e){void 0===e&&(e=!0);y.isPlainObject(this.viewer.ajaxHeaders)?this.ajaxHeaders=y.extend({},this.viewer.ajaxHeaders,this._ownAjaxHeaders):this.ajaxHeaders=this._ownAjaxHeaders;if(e){var t,i;for(var n in this.tilesMatrix){t=this.source.getNumTiles(n);for(var o in this.tilesMatrix[n]){i=(t.x+o%t.x)%t.x;for(var r in this.tilesMatrix[n][o]){s=(t.y+r%t.y)%t.y;(r=this.tilesMatrix[n][o][r]).loadWithAjax=this.loadTilesWithAjax;if(r.loadWithAjax){var s=this.source.getTileAjaxHeaders(n,i,s);r.ajaxHeaders=y.extend({},this.ajaxHeaders,s)}else r.ajaxHeaders=null}}}for(var a=0;a=this.minPixelRatio)r=l=!0;else if(!r)continue;var c=e.deltaPixelsFromPointsNoRotate(this.source.getPixelRatio(a),!1).x*this._scaleSpring.current.value;var u=e.deltaPixelsFromPointsNoRotate(this.source.getPixelRatio(Math.max(this.source.getClosestLevel(),0)),!1).x*this._scaleSpring.current.value;u=this.immediateRender?1:u;h=Math.min(1,(h-.5)/.5);c=u/Math.abs(u-c);o=this._updateLevel(r,l,a,h,c,t,s,o);if(this._providesCoverage(this.coverage,a))break}this._drawTiles(this.lastDrawn);if(o&&!o.context2D){this._loadTile(o,s);this._needsDraw=!0;this._setFullyLoaded(!1)}else this._setFullyLoaded(0===this._tilesLoading)},_getCornerTiles:function(e,t,i){var n;var o;if(this.wrapHorizontal){n=y.positiveModulo(t.x,1);o=y.positiveModulo(i.x,1)}else{n=Math.max(0,t.x);o=Math.min(1,i.x)}var r=1/this.source.aspectRatio;if(this.wrapVertical){s=y.positiveModulo(t.y,r);a=y.positiveModulo(i.y,r)}else{s=Math.max(0,t.y);a=Math.min(r,i.y)}var s=this.source.getTileAtPoint(e,new y.Point(n,s));var a=this.source.getTileAtPoint(e,new y.Point(o,a));e=this.source.getNumTiles(e);if(this.wrapHorizontal){s.x+=e.x*Math.floor(t.x);a.x+=e.x*Math.floor(i.x)}if(this.wrapVertical){s.y+=e.y*Math.floor(t.y/r);a.y+=e.y*Math.floor(i.y/r)}return{topLeft:s,bottomRight:a}},_updateLevel:function(e,t,i,n,o,r,s,a){var l=r.getBoundingBox().getTopLeft();var h=r.getBoundingBox().getBottomRight();this.viewer&&this.viewer.raiseEvent("update-level",{tiledImage:this,havedrawn:e,level:i,opacity:n,visibility:o,drawArea:r,topleft:l,bottomright:h,currenttime:s,best:a});this._resetCoverage(this.coverage,i);this._resetCoverage(this.loadingCoverage,i);h=this._getCornerTiles(i,l,h);var c=h.topLeft;var u=h.bottomRight;var d=this.source.getNumTiles(i);var p=this.viewport.pixelFromPoint(this.viewport.getCenter());if(this.getFlip()){u.x+=1;this.wrapHorizontal||(u.x=Math.min(u.x,d.x-1))}for(var g=c.x;g<=u.x;g++)for(var m=c.y;m<=u.y;m++){if(this.getFlip()){var v=(d.x+g%d.x)%d.x;v=g+d.x-v-v-1}else v=g;null!==r.intersection(this.getTileBounds(i,v,m))&&(a=this._updateTile(t,e,v,m,i,n,o,p,d,s,a))}return a},_updateTile:function(e,t,i,n,o,r,s,a,l,h,c){var u=this._getTile(i,n,o,h,l,this._worldWidthCurrent,this._worldHeightCurrent),l=t;this.viewer&&this.viewer.raiseEvent("update-tile",{tiledImage:this,tile:u});this._setCoverage(this.coverage,o,i,n,!1);t=u.loaded||u.loading||this._isCovered(this.loadingCoverage,o,i,n);this._setCoverage(this.loadingCoverage,o,i,n,t);if(!u.exists)return c;e&&!l&&(this._isCovered(this.coverage,o,i,n)?this._setCoverage(this.coverage,o,i,n,!0):l=!0);if(!l)return c;this._positionTile(u,this.source.tileOverlap,this.viewport,a,s);if(!u.loaded)if(u.context2D)this._setTileLoaded(u);else{s=this._tileCache.getImageRecord(u.cacheKey);s&&this._setTileLoaded(u,s.getData())}u.loaded?this._blendTile(u,i,n,o,r,h)&&(this._needsDraw=!0):u.loading?this._tilesLoading++:t||(c=this._compareTiles(c,u));return c},_getTile:function(e,t,i,n,o,r,s){var a,l,h,c,u,d,p,g,m,v=this.tilesMatrix,f=this.source;v[i]||(v[i]={});v[i][e]||(v[i][e]={});if(!v[i][e][t]||!v[i][e][t].flipped!=!this.flipped){a=(o.x+e%o.x)%o.x;l=(o.y+t%o.y)%o.y;h=this.getTileBounds(i,e,t);c=f.getTileBounds(i,a,l,!0);u=f.tileExists(i,a,l);d=f.getTileUrl(i,a,l);m=f.getTilePostData(i,a,l);if(this.loadTilesWithAjax){p=f.getTileAjaxHeaders(i,a,l);y.isPlainObject(this.ajaxHeaders)&&(p=y.extend({},this.ajaxHeaders,p))}else p=null;g=f.getContext2D?f.getContext2D(i,a,l):void 0;m=new y.Tile(i,e,t,h,u,d,g,this.loadTilesWithAjax,p,c,m,f.getTileHashKey(i,a,l,d,p,m));this.getFlip()?0==a&&(m.isRightMost=!0):a==o.x-1&&(m.isRightMost=!0);l==o.y-1&&(m.isBottomMost=!0);m.flipped=this.flipped;v[i][e][t]=m}(m=v[i][e][t]).lastTouchTime=n;return m},_loadTile:function(n,o){var r=this;n.loading=!0;this._imageLoader.addJob({src:n.getUrl(),tile:n,source:this.source,postData:n.postData,loadWithAjax:n.loadWithAjax,ajaxHeaders:n.ajaxHeaders,crossOriginPolicy:this.crossOriginPolicy,ajaxWithCredentials:this.ajaxWithCredentials,callback:function(e,t,i){r._onTileLoad(n,o,e,t,i)},abort:function(){n.loading=!1}})},_onTileLoad:function(t,e,i,n,o){if(i){t.exists=!0;if(ee.visibility||t.visibility===e.visibility&&t.squaredDistancethis.smoothTileEdgesMinZoom&&!this.iOSDevice&&this.getRotation(!0)%360==0&&y.supportsCanvas&&this.viewer.useCanvas){i=!0;n=t.getScaleForEdgeSmoothing();o=t.getTranslationForEdgeSmoothing(n,this._drawer.getCanvasSize(!1),this._drawer.getCanvasSize(!0))}var a;if(i){if(!n){a=this.viewport.viewportToViewerElementRectangle(this.getClippedBounds(!0)).getIntegerBoundingBox();this._drawer.viewer.viewport.getFlip()&&(this.viewport.getRotation(!0)%360==0&&this.getRotation(!0)%360==0||(a.x=this._drawer.viewer.container.clientWidth-(a.x+a.width)));a=a.times(y.pixelDensityRatio)}this._drawer._clear(!0,a)}if(!n){this.viewport.getRotation(!0)%360!=0&&this._drawer._offsetForRotation({degrees:this.viewport.getRotation(!0),useSketch:i});this.getRotation(!0)%360!=0&&this._drawer._offsetForRotation({degrees:this.getRotation(!0),point:this.viewport.pixelFromPointNoRotate(this._getRotationPoint(!0),!0),useSketch:i});this.viewport.getRotation(!0)%360==0&&this.getRotation(!0)%360==0&&this._drawer.viewer.viewport.getFlip()&&this._drawer._flip()}r=!1;if(this._clip){this._drawer.saveContext(i);s=this.imageToViewportRectangle(this._clip,!0);s=s.rotate(-this.getRotation(!0),this._getRotationPoint(!0));s=this._drawer.viewportToDrawerRectangle(s);n&&(s=s.times(n));o&&(s=s.translate(o));this._drawer.setClip(s,i);r=!0}if(this._croppingPolygons){var l=this;this._drawer.saveContext(i);try{var h=this._croppingPolygons.map(function(e){return e.map(function(e){e=l.imageToViewportCoordinates(e.x,e.y,!0).rotate(-l.getRotation(!0),l._getRotationPoint(!0));e=l._drawer.viewportCoordToDrawerCoord(e);n&&(e=e.times(n));return e=o?e.plus(o):e})});this._drawer.clipWithPolygons(h,i)}catch(e){y.console.error(e)}r=!0}if(this.placeholderFillStyle&&!1===this._hasOpaqueTile){h=this._drawer.viewportToDrawerRectangle(this.getBounds(!0));n&&(h=h.times(n));o&&(h=h.translate(o));var c=null;c="function"==typeof this.placeholderFillStyle?this.placeholderFillStyle(this,this._drawer.context):this.placeholderFillStyle;this._drawer.drawRectangle(h,c,i)}c=function(e){if("number"==typeof e)return m(e);if(!e||!y.Browser)return p;var t=e[y.Browser.vendor];g(t)&&(t=e["*"]);return m(t)}(this.subPixelRoundingForTransparency);var u=!1;c===y.SUBPIXEL_ROUNDING_OCCURRENCES.ALWAYS?u=!0:c===y.SUBPIXEL_ROUNDING_OCCURRENCES.ONLY_AT_REST&&(u=!(this.viewer&&this.viewer.isAnimating()));for(var d=e.length-1;0<=d;d--){t=e[d];this._drawer.drawTile(t,this._drawingHandler,i,n,o,u,this.source);t.beingDrawn=!0;this.viewer&&this.viewer.raiseEvent("tile-drawn",{tiledImage:this,tile:t})}r&&this._drawer.restoreContext(i);if(!n){this.getRotation(!0)%360!=0&&this._drawer._restoreRotationChanges(i);this.viewport.getRotation(!0)%360!=0&&this._drawer._restoreRotationChanges(i)}if(i){if(n){this.viewport.getRotation(!0)%360!=0&&this._drawer._offsetForRotation({degrees:this.viewport.getRotation(!0),useSketch:!1});this.getRotation(!0)%360!=0&&this._drawer._offsetForRotation({degrees:this.getRotation(!0),point:this.viewport.pixelFromPointNoRotate(this._getRotationPoint(!0),!0),useSketch:!1})}this._drawer.blendSketch({opacity:this.opacity,scale:n,translate:o,compositeOperation:this.compositeOperation,bounds:a});if(n){this.getRotation(!0)%360!=0&&this._drawer._restoreRotationChanges(!1);this.viewport.getRotation(!0)%360!=0&&this._drawer._restoreRotationChanges(!1)}}n||this.viewport.getRotation(!0)%360==0&&this.getRotation(!0)%360==0&&this._drawer.viewer.viewport.getFlip()&&this._drawer._flip();this._drawDebugInfo(e)}},_drawDebugInfo:function(e){if(this.debugMode)for(var t=e.length-1;0<=t;t--){var i=e[t];try{this._drawer.drawDebugInfo(i,e.length,t,this)}catch(e){y.console.error(e)}}},_providesCoverage:function(e,t,i,n){var o,r,s,a;if(!e[t])return!1;if(void 0!==i&&void 0!==n)return void 0===e[t][i]||void 0===e[t][i][n]||!0===e[t][i][n];for(s in o=e[t])if(Object.prototype.hasOwnProperty.call(o,s))for(a in r=o[s])if(Object.prototype.hasOwnProperty.call(r,a)&&!r[a])return!1;return!0},_isCovered:function(e,t,i,n){return void 0===i||void 0===n?this._providesCoverage(e,t+1):this._providesCoverage(e,t+1,2*i,2*n)&&this._providesCoverage(e,t+1,2*i,2*n+1)&&this._providesCoverage(e,t+1,2*i+1,2*n)&&this._providesCoverage(e,t+1,2*i+1,2*n+1)},_setCoverage:function(e,t,i,n,o){if(e[t]){e[t][i]||(e[t][i]={});e[t][i][n]=o}else y.console.warn("Setting coverage for a tile before its level's coverage has been reset: %s",t)},_resetCoverage:function(e,t){e[t]={}}});var p=y.SUBPIXEL_ROUNDING_OCCURRENCES.NEVER;function g(e){return e!==y.SUBPIXEL_ROUNDING_OCCURRENCES.ALWAYS&&e!==y.SUBPIXEL_ROUNDING_OCCURRENCES.ONLY_AT_REST&&e!==y.SUBPIXEL_ROUNDING_OCCURRENCES.NEVER}function m(e){return g(e)?p:e}}(OpenSeadragon);!function(g){function m(e){g.console.assert(e,"[TileCache.cacheTile] options is required");g.console.assert(e.tile,"[TileCache.cacheTile] options.tile is required");g.console.assert(e.tiledImage,"[TileCache.cacheTile] options.tiledImage is required");this.tile=e.tile;this.tiledImage=e.tiledImage}function v(e){g.console.assert(e,"[ImageRecord] options is required");g.console.assert(e.data,"[ImageRecord] options.data is required");this._tiles=[];e.create.apply(null,[this,e.data,e.ownerTile]);this._destroyImplementation=e.destroy.bind(null,this);this.getImage=e.getImage.bind(null,this);this.getData=e.getData.bind(null,this);this.getRenderedContext=e.getRenderedContext.bind(null,this)}v.prototype={destroy:function(){this._destroyImplementation();this._tiles=null},addTile:function(e){g.console.assert(e,"[ImageRecord.addTile] tile is required");this._tiles.push(e)},removeTile:function(e){for(var t=0;tthis._maxImageCacheCount){var o=null;var r=-1;var s=null;var a,l,h,c,u,d;for(var p=this._tilesLoaded.length-1;0<=p;p--)if(!((a=(d=this._tilesLoaded[p]).tile).level<=t||a.beingDrawn))if(o){c=a.lastTouchTime;l=o.lastTouchTime;u=a.level;h=o.level;if(c=this._items.length)throw new Error("Index bigger than number of layers.");if(t!==i&&-1!==i){this._items.splice(i,1);this._items.splice(t,0,e);this._needsDraw=!0;this.raiseEvent("item-index-change",{item:e,previousIndex:i,newIndex:t})}},removeItem:function(e){g.console.assert(e,"[World.removeItem] item is required");var t=g.indexOf(this._items,e);if(-1!==t){e.removeHandler("bounds-change",this._delegatedFigureSizes);e.removeHandler("clip-change",this._delegatedFigureSizes);e.destroy();this._items.splice(t,1);this._figureSizes();this._needsDraw=!0;this._raiseRemoveItem(e)}},removeAll:function(){this.viewer._cancelPendingImages();var e;var t;for(t=0;td.height?r:r*(d.width/d.height))*(d.height/d.width);d=new g.Point(l+(r-u)/2,h+(r-d)/2);c.setPosition(d,t);c.setWidth(u,t);"horizontal"===i?l+=s:h+=s}this.setAutoRefigureSizes(!0)},_figureSizes:function(){var e=this._homeBounds?this._homeBounds.clone():null;var t=this._contentSize?this._contentSize.clone():null;var i=this._contentFactor||0;if(this._items.length){var n=this._items[0];var o=n.getBounds();this._contentFactor=n.getContentSize().x/o.width;var r=n.getClippedBounds().getBoundingBox();var s=r.x;var a=r.y;var l=r.x+r.width;var h=r.y+r.height;for(var c=1;c Date: Tue, 18 Nov 2025 13:56:28 +0200 Subject: [PATCH 2/7] fixed files php-cs-fixer --- .../arIiifPluginConfiguration.class.php | 30 +- .../lib/arIiifPluginComponents.class.php | 133 ++++----- .../arIiifPluginComponents.class.php.backup | 209 ------------- .../arIiifPlugin/actions/components.class.php | 133 ++++----- .../arIiifPlugin/templates/_carousel.php | 68 ++--- .../arIiifPlugin/templates/_viewer.php | 49 ++- .../modules/iiif/actions/actions.class.php | 282 +++++++++--------- .../modules/iiif/templates/canvasSuccess.php | 2 +- .../iiif/templates/manifestSuccess.php | 4 +- .../iiif/templates/objectManifestSuccess.php | 4 +- 10 files changed, 337 insertions(+), 577 deletions(-) delete mode 100644 plugins/arIiifPlugin/lib/arIiifPluginComponents.class.php.backup diff --git a/plugins/arIiifPlugin/config/arIiifPluginConfiguration.class.php b/plugins/arIiifPlugin/config/arIiifPluginConfiguration.class.php index e5c251fe05..153ca6fcb3 100644 --- a/plugins/arIiifPlugin/config/arIiifPluginConfiguration.class.php +++ b/plugins/arIiifPlugin/config/arIiifPluginConfiguration.class.php @@ -1,14 +1,12 @@ dispatcher->connect('routing.load_configuration', array($this, 'listenToRoutingLoadConfigurationEvent')); + $this->dispatcher->connect('routing.load_configuration', [$this, 'listenToRoutingLoadConfigurationEvent']); } /** - * Listen to routing.load_configuration event + * Listen to routing.load_configuration event. * * @param sfEvent $event */ public function listenToRoutingLoadConfigurationEvent(sfEvent $event) { $routing = $event->getSubject(); - + // Load plugin routing rules $routing->prependRoute('iiif_manifest', new sfRoute( '/iiif/:slug/manifest', - array('module' => 'iiif', 'action' => 'manifest') + ['module' => 'iiif', 'action' => 'manifest'] )); - + $routing->prependRoute('iiif_object_manifest', new sfRoute( '/iiif/object/:id/manifest', - array('module' => 'iiif', 'action' => 'objectManifest') + ['module' => 'iiif', 'action' => 'objectManifest'] )); - + $routing->prependRoute('iiif_canvas', new sfRoute( '/iiif/:slug/canvas/:canvas', - array('module' => 'iiif', 'action' => 'canvas') + ['module' => 'iiif', 'action' => 'canvas'] )); } /** - * Establish plugin version + * Establish plugin version. */ public static function getVersion() { diff --git a/plugins/arIiifPlugin/lib/arIiifPluginComponents.class.php b/plugins/arIiifPlugin/lib/arIiifPluginComponents.class.php index a7a942de1d..f2e69e269c 100644 --- a/plugins/arIiifPlugin/lib/arIiifPluginComponents.class.php +++ b/plugins/arIiifPlugin/lib/arIiifPluginComponents.class.php @@ -1,47 +1,40 @@ resource)) - { + if (!isset($this->resource)) { return sfView::NONE; } - $this->images = array(); - - if ($this->resource instanceof QubitDigitalObject) - { + $this->images = []; + + if ($this->resource instanceof QubitDigitalObject) { $this->images = $this->getDigitalObjectIIIFImages($this->resource); - } - else if ($this->resource instanceof QubitInformationObject) - { + } elseif ($this->resource instanceof QubitInformationObject) { $this->images = $this->getInformationObjectIIIFImages($this->resource); } - if (empty($this->images)) - { + if (empty($this->images)) { return sfView::NONE; } - $config = sfConfig::get('app_iiif_carousel', array( - 'auto_rotate' => true, - 'rotate_interval' => 5000, - 'show_navigation' => true, - 'show_thumbnails' => false, - 'viewer_height' => 600 - )); + $config = sfConfig::get('app_iiif_carousel', [ + 'auto_rotate' => true, + 'rotate_interval' => 5000, + 'show_navigation' => true, + 'show_thumbnails' => false, + 'viewer_height' => 600, + ]); $this->autoRotate = isset($this->autoRotate) ? $this->autoRotate : $config['auto_rotate']; $this->rotateInterval = isset($this->rotateInterval) ? $this->rotateInterval : $config['rotate_interval']; @@ -49,74 +42,73 @@ public function executeCarousel($request) $this->showThumbnails = isset($this->showThumbnails) ? $this->showThumbnails : $config['show_thumbnails']; $this->viewerHeight = isset($this->viewerHeight) ? $this->viewerHeight : $config['viewer_height']; - $this->carouselId = 'iiif-carousel-' . uniqid(); + $this->carouselId = 'iiif-carousel-'.uniqid(); $this->addAssets(); } /** - * Display simple IIIF viewer + * Display simple IIIF viewer. + * + * @param mixed $request */ public function executeViewer($request) { - if (!isset($this->resource) || !$this->resource instanceof QubitDigitalObject) - { + if (!isset($this->resource) || !$this->resource instanceof QubitDigitalObject) { return sfView::NONE; } $images = $this->getDigitalObjectIIIFImages($this->resource); - - if (empty($images)) - { + + if (empty($images)) { return sfView::NONE; } $this->iiifUrl = $images[0]['url']; $this->imageLabel = isset($images[0]['label']) ? $images[0]['label'] : ''; - $config = sfConfig::get('app_iiif_carousel', array('viewer_height' => 600)); + $config = sfConfig::get('app_iiif_carousel', ['viewer_height' => 600]); $this->viewerHeight = isset($this->viewerHeight) ? $this->viewerHeight : $config['viewer_height']; - $this->viewerId = 'iiif-viewer-' . uniqid(); + $this->viewerId = 'iiif-viewer-'.uniqid(); $this->addAssets(); } /** - * Get IIIF images from a digital object + * Get IIIF images from a digital object. + * + * @param mixed $digitalObject */ protected function getDigitalObjectIIIFImages($digitalObject) { - $images = array(); + $images = []; // Check for IIIF manifest URL property using Criteria - $criteria = new Criteria; + $criteria = new Criteria(); $criteria->add(QubitProperty::OBJECT_ID, $digitalObject->id); $criteria->add(QubitProperty::NAME, 'iiifManifestUrl'); - - foreach (QubitProperty::get($criteria) as $property) - { - $images[] = array( - 'url' => $property->value, - 'label' => $digitalObject->name, - 'identifier' => $digitalObject->id - ); - + + foreach (QubitProperty::get($criteria) as $property) { + $images[] = [ + 'url' => $property->value, + 'label' => $digitalObject->name, + 'identifier' => $digitalObject->id, + ]; + return $images; } // Construct IIIF URL from file path - if (null !== $digitalObject->path) - { + if (null !== $digitalObject->path) { $iiifBaseUrl = sfConfig::get('app_iiif_base_url'); - - if (!empty($iiifBaseUrl)) - { + + if (!empty($iiifBaseUrl)) { $identifier = $this->getIIIFIdentifier($digitalObject); - - $images[] = array( - 'url' => rtrim($iiifBaseUrl, '/') . '/' . $identifier . '/info.json', - 'label' => $digitalObject->name, - 'identifier' => $digitalObject->id, - 'path' => $digitalObject->path - ); + + $images[] = [ + 'url' => rtrim($iiifBaseUrl, '/').'/'.$identifier.'/info.json', + 'label' => $digitalObject->name, + 'identifier' => $digitalObject->id, + 'path' => $digitalObject->path, + ]; } } @@ -124,18 +116,19 @@ protected function getDigitalObjectIIIFImages($digitalObject) } /** - * Get IIIF images from an information object + * Get IIIF images from an information object. + * + * @param mixed $informationObject */ protected function getInformationObjectIIIFImages($informationObject) { - $images = array(); + $images = []; - $criteria = new Criteria; + $criteria = new Criteria(); $criteria->add(QubitDigitalObject::OBJECT_ID, $informationObject->id); $criteria->addAscendingOrderByColumn(QubitDigitalObject::SEQUENCE); - foreach (QubitDigitalObject::get($criteria) as $digitalObject) - { + foreach (QubitDigitalObject::get($criteria) as $digitalObject) { $digitalObjectImages = $this->getDigitalObjectIIIFImages($digitalObject); $images = array_merge($images, $digitalObjectImages); } @@ -144,23 +137,23 @@ protected function getInformationObjectIIIFImages($informationObject) } /** - * Generate IIIF identifier from digital object + * Generate IIIF identifier from digital object. + * + * @param mixed $digitalObject */ protected function getIIIFIdentifier($digitalObject) { - if (null !== $digitalObject->checksum) - { + if (null !== $digitalObject->checksum) { return $digitalObject->checksum; } - + $filename = pathinfo($digitalObject->path, PATHINFO_FILENAME); - $identifier = preg_replace('/[^a-zA-Z0-9_-]/', '_', $filename); - - return $identifier; + + return preg_replace('/[^a-zA-Z0-9_-]/', '_', $filename); } /** - * Add required CSS and JavaScript assets + * Add required CSS and JavaScript assets. */ protected function addAssets() { diff --git a/plugins/arIiifPlugin/lib/arIiifPluginComponents.class.php.backup b/plugins/arIiifPlugin/lib/arIiifPluginComponents.class.php.backup deleted file mode 100644 index 882a544962..0000000000 --- a/plugins/arIiifPlugin/lib/arIiifPluginComponents.class.php.backup +++ /dev/null @@ -1,209 +0,0 @@ -resource)) - { - return sfView::NONE; - } - - // Initialize images array - $this->images = array(); - - // Check if this is a digital object with IIIF support - if ($this->resource instanceof QubitDigitalObject) - { - $this->images = $this->getDigitalObjectIIIFImages($this->resource); - } - // Check if this is an information object with multiple digital objects - else if ($this->resource instanceof QubitInformationObject) - { - $this->images = $this->getInformationObjectIIIFImages($this->resource); - } - - // If no images found, don't display component - if (empty($this->images)) - { - return sfView::NONE; - } - - // Load configuration - $config = sfConfig::get('app_iiif_carousel', array()); - - // Set options with defaults from configuration - $this->autoRotate = isset($this->autoRotate) ? $this->autoRotate : $config['auto_rotate']; - $this->rotateInterval = isset($this->rotateInterval) ? $this->rotateInterval : $config['rotate_interval']; - $this->showNavigation = isset($this->showNavigation) ? $this->showNavigation : $config['show_navigation']; - $this->showThumbnails = isset($this->showThumbnails) ? $this->showThumbnails : $config['show_thumbnails']; - $this->viewerHeight = isset($this->viewerHeight) ? $this->viewerHeight : $config['viewer_height']; - - // Generate unique ID for this carousel instance - $this->carouselId = 'iiif-carousel-' . uniqid(); - - // Add required assets to response - $this->addAssets(); - } - - /** - * Display simple IIIF viewer (non-carousel, single image) - * - * @param sfRequest $request A request object - */ - public function executeViewer($request) - { - // Get the digital object - if (!isset($this->resource) || !$this->resource instanceof QubitDigitalObject) - { - return sfView::NONE; - } - - // Get IIIF URL - $images = $this->getDigitalObjectIIIFImages($this->resource); - - if (empty($images)) - { - return sfView::NONE; - } - - $this->iiifUrl = $images[0]['url']; - $this->imageLabel = isset($images[0]['label']) ? $images[0]['label'] : ''; - - // Load configuration - $config = sfConfig::get('app_iiif_carousel', array()); - - // Set viewer height - $this->viewerHeight = isset($this->viewerHeight) ? $this->viewerHeight : $config['viewer_height']; - - // Generate unique ID - $this->viewerId = 'iiif-viewer-' . uniqid(); - - // Add assets - $this->addAssets(); - } - - /** - * Get IIIF images from a digital object - * - * @param QubitDigitalObject $digitalObject - * @return array - */ - protected function getDigitalObjectIIIFImages($digitalObject) - { - $images = array(); - - // Check if digital object has IIIF manifest URL in properties - foreach ($digitalObject->getProperties(null, 'iiifManifestUrl') as $property) - { - $images[] = array( - 'url' => $property->value, - 'label' => $digitalObject->name, - 'identifier' => $digitalObject->id - ); - - // Return first match - return $images; - } - - // Check master file path and construct IIIF URL - if (null !== $digitalObject->path) - { - // Get IIIF base URL from configuration - $iiifBaseUrl = sfConfig::get('app_iiif_base_url'); - - if (!empty($iiifBaseUrl)) - { - // Construct IIIF URL from file identifier - $identifier = $this->getIIIFIdentifier($digitalObject); - - $images[] = array( - 'url' => rtrim($iiifBaseUrl, '/') . '/' . $identifier . '/info.json', - 'label' => $digitalObject->name, - 'identifier' => $digitalObject->id, - 'path' => $digitalObject->path - ); - } - } - - return $images; - } - - /** - * Get IIIF images from an information object (multiple digital objects) - * - * @param QubitInformationObject $informationObject - * @return array - */ - protected function getInformationObjectIIIFImages($informationObject) - { - $images = array(); - - // Get all digital objects for this information object - $criteria = new Criteria; - $criteria->add(QubitDigitalObject::OBJECT_ID, $informationObject->id); - $criteria->addAscendingOrderByColumn(QubitDigitalObject::SEQUENCE); - - foreach (QubitDigitalObject::get($criteria) as $digitalObject) - { - $digitalObjectImages = $this->getDigitalObjectIIIFImages($digitalObject); - $images = array_merge($images, $digitalObjectImages); - } - - return $images; - } - - /** - * Generate IIIF identifier from digital object - * - * @param QubitDigitalObject $digitalObject - * @return string - */ - protected function getIIIFIdentifier($digitalObject) - { - // Use the digital object's checksum if available - if (null !== $digitalObject->checksum) - { - return $digitalObject->checksum; - } - - // Or use the filename without extension - $filename = pathinfo($digitalObject->path, PATHINFO_FILENAME); - - // Clean filename for URL - $identifier = preg_replace('/[^a-zA-Z0-9_-]/', '_', $filename); - - return $identifier; - } - - /** - * Add required CSS and JavaScript assets - */ - protected function addAssets() - { - $response = $this->getResponse(); - - // Add OpenSeadragon library - $response->addJavaScript('/plugins/arIiifPlugin/vendor/openseadragon/openseadragon.min.js', 'last'); - - // Add IIIF carousel JavaScript - $response->addJavaScript('/plugins/arIiifPlugin/js/iiif-carousel.js', 'last'); - - // Add IIIF carousel CSS - $response->addStylesheet('/plugins/arIiifPlugin/css/iiif-carousel.css', 'last'); - } -} diff --git a/plugins/arIiifPlugin/modules/arIiifPlugin/actions/components.class.php b/plugins/arIiifPlugin/modules/arIiifPlugin/actions/components.class.php index a7a942de1d..f2e69e269c 100644 --- a/plugins/arIiifPlugin/modules/arIiifPlugin/actions/components.class.php +++ b/plugins/arIiifPlugin/modules/arIiifPlugin/actions/components.class.php @@ -1,47 +1,40 @@ resource)) - { + if (!isset($this->resource)) { return sfView::NONE; } - $this->images = array(); - - if ($this->resource instanceof QubitDigitalObject) - { + $this->images = []; + + if ($this->resource instanceof QubitDigitalObject) { $this->images = $this->getDigitalObjectIIIFImages($this->resource); - } - else if ($this->resource instanceof QubitInformationObject) - { + } elseif ($this->resource instanceof QubitInformationObject) { $this->images = $this->getInformationObjectIIIFImages($this->resource); } - if (empty($this->images)) - { + if (empty($this->images)) { return sfView::NONE; } - $config = sfConfig::get('app_iiif_carousel', array( - 'auto_rotate' => true, - 'rotate_interval' => 5000, - 'show_navigation' => true, - 'show_thumbnails' => false, - 'viewer_height' => 600 - )); + $config = sfConfig::get('app_iiif_carousel', [ + 'auto_rotate' => true, + 'rotate_interval' => 5000, + 'show_navigation' => true, + 'show_thumbnails' => false, + 'viewer_height' => 600, + ]); $this->autoRotate = isset($this->autoRotate) ? $this->autoRotate : $config['auto_rotate']; $this->rotateInterval = isset($this->rotateInterval) ? $this->rotateInterval : $config['rotate_interval']; @@ -49,74 +42,73 @@ public function executeCarousel($request) $this->showThumbnails = isset($this->showThumbnails) ? $this->showThumbnails : $config['show_thumbnails']; $this->viewerHeight = isset($this->viewerHeight) ? $this->viewerHeight : $config['viewer_height']; - $this->carouselId = 'iiif-carousel-' . uniqid(); + $this->carouselId = 'iiif-carousel-'.uniqid(); $this->addAssets(); } /** - * Display simple IIIF viewer + * Display simple IIIF viewer. + * + * @param mixed $request */ public function executeViewer($request) { - if (!isset($this->resource) || !$this->resource instanceof QubitDigitalObject) - { + if (!isset($this->resource) || !$this->resource instanceof QubitDigitalObject) { return sfView::NONE; } $images = $this->getDigitalObjectIIIFImages($this->resource); - - if (empty($images)) - { + + if (empty($images)) { return sfView::NONE; } $this->iiifUrl = $images[0]['url']; $this->imageLabel = isset($images[0]['label']) ? $images[0]['label'] : ''; - $config = sfConfig::get('app_iiif_carousel', array('viewer_height' => 600)); + $config = sfConfig::get('app_iiif_carousel', ['viewer_height' => 600]); $this->viewerHeight = isset($this->viewerHeight) ? $this->viewerHeight : $config['viewer_height']; - $this->viewerId = 'iiif-viewer-' . uniqid(); + $this->viewerId = 'iiif-viewer-'.uniqid(); $this->addAssets(); } /** - * Get IIIF images from a digital object + * Get IIIF images from a digital object. + * + * @param mixed $digitalObject */ protected function getDigitalObjectIIIFImages($digitalObject) { - $images = array(); + $images = []; // Check for IIIF manifest URL property using Criteria - $criteria = new Criteria; + $criteria = new Criteria(); $criteria->add(QubitProperty::OBJECT_ID, $digitalObject->id); $criteria->add(QubitProperty::NAME, 'iiifManifestUrl'); - - foreach (QubitProperty::get($criteria) as $property) - { - $images[] = array( - 'url' => $property->value, - 'label' => $digitalObject->name, - 'identifier' => $digitalObject->id - ); - + + foreach (QubitProperty::get($criteria) as $property) { + $images[] = [ + 'url' => $property->value, + 'label' => $digitalObject->name, + 'identifier' => $digitalObject->id, + ]; + return $images; } // Construct IIIF URL from file path - if (null !== $digitalObject->path) - { + if (null !== $digitalObject->path) { $iiifBaseUrl = sfConfig::get('app_iiif_base_url'); - - if (!empty($iiifBaseUrl)) - { + + if (!empty($iiifBaseUrl)) { $identifier = $this->getIIIFIdentifier($digitalObject); - - $images[] = array( - 'url' => rtrim($iiifBaseUrl, '/') . '/' . $identifier . '/info.json', - 'label' => $digitalObject->name, - 'identifier' => $digitalObject->id, - 'path' => $digitalObject->path - ); + + $images[] = [ + 'url' => rtrim($iiifBaseUrl, '/').'/'.$identifier.'/info.json', + 'label' => $digitalObject->name, + 'identifier' => $digitalObject->id, + 'path' => $digitalObject->path, + ]; } } @@ -124,18 +116,19 @@ protected function getDigitalObjectIIIFImages($digitalObject) } /** - * Get IIIF images from an information object + * Get IIIF images from an information object. + * + * @param mixed $informationObject */ protected function getInformationObjectIIIFImages($informationObject) { - $images = array(); + $images = []; - $criteria = new Criteria; + $criteria = new Criteria(); $criteria->add(QubitDigitalObject::OBJECT_ID, $informationObject->id); $criteria->addAscendingOrderByColumn(QubitDigitalObject::SEQUENCE); - foreach (QubitDigitalObject::get($criteria) as $digitalObject) - { + foreach (QubitDigitalObject::get($criteria) as $digitalObject) { $digitalObjectImages = $this->getDigitalObjectIIIFImages($digitalObject); $images = array_merge($images, $digitalObjectImages); } @@ -144,23 +137,23 @@ protected function getInformationObjectIIIFImages($informationObject) } /** - * Generate IIIF identifier from digital object + * Generate IIIF identifier from digital object. + * + * @param mixed $digitalObject */ protected function getIIIFIdentifier($digitalObject) { - if (null !== $digitalObject->checksum) - { + if (null !== $digitalObject->checksum) { return $digitalObject->checksum; } - + $filename = pathinfo($digitalObject->path, PATHINFO_FILENAME); - $identifier = preg_replace('/[^a-zA-Z0-9_-]/', '_', $filename); - - return $identifier; + + return preg_replace('/[^a-zA-Z0-9_-]/', '_', $filename); } /** - * Add required CSS and JavaScript assets + * Add required CSS and JavaScript assets. */ protected function addAssets() { diff --git a/plugins/arIiifPlugin/modules/arIiifPlugin/templates/_carousel.php b/plugins/arIiifPlugin/modules/arIiifPlugin/templates/_carousel.php index cfd2000fb8..1c015f4659 100644 --- a/plugins/arIiifPlugin/modules/arIiifPlugin/templates/_carousel.php +++ b/plugins/arIiifPlugin/modules/arIiifPlugin/templates/_carousel.php @@ -1,7 +1,7 @@ - -