簡単なIIIFビューワを作ってみよう(1): IIIF Presentation APIの理解に向けて

IIIF Presentation APIについて、当ブログではこれまであまり言及してきませんでした。その理由は大きく二つあって、一つは、JSONを読める人なら必要があったときに見ればすぐにわかるのではないか、ということと、一方で、コンテンツの専門家のレベルでは、IIIF Presentation APIはほとんど何も決めていないに等しいので特に語るべきことはなく、さらに、ユーザレベルでは触る必要がないもので、むしろ機械か専門家にまかせていただいた方がいいところだろうかと思ってしまい、結局のところ簡単に触れるのみとしてきました。

 しかしながら、解説がほしいという各方面からのご要望や、先日開催されたIIIF Presentation APIを読む会などに参加させていただいたこともあり、何かそろそろやってみた方がいいのではないかと思いまして、色々考えていたところ、ようやく一つひらめきました。

 ・・・というのが、「簡単なIIIFビューワを作ってみよう」という企画です。これならば、IIIF Presentation APIの解説の難しさを乗り越えられるのではないかと思ったのでした。とにかく、この件は、JSONの便利さ(と限界)を知っていないとよくわからないのですが、これを理解してもらう上で、「IIIFビューワを作ってみる」、つまり、IIIF ManifestのJSONデータを適当に取り出して処理してみるというのがとてもよいのではないかと思うのです。

 ただし、こういうことを始めると、「もっとよい方法があるのに」と思われる人がきっとおられると思います。(私はプログラマとしてはかなりヘボい方ですので。)そこで、どちらかといいますと、そういう方は、それはそれでよりよいチュートリアルを作って無料公開していただければ、こちらからはリンクを張るだけで済むようになりますので、ぜひともお願いしたいところです。

 

 というわけで、さっそく・・・といきたいところですが、ここでいきなり解説です。IIIFビューワ、画像が拡大縮小できたりして、しかも大きな画像は自動的にタイル化して一部だけサーバからとってくるとか、すごい機能なのに、それを自分で作れるの!?と思う人もおられると思います。そうではありません。そこは、IIIF Image APIの領分です。Image APIについては今回は扱いませんので、それを処理してくれる画像表示ソフトをベースに話を進めていきます。画像表示ソフトには、LeafletやOpenSeadragonなど、元々IIIF対応ではなかったものを IIIF Image API向けに改造したものがいくつか流通しています。特に後者はIIIFに標準対応するようになりました。Leafletの方が良いというプログラマの方々も結構おられるのですが、私のようなヘボプログラマにはOpenSeadragonの方がやりやすい面がありまして、ここではとりあえずOpenSeadragonを使ってみます。

 さて、画像表示をまかせてしまうということは、あとは何をする必要があるのでしょうか?そう、それがIIIF Presentation APIの素晴らしさであり、また、IIIFの本領を発揮するところでもあるのです。

 一つの資料には、画像がいくつか含まれていることがしばしばあります。また、資料に関する情報はどこかにうまくくっつけておかないと、その資料が何だったかわからなくなってしまうことがあります。画像にアノテーションをつけておきたいと思うこともありますが、それも画像との関係づけが切れてしまうと、何がなんだかわからなくなってしまいます。(ほぼ、ゴミデータになります)。これをなんとかしなければデジタルデータの未来はない、そのためには皆で共通のルールを・・・というのが IIIFであり、それを実現しているのがIIIF Presentation APIなのです。つまり、そういった情報をすべてまとめて一つのファイルに書き込んでしまおうという話であり、書き込んだものを皆でうまく共有できるように、ごくシンプルなルールを IIIF Presentation APIとして設定して皆で共有することになったのでした。

 

 ここまでくると、今回のIIIFビューワでどういう範囲を作ろうとしているのか、大体おわかりいただけたかと思います。つまり、IIIF Presentation APIが仕切っている「資料に含まれる画像や資料に関する諸々の情報等」を基に一つの資料を閲覧できる仕組みを作ってみよう、ということなのです。ただし、ごく簡単なものを。

 

 ということで、まずは画像処理をおまかせするためのOpenSeadragonです。これは元々マイクロソフトが作っていたものがオープンソース化されたもので、安定度はかなり高いと言わざるを得ません。公式ページの右上のアイコンからダウンロードできますので、とりあえずダウンロードして展開してみましょう。(展開しないでダブルクリックしないように!)

f:id:digitalnagasaki:20190502234752p:plain  

それから、同じフォルダ(ディレクトリ)に、jqueryもダウンロードしておきましょう。これも、バリバリのプログラマの方々からは「今時そんなもの使ってどうするの」とよく言われるもので、私のようなヘボプログラマ御用達のものなのですが、とりあえずお試しということでご容赦ください。もっと良いモノを使える人は適当に読み替えてください。 以下の"Download jQuery"というボタンをクリックしてから、

f:id:digitalnagasaki:20190502235456p:plain

表示されたページの Download the compressed, production jQuery 3.4.1 というリンクをクリックすればダウンロードできます。

f:id:digitalnagasaki:20190502235649p:plain  

さて、そうすると、おそらく、フォルダ(ディレクトリ)は以下のようになっているはずです。

(Windows10の場合)

f:id:digitalnagasaki:20190502235911p:plain

 

(Ubuntu on WSL でのコマンドライン表示)

$ ls -l 合計 836 -rwxrwxrwx 1 nagasaki nagasaki 88145 5月 2 06:14 jquery-3.4.1.min.js drwxrwxrwx 1 nagasaki nagasaki 512 5月 2 23:57 openseadragon-bin-2.4.0 -rwxrwxrwx 1 nagasaki nagasaki 797571 7月 21 2018 openseadragon-bin-2.4.0.zip

 

このように、ファイル jquery-3.4.1.min.js と、openseadragon-bin-2.4.0.zipを展開した

フォルダ(ディレクトリ)openseadragon-bin-2.4.0 が同じ階層に来るようにしてください。フォルダ(ディレクトリ)をあわせておくのはこの種の仕事ではとても大事ですのでよく注意してください。(うまくいかない場合はまずこのあたりから疑って確認してみることです)

はじめの一歩:タイトルと帰属の取り出し

さて、そうしましたら、このフォルダに、test.htmlというファイルを作ってみましょう。その内容は、とりあえず以下のようにしてみましょう。ファイルは、Windowsの「メモ帳」でも作成できますが、その場合、保存する際の「文字コード」を必ず「UTF-8」にしてください。

そこで、まずは、jqueryを使って、IIIF Manifestファイルを読み出して、そこからタイトルと帰属の情報を取り出して表示するという、ごく簡単なものを書いてみましょう。

<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8'>
    <title>私の簡易IIIFビューワ</title>
    <script src="jquery-3.4.1.min.js"></script>  
  </head>
  <body>
    ManifestURI: <input type="text" size="40" id="linkManiURI" value="">&nbsp;<button id="maniLoad">Load</button><br/>
    タイトル: <div id="linkLabel"></div>
    帰属: <div id="linkAttr"></div>
    
    <script>
  $(function(){
   $("#maniLoad").click(function(){
     var pUrl = $("#linkManiURI").val();
     $.ajax({
       url:pUrl,
       dataType:'json'}).done(function(maniJson){
         $("#linkAttr").text(maniJson["attribution"]);
         $("#linkLabel").text(maniJson["label"]); 
     });
   });
  });
    </script>
  </body>
</html>

この状態で、たとえば以下のManifest URIを読み込ませてみると、

https://gallica.bnf.fr/iiif/ark:/12148/btv1b10526547d/manifest.json

タイトル:

BnF, département Estampes et photographie, BOITE FOL-DE-10

帰属:

Bibliothèque nationale de France

という風に表示されるはずです。他にもManifest URIを色々読み込ませてみると、それぞれのタイトルと帰属を表示してくれるはずです。 (このプログラムでは、プログラム自体をわかりやすくするために、新たに読み込んだManifest URIにタイトルか帰属がなかった場合、前回のものがそのまま残りますのでご注意ください。)

 なお、動作するものをこちらに置いておきますのでご参考にしてみてください。

 ところで、ここで特に注目していただきたいのは以下の箇所です。

   $("#maniLoad").click(function(){
      // (1)  id: maniLoadのエレメントがクリックされたら以下の処理をする
      const pUrl = $("#linkManiURI").val();
         // (2) id: linkManiURI に記入された文字列(値, この場合はManifest URI)を変数 PUrlに代入する
      $.ajax({
        url:pUrl,
        dataType:'json'}).done(function(maniJson){
           // (3) pUrl (=Manifest URI)にアクセスしてjsonデータとして取得し変数maniJsonに代入してから以下の処理をする
          $("#linkAttr").text(maniJson["attribution"]);
           // (4) 取得したjsonデータ中のトップレベルでattributionというキーの値(テキスト)をid: linkAttr に表示
          $("#linkLabel").text(maniJson["label"]); 
          // (5) 取得したjsonデータ中のトップレベルでlabelというキーの値(テキスト)をid: linkLabel に表示
      });
    });

(3)以降に特に注目です。たとえばこちらのIIIF Manifestファイルに直接アクセスしてみると、トップレベルのlabelとattributionはそれぞれ以下のようになっています。

  "label" : "BnF, département Estampes et photographie, BOITE FOL-DE-10",
  "attribution" : "Bibliothèque nationale de France",

このように、キーと値が対になっているのがJSONデータの特徴なのですが、ここで、labelとattributionが、それぞれ資料のタイトルと、資料の帰属を表すものとして、JSONデータの階層構造のトップレベルに書いておくようにと決めているのがIIIF Presentation API、ということになります。

ようやくタイトルと帰属を取り出すことができました。次に画像を取り出したくなりますが、IIIF Presentation APIが定めるJSONデータの形式にて、資料に属する個々の画像がどの階層にどのように属しているか、もう少しみてみましょう。

枚数が少ないと比較的わかりやすいので、引き続き、こちらのIIIF Manifestファイルを見ていきましょう。

"sequences" : [ {
    "canvases" : [ {
      "@id" : "https://gallica.bnf.fr/iiif/ark:/12148/btv1b10526547d/canvas/f1",

このように、トップレベルに「sequences」というキーがあります。これが複数であることにも注目してください。これは資料に含まれる個々のコンテンツの順番を定義していますが、複数形になっていることからもわかるように、複数の順番を記述できることになっています。「"sequences" : 」に続いて「 [ { 」という風になっていることにも着目してください。JSON形式では、値のところに「 [ 」が来た場合、この中にキー/値の対のセットを複数含むことができるようになります。いわば、一つ下の階層を作ることができるようになると言えます。そこで、次に来ているキーは再び複数形です。「canvases」というのは、IIIF Presentation APIの考え方の根幹を成す「canvas」を指しており、それをここで複数含むことができることを示唆しています。  IIIFにおける canvasは、たとえば本における抽象的なページの概念と考えることができます。あるページに関するデジタルデータとしては、デジタル撮影した画像や、テキストデータ、誰かが後からつけたコメントなど、様々なデータがあり得ます。それらのすべては、一つのページとして取りまとめられ、そして、そのようにしてまとめられたページを一つもしくは複数の順番で並べることによって一つの資料が構成される、というのが、IIIFの基本的な考え方です。そして、そのページのことを、本以外のものも扱うことができる抽象概念として「canvas」と呼んでいます。(少なくともversion 2まではそうです)。

 そうすると、canvasが複数含まれることがIIIFにおいて自然であることはおわかりいただけたかと思います。では、このcanvasに画像が載っているはずだ、ということになります。もう少し見ていきましょう。

 今回はviewerを作ることが目的ですので、少し端折ります。以下の箇所に注目してみましょう。

      "images" : [ {
        "motivation" : "sc:painting",
        "on" : "https://gallica.bnf.fr/iiif/ark:/12148/btv1b10526547d/canvas/f1",
        "resource" : {
          "format" : "image/jpeg",
          "service" : {
            "profile" : "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level2",
            "@context" : "http://iiif.io/api/image/1/context.json",
            "@id" : "https://gallica.bnf.fr/iiif/ark:/12148/btv1b10526547d/f1"
          },
          "height" : 4246,
          "width" : 6197,
          "@id" : "https://gallica.bnf.fr/iiif/ark:/12148/btv1b10526547d/f1/full/full/0/native.jpg",
          "@type" : "dctypes:Image"
        },
        "@type" : "oa:Annotation"
      } ]

さらにちょっと階層ができていますが、やはり「images」も複数になっています。これは一つのcanvasに複数の画像が載ることを許容しているためです。色々な使い方がありますが、たとえば、部分的に切り取られた画像同士をviewer上で組み合わせるといったことにも使われます。

さらに少し飛ばしてみていくと、「resource」の下に「service」というのがあります。ここに、IIIF Image APIが提供する画像情報を記述してあるようです。もう一度その箇所だけを見てみると以下のようになっています。

          "service" : {
            "profile" : "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level2",
            "@context" : "http://iiif.io/api/image/1/context.json",
            "@id" : "https://gallica.bnf.fr/iiif/ark:/12148/btv1b10526547d/f1"
          },

ここで、簡単なIIIF viewerを作るために特に重要になるのは、「@id」 のところです。これはIIIF Image APIでの画像のベースになるURIを示しており、この後に続けて「/info.json」をつけると、その画像にIIIF Image APIでアクセスするために必要な情報が返戻されるようになっています。たとえば以下のような感じです。

{
    "profile": "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level2",
    "width": 6197,
    "height": 4246,
    "@context": "http://library.stanford.edu/iiif/image-api/1.1/context.json",
    "@id": "https://gallica.bnf.fr/iiif/ark:/12148/btv1b10526547d/f1"
}

OpenSeadragonのような、Image API対応の画像表示ソフトに対しては、この info.jsonのURIを渡す必要があります。そこで、これを取り出してOpenSeadragonに読み込ませると、画像が表示できる、ということになります。が、そろそろ寝ないとまずいので、続きは次回ということでよろしくお願いいたします。