🦁

IIIFイメージサーバの一つであるCantaloupeをEC2で起動する

2023/09/19に公開

概要

IIIFイメージサーバの一つであるCantaloupeをEC2で起動する方法の備忘録です。

https://cantaloupe-project.github.io/

加えて、画像のダウンロードサイズに制限を加えるDelegate Methodsの一例についても紹介します。具体的には、フルサイズの画像を/full/full/で取得しようとした際、エラーが出てしまうケースへの対応を行います。

https://cantaloupe-project.github.io/manual/5.0/access-control.html

Cantaloupeのセットアップ

EC2インスタンスの作成

プラットフォームをUbuntu、インスタンスタイプをt2.medium、ストレージを8GB、に設定したEC2インスタンスを作成しました。

結果、以下の「パブリック IPv4 アドレス」を持つEC2インスタンスが作成されました。

54.172.71.20

ssh

起動したEC2インスタンスにsshで接続します。接続後、以下のコマンドにより、rootユーザのパスワードを設定します。

sudo su
passwd

javaのインストール

以下のコマンドなどにより、javaをインストールします。

apt-get update
apt install default-jre

cantaloupeのダウンロード

以下のコマンドなどにより、cantaloupeをダウンロードします。

apt install unzip
wget https://github.com/cantaloupe-project/cantaloupe/releases/download/v5.0.5/cantaloupe-5.0.5.zip
unzip cantaloupe-5.0.5.zip

設定

以下のコマンドなどにより、設定ファイル「cantaloupe.properties」を編集します。

cd cantaloupe-5.0.5
# 設定例ファイルから設定ファイルをコピー
cp cantaloupe.properties.sample cantaloupe.properties

vi cantaloupe.propertiesなどのコマンドにより、画像を格納するフォルダを指定します。

cantaloupe.properties
FilesystemSource.BasicLookupStrategy.path_prefix = /home/ubuntu/images/

cantaloupeの起動

java -Dcantaloupe.config=cantaloupe.properties -Xmx2g -jar cantaloupe-5.0.5.jar

以下のようなURLでcantaloupeが起動します。

http://54.172.71.20:8182/

画像の配置

サーバ上での作業

ubuntuユーザで/home/ubuntu/imagesに画像を格納するフォルダを作成します。

su ubuntu
mkdir /home/ubuntu/images

ローカルでの作業

以下のノートブックなどを使って、pyramid tiled tifをローカルにダウンロードします。

https://zenn.dev/nakamura196/articles/ef6b0937e4e887

そして、converted.tifをダウンロードした場合、以下のようなコマンドを使って、サーバに画像をアップロードします。

scp -i <秘密鍵へのパス> /Users/xxx/Downloads/converted.tif ubuntu@54.172.71.20:./images/

画像がサーバにアップロードされると、以下のようなURLでinfo.jsonを取得できます。

http://54.172.71.20:8182/iiif/3/converted.tif/info.json

http://54.172.71.20:8182/iiif/3/converted.tifのようなURLでもリダイレクトされました。

さらに、以下のように、/3/を/2/にすると、Image API v.2のinfo.jsonを取得できます。

http://54.172.71.20:8182/iiif/2/converted.tif

小まとめ

これまでの設定で最低限のCantaloupeの起動は完了です。別途、https対応など行う必要がありますが、その方法は他の記事などで紹介できればと思います。

サイズが大きい画像への対応: max_pixelsを有効にする場合

例えば、『百鬼夜行図』(東京大学総合図書館所蔵)を対象とした場合、以下のURLからサイズが「79508 × 3082」であることがわかります。

https://iiif.dl.itc.u-tokyo.ac.jp/iiif/2/hyakki%2Fimages%2Fhyakki.tif/info.json

このPyramid Tiled Tiffは以下のGitHubリポジトリからダウンロードいただけます。

https://github.com/nakamura196/ptif_sample/blob/main/hyakki.tif

このファイルをそのままアップロードした場合、フルサイズの画像を取得しようとすると、以下のエラーが発生します。

http://54.172.71.20:8182/iiif/2/hyakki.tif/full/full/0/default.jpg

edu.illinois.library.cantaloupe.operation.IllegalSizeException: The requested pixel area exceeds the maximum threshold (max_pixels) set in the configuration.
	at edu.illinois.library.cantaloupe.operation.OperationList.validate(OperationList.java:826)
	at edu.illinois.library.cantaloupe.processor.Processor.validate(Processor.java:201)
	at edu.illinois.library.cantaloupe.resource.ImageRequestHandler.handle(ImageRequestHandler.java:399)
	at edu.illinois.library.cantaloupe.resource.iiif.v2.ImageResource.doGET(ImageResource.java:128)
	at edu.illinois.library.cantaloupe.resource.HandlerServlet.handle(HandlerServlet.java:97)
	at edu.illinois.library.cantaloupe.resource.HandlerServlet.doGet(HandlerServlet.java:35)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:791)

これは、cantaloupe.propertiesmax_pixels10,000,000が設定されており、79,508 × 3,082 = 245,043,656max_pixelsを超えてしまうためです。

cantaloupe.properties
# Maximum number of pixels to return in a response, to prevent overloading
# the server. Requests for more pixels than this will receive an error
# response. Set to 0 for no maximum.
max_pixels = 10000000

このmax_pixels0にすることで、上限値を解除することができますが、その方法は後述します。

max_pixelsを指定することで、サーバへの負荷を軽減できる利点がありますが、Universal Viewerなどでフルサイズの画像をダウンロードしようとした際、利用者にエラーが返却されてしまう点が課題です。

そのため、Cantaloupeで用意されているDelegate Methodsを使って、max_pixelsの閾値を超える場合の対処方法を検討してみます。

Delegate Methodsの有効化

cantaloupe.propertiesdelegate_script.enabledをtrueにします。さらに、delegate_script.pathnameを指定します。ここでは、ubuntuユーザのホームディレクトリを想定します。

cantaloupe.properties
# Enables the delegate script: a Ruby script containing various delegate
# methods. (See the user manual.)
delegate_script.enabled = true

# !! This can be an absolute path, or a filename; if only a filename is
# specified, it will be searched for in the same folder as this file, and
# then the current working directory.
delegate_script.pathname = /home/ubuntu/delegates.rb

さらに、サンプルのスクリプトをubuntuユーザでコピーしておきます。

cp /home/ubuntu/cantaloupe-5.0.5/delegates.rb.sample /home/ubuntu/delegates.rb

スクリプトの更新

delegates.rbスクリプト内のauthorizeメソッドを以下のように更新します。

/home/ubuntu/delegates.rb
def authorize(options = {})
    max_pixels = 10000000
    request_uri = context['request_uri']
    full_size = context['full_size']

    if request_uri && request_uri.include?('/full/full/') && full_size
      width, height = full_size['width'], full_size['height']
      total_pixels = width * height

      if total_pixels > max_pixels
        {
          'status_code' => 301,
          'location' => "#{request_uri.split('/full/full/').first}/full/max/0/default.jpg"
        }
      else
        true
      end
    else
      true
    end
  end

上記により、/full/full/をURLに含む形でリクエストされ、それがmax_pixelsの値を超える場合、/full/max/を含むURLにリダイレクトさせます。これにより、エラーは返却されず、max_pixelsで指定されたサイズで画像がダウンロードされます。

サイズが大きい画像への対応: max_pixelsを無効にする場合

上記の方法とは別に、max_pixelsを無効にする方法も考えられます。具体的には、以下のようにmax_pixelsを指定します。

cantaloupe.properties
# Maximum number of pixels to return in a response, to prevent overloading
# the server. Requests for more pixels than this will receive an error
# response. Set to 0 for no maximum.
max_pixels = 0

上記の設定により、サーバのスペック次第ですが、max_pixelsを気にせずに利用することができます。

なお、本記事で使用しているt2.mediumインスタンスでは、java.lang.OutOfMemoryError: Java heap spaceのエラーにより、横幅などを大きな値で指定した場合、ダウンロードできませんでした。

一方、スペックが高いサーバの場合、上記のヒープメモリを気にする必要はありませんが、上述の「百鬼夜行図」をフルサイズ(/full/full/を含むURL)でダウンロードしようとすると、以下のようにダウンロードできませんでした。

これは、jpgの最大サイズに引っかかってしまうのが原因のようでした。

上記への対応として、delegates.rbスクリプト内のauthorizeメソッドを以下のように変更することで、指定した横幅または縦幅を最大値として画像をダウンロードできるようになりました。

/home/ubuntu/delegates.rb
def authorize(options = {})
    max_pixels = 65500
    request_uri = context['request_uri']
    full_size = context['full_size']
    if request_uri && request_uri.include?('/full/full/') && full_size
      width, height = full_size['width'], full_size['height']
      if width > max_pixels || height > max_pixels
        scale_factor = [max_pixels / width.to_f, max_pixels / height.to_f].min
        new_width = (width * scale_factor).round
        new_height = (height * scale_factor).round
        {
          'status_code' => 301,
          'location' => "#{request_uri.split('/full/full/').first}/full/#{new_width},#{new_height}/0/default.jpg"
        }
      else
        true
      end
    else
      true
    end
  end

ただし、上記の設定の場合、info.jsonmaxAreamaxWidthなどが記述されないため、/full/full/を含むURLでアクセスしたにもかかわらず、info.jsonで明記されているwidthheightよりも小さいサイズの画像がダウンロードされてしまうため、適切な方法ではないと考えられます。

縦幅と横幅の乗算の結果であるmax_pixelsを指定しなくて良い点が利点ですが、IIIFの規格に適合しているかを検討する必要がありそうです。

https://iiif.io/api/image/3.0/

まとめ

本記事では、Cantaloupeのセットアップ方法を紹介しました。

また例外的な対応方法として、サイズが大きい画像のダウンロードに際して、Delegate Methodsを使用する方法を紹介しました。Delegate Methodsを活用することにより、認証済みのユーザにのみ大きな画像をダウンロードさせる、といったことを実現できるようです。

今回は変則的な利用方法を紹介しましたが、今後Delegate Methodsの使用例についても調査できればと思います。

本記事がCantaloupeを用いたIIIFイメージサーバの構築に立てば幸いです。

また誤った理解や記述が含まれる可能性が高いため、修正コメントなどをいただけますと幸いです。

Discussion