03/14
一歩進んだIIIFマニフェストの利用
神崎 正英
メタデータの記述
資料を利用しやすい形で提供するためには、表示ツールの画像処理用だけでなく、画像の内容を人間の利用者に伝える情報が不可欠です。最小限の情報は各リソースに付与するlabel
で得られますが、より詳しい説明文や利用のためのライセンスなどもぜひ知りたいところでしょう。
前回の資料オブジェクト全体に関する情報でも紹介したように、IIIFマニフェストでは、こうした記述、関連付けのためのプロパティをいくつか定義しています。この中で、汎用的なメタデータの記述に使えるmetadata
プロパティの記述方法を少し詳しく見ておきましょう。
metadata
は、仕様でプロパティとして定義されていない、表示のための情報項目を記述するものです。そのために情報の項目名を示すlabel
と項目内容のvalue
を対にし、一連の情報を配列として提示します。
例1
"metadata": [ { "label": "Author", "value": "歌川広重" }, { "label": "Published", "value": "嘉永年間" } ]...
著者を表すプロパティがあらかじめ定義されていれば、"Author": "歌川広重"
と書けるところです。しかしツールに表示を求める(画像処理情報ではない)メタデータ項目は限定的にする必要があるので、代わりに何にでも使えるmetadata
を用意しているわけです。
label
は文字列のみですが、value
はHTMLのマークアップを含めることができます(処理系はこの点に注意しなければなりません)。またmetadata
はマニフェスト全体だけでなく、個々のカンバスなど他のリソースにも与えることができます。
※JSON-LDの機能を利用すれば、metadata
を使わなくてもDublin Coreなどの語彙で必要なメタデータを記述できますが、IIIFのツールがそれを表示してくれるとは限りません。これはあくまで、ツールを通じて人間の利用者が理解できるようにするためのメタデータ記述なのです。
多言語対応
metadata
に限らず、人が読むための情報は利用者によって望ましい言語が異なります。項目名や内容を多言語で提供するために、IIIFマニフェストではJSON-LDの言語情報付き文字列表現(以下「タグ付き文字列」)を利用しています。これはプロパティ値を構造化して@language
で言語コードを示し、本来のプロパティ値を@value
とするものです。
例2
"metadata": [ { "label": [ {"@value": "Author", "@language": "en"}, {"@value": "作者", "@language": "ja"} ], "value": [ {"@value": "Utagawa Hiroshige", "@language": "en"}, {"@value": "歌川広重", "@language": "ja"} ] }, ... }...
value
と@value
の2種類があって混乱しそうですが、少なくともIIIFマニフェスト(2.1)においては、@value
はこのタグ付き文字列でしか用いられません。
タグ付き文字列は、ほかにlabel
、description
、attribution
にも利用できます。せっかくの資源を国際的にも活用できるようにするため、ぜひ採用を検討したいところです。
複数値と多言語
マニフェストのlabel
、description
なども含めた表示用メタデータ項目は、複数値を持っても構いません。たとえばattribution
として権利/帰属を記述する対象が複数というケースは十分考えられます。JSONでは同じプロパティを反復できないので、この場合は値を配列とします。
例3
"attribution": [ "デジタル画像は国立国会図書館デジタルライブラリより", "IIIFマニフェストは国デコImage Wall版にラベルや説明などを追加編集" ], ...
ここで、この複数プロパティ値をそれぞれ多言語で記述する必要が生じた場合はどうすればよいでしょうか。プロパティ値ごとの対応関係を保持するならば、入れ子の配列が必要です。
例4
"attribution": [ [ {"@value": "Digital images are part of National Diet...", "@language": "en"}, {"@value": "デジタル画像は国立国会図書館デジタルライブラリより", "@language": "ja"} ], [ {"@value": "The IIIF manifest was originally generated by....", "@language": "en"}, {"@value": "IIIFマニフェストは国デコImage Wall版にラベルや...", "@language": "ja"} ] ], ...
この記述はJSON-LDとしては構わないのですが、IIIFでは採用されていません(ほとんどのビューアでエラーになります)。複数値を多言語化する場合は、タグ付き文字列オブジェクトを単純に列挙します。
例5
"attribution": [ {"@value": "Digital images are part of National Diet...", "@language": "en"}, {"@value": "デジタル画像は国立国会図書館デジタルライブラリより", "@language": "ja"}, {"@value": "The IIIF manifest was originally generated by....", "@language": "en"}, {"@value": "IIIFマニフェストは国デコImage Wall版にラベルや...", "@language": "ja"} ], ...
タグ付き文字列と単純文字列を混在させることも可能です。IIIFでの処理手順は、この場合「タグ付き文字列に適切な言語が見当たらなければ単純文字列を表示する」と定めています。
複数値を多言語化しているときは、この混在には注意が必要です。混在させられたプロパティ値は、本来グループ化すべきものがまとめられておらず、言語情報による区別しかありません。そのため値によって多言語だったりそうでなかったりすると、(優先言語処理の関係で)タグ付き文字列か単純文字列かどちらか一方しか表示されなくなってしまうのです。
なお、metadata
プロパティの場合は項目名ごとにオブジェクトとして分かれているので、ある項目が多言語で別項目が単純文字列などと混在しても支障はありません。
レンジによる構造化
IIIFマニフェストには、画像などのカンバスを順番に列挙するシーケンス(Sequence)の他に、カンバスの論理的な順序やグループなどを構造化するレンジ(Range)が用意されています。シーケンスは全てのカンバスをフラットに並べた配列であるのに対し、レンジは階層構造をもたせたり、一部のカンバスだけを対象にして用いることが可能です。
レンジの役割とプロパティ
たとえば書物のデジタル画像の場合、その中の章や節といった内容の構造を示す手段が必要です。シーケンスは基本的に画像(カンバス)に対応する物理構造の情報を持ちますが、ページの途中で章が変わるなど、内容の構造をそこに多重化するのは問題が多いため、別途レンジという形で表現します。
レンジはシーケンスと同じくマニフェストの最上位に置かれ、structures
プロパティで記述されます。プロパティ値はすべてのレンジを要素とする配列です。この要素は章節のような入れ子構造の表現にも用いられますが、JSONオブジェクトにおいてはフラットに並びます。
各レンジは次のプロパティを持ちます。
プロパティ名 | 値の内容 |
---|---|
@id | レンジのID。一意に識別できるURI |
@type | レンジを示す型で、値はsc:Range |
label | レンジの表示名(階層目次の項目名) |
viewingHint | レンジの階層位置を示すヒント |
メンバー | レンジに含まれるメンバーを示す(下記参照) |
メンバーを表すプロパティは次の3種類です。
プロパティ名 | 値の内容 |
---|---|
ranges | レンジの子となるレンジのIDの配列(入れ子階層) |
canvases | レンジの子となるカンバスのIDの配列 |
members | レンジの子となるレンジ/カンバスを記述するオブジェクトの配列 |
ranges
の各要素は、structures
プロパティ値として並ぶ別のレンジを参照します。これによって、JSONを入れ子にすることなく階層構造を表現しています。レンジがcanvases
を持てば、その各要素が階層の終点ということになります。一つのレンジがranges
とcanvases
の両方を持つことも可能な点に注意してください。
レンジの記述
上記のプロパティを用いて、簡単な目次構造を記述してみましょう。次の例に用いる資料は、中世の詩を集めた写本のデジタル画像です。羊皮紙を綴じ合わせる順序が間違っていたため、写本の148ページで終わる章の次は169ページから始まります。
例を単純化するため、1つ目の章は最後の詩だけを、次の章は章全体のみを目次にします。
例6
"structures": [ { "@type": "sc:Range", "@id": "http://example.org/iif/cb/range/0", "label": "ブラヌス写本", "viewingHint": "top", "ranges": [ "http://example.org/iif/cb/range/1", "http://example.org/iif/cb/range/3" ] }, { "@type": "sc:Range", "@id": "http://example.org/iif/cb/range/1", "label": "恋の歌編", "ranges": ["http://example.org/iif/cb/range/2"] }, { "@type": "sc:Range", "@id": "http://example.org/iif/cb/range/2", "label": "CB186 フローラよ", "canvases": ["http://example.org/iif/cb/canvas/p148"] }, { "@type": "sc:Range", "@id": "http://example.org/iif/cb/range/3", "label": "酒の歌編", "canvases": ["http://example.org/iif/cb/canvas/p169"] } ]...
レンジの2と3が、写本画像としては連続しない2つのページ(カンバス)を指すことで、論理的な章の構成を示しています。
viewingHint
の値をtop
として加えると、そのレンジが階層構造の出発点であることを示します。論理的なルートとして機能するものなので、ビューアによってはこの表示を飛ばして次の階層から目次を示すものもあります(たぶんその方が自然です)。
members
プロパティは表示API仕様の2.1から加わったもので、ranges
とcanvases
の両方の役割をまとめ、さらに情報量を増やしています。そのためmembers
プロパティの要素はURI文字列ではなくJSONオブジェクトです。
対象のURIを@id
に記述し、レンジなのかカンバスなのかは@type
プロパティで示します。どちらの場合もlabel
が必須です。上例の「恋の歌編」の部分をmembers
に書き直してみましょう。
例7
{ "@type": "sc:Range", "@id": "http://example.org/iif/cb/range/1", "label": "恋の歌編", "members": [ { "@type": "sc:Range", "label": "CB186", "@id": "http://example.org/iif/cb/range/2" } ] }, { "@type": "sc:Range", "@id": "http://example.org/iif/cb/range/2", "label": "CB186 フローラよ", "members": [ { "@type": "sc:Canvas", "label": "写本148ページ", "@id": "http://example.org/iif/cb/canvas/p148" } ] }...
この例でも分かるように、members
の要素としてのレンジと、その参照先(structures
の要素)のレンジの両方がラベルを持つことになります(どちらも必須)。どう使い分けて欲しいのか、仕様にも示されておらず不明です。
また、仕様書の当該セクションの最後で、バージョン3.0では、ranges
とcanvases
を非推奨にしてmembers
に一本化するとうたっていますが、現状ではmembers
を正しく処理できないツールが多いので、当面はranges
/canvases
の方が安心できそうです。
カンバスの部分の参照
章や節がページの途中で切り替わる場合、その境目を指すcanvases
の要素は、厳密に言えばページ(カンバス)単位ではなく、その中で当該章/節にあたる部分を示すべきということになるでしょう。こうした用途を念頭に、レンジにおいてはカンバスURIにメディアフラグメントを加えた識別子を利用できることになっています。
上の例で「CB186 フローラよ」は148ページの下部、座標(x,y,w,h)でいえば137,343,585,603ピクセルの範囲で、同じページのその上には「CB185 ああつらい」の後半が書かれています。フラグメントを使えば、レンジ2は次のように記述できます。
例8
{ "@type": "sc:Range", "@id": "http://example.org/iif/cb/range/2", "label": "CB186 フローラよ", "canvases": [ "http://example.org/iif/cb/canvas/p148#xywh=137,343,585,603" ] }...
新聞の飛び地記事のような、本文の続きが別のページに置かれている構造もこの方法で表現できるわけです。これを利用して、ページを開いた時に該当部分をハイライト表示させることも可能でしょう。
ただ残念ながら多くのツールはこのフラグメント指定に対応しておらず、かえってエラーを生じる場合もあるので、すぐに利用するのは難しいかもしれません。
コレクションの表現
資料はしばしば複数のオブジェクトがグループを構成します。書籍の上下巻や全集の各巻などは、それぞれの書籍オブジェクトとして独立した存在でありながら、グループとしての扱いも必要です。
これに対応する形で、IIIFで個別資料に対応するマニフェストをグループ化する方法がコレクションです。コレクションは、マニフェストとよく似た構造のJSONオブジェクトで、同じように@context
や@id
、メタデータを持ちます。@type
の値はsc:Collection
で、sequences
の代わりにmanifests
プロパティを持ち、その値としてグループ化するマニフェストを列挙します。
国立国語研究所が日本語史研究資料として公開しているデジタル画像は、多くが上下巻などのグループになっています。この中から、徒然草(寛文七年版)上下巻のマニフェストをコレクションとして記述してみましょう。
例9
{ "@context": "http://iiif.io/api/presentation/2/context.json", "@id": "http://example.org/iiif/collection/ninjaldl", "@type": "sc:Collection", "label": "徒然草(寛文七年版)", "manifests": [ { "@id": "http://dglb01.ninjal.ac.jp/ninjaldl/turezure/001/manifest.json", "@type": "sc:Manifest", "label": "上巻" }, { "@id": "http://dglb01.ninjal.ac.jp/ninjaldl/turezure/002/manifest.json", "@type": "sc:Manifest", "label": "下巻" } ] }
manifests
の値となる配列要素は、@type
がsc:Manifest
であることからも分かるようにマニフェストそのものなのですが、ここにsequences
を埋め込むことはなく、@id
のURIにリンクする形です(レンジのmembers
の値がカンバスであるときと同様です)。
コレクションの入れ子
コレクションはmanifests
によってマニフェストをグループ化するだけでなく、別のコレクションをcollections
プロパティでまとめることもできます。
たとえば徒然草関連のデジタル画像は、人文学オープンデータ共同利用センターの日本古典籍データセットでも多数公開されています。この中から「徒然草寿命院抄」に関する3つの資料をグループ化し、さらに日本語史研究資料と合わせた親コレクションを作ってみます。子コレクションには@context
は不要です。
例10
{ "@context": "http://iiif.io/api/presentation/2/context.json", "@id": "http://example.org/iif/collection/tsurezure", "@type": "sc:Collection", "label": "徒然草および関連書", "collections": [ { "@id": "http://example.org/iif/collection/ninjald", "@type": "sc:Collection", "label": "徒然草(寛文七年版)", "manifests": [ { "@id": "http://dglb01.ninjal.ac.jp/ninjaldl/turezure/001/manifest.json", "@type": "sc:Manifest", "label": "上巻" }, ... ] }, { "@id": "http://example.org/iif/collection/pmjt", "@type": "sc:Collection", "label": "徒然草寿命院抄", "manifests": [ { "@id": "http://codh.rois.ac.jp/pmjt/book/200015714/manifest.json", "@type": "sc:Manifest", "label": "徒然草寿命院抄(写) 2冊〔89-76-1~2〕" }, ... ] } ] }
コレクションが階層構造を持てるのは、レンジの場合とよく似ています。実際、Universal Viewerに入れ子コレクションのマニフェストを与えると、レンジによる目次とそっくりの形で表示されます(ただしコレクションの場合はJSONの記述も入れ子になるところが異なります)。
レンジと同様、manifests
とcollections
を合わせたmembers
も表現API仕様2.1からは使えるようになり、やはり3.0では前者を非推奨にするとしています。コレクションの場合は、もともとプロパティの配列要素がURI文字列ではなくJSONオブジェクトなので、members
も概ね問題なく使えそうです。