みんなで翻刻のWeb API!

Web APIという言葉はあちこちで耳にされることがあると思います。API=アプリケーション・プログラミング・インターフェイス、ということで、つまり何かを作ったり動かしたりする時にやりとりをする機能、をWebで使えるようにしたもの、と考えておけばいいでしょうかね。Webブラウザの裏側でサーバ同士でデータをやりとりできるというのが肝で、各所のデータを統合した便利な機能を提供してくれたりするのはまさにWeb APIの恩恵によるものです。

世はWeb API花盛りです。花盛り過ぎて、それについて話題にすることもあまりなくなってきてはや10年、といったところです。あってもなくても、それはそれぞれのポリシーによる選択の結果をあらわしているに過ぎない、というところまで時代は進んでいるのかなと思っております。

しかしながら、一方で、開発途中のシステムだと、「Web APIも用意したけどあとまわし」ということも散見されます。また、Web APIを用意しても、「どういう構造になっているのか」「どういう風に使えるのか」を知らしめる仕様書のようなものが公開されていないと、せっかく用意したのにあまり使ってもらえないということもあります。逆に、あまり広く使われすぎると困るので仕様書は広く公開しないようにしていることもあるようです。

前置きが長くなりましたが、前回記事で紹介した「みんなで翻刻⇔みんなで検索」が実現できたのも、このWeb APIのおかげです。開発者である橋本雄太氏が、ご多忙な中で1時間でささっと作ってくださいました。ここでのWeb APIはそれほど複雑なものではなく、しかし、本文検索サイトを構築しつつ本家に更新があったらそれを検知して検索インデックスを更新する、という仕組みを作成するにあたって必要となる機能を大体網羅しているものでした。

というわけで、今回は、みんなで翻刻Web APIの紹介を少しだけ試みます。

まず、「現在登録されているプロジェクトの一覧」を取得するWeb API (のURL)は下記の通りです。

https://us-central1-honkoku2.cloudfunctions.net/api/projects

こちらにアクセスすると、プロジェクトの一覧とそれぞれの説明等に加えて、プロジェクトのIDが返戻されます。このフォーマットはWebでよく用いられるJSONというフォーマットになっています。これは、このまま見てもごちゃっとしてよくわかりませんが、全部コピペしてJSON整形ツールにかけると、構造を反映した形で見やすく表示できます。たとえばこのサイトだと以下のような感じになります。

f:id:digitalnagasaki:20200106210839p:plain
JSON画像

つまり、「みんなで翻刻(以下、「みん翻」と略します)」で現在展開されているプロジェクトの情報を得たければ、このWeb APIで取得できる、ということになります。

さて、筆者が今回作ったのは「本文検索」でした。そうすると、ここで取得できる情報だけでは検索ができません。「みん翻」のデータは、

プロジェクト>コレクション>エントリ>各頁(画像)

という風になっているようですので、次に、個々のプロジェクトが持っている「コレクション」の情報を取得します。この際には、上記のWeb APIで得られる各プロジェクトの"id"が必要になります。 これを何らかの方法で取得して、今度は以下のURLにてアクセスします。たとえば、「日本の仏典を翻刻!」のプロジェクトの場合、idは「21dzk」ですので、URLの最後に以下のようにそのプロジェクトidを付与してアクセスします。

https://us-central1-honkoku2.cloudfunctions.net/api/projects/21dzk

そうすると、このプロジェクトがどういうコレクションを持っているかという情報が得られます。これもやはり、先ほどと同じJSON形式で返戻されます。コレクションにはその説明もありますが、今回必要なのは本文ですので、さらに下の階層へと向かいます。このコレクションに含まれる(=下位にある)エントリを取得すべく、とりあえずここで入手できたコレクションのidを用いて以下のようにWeb APIにアクセスしてみます。ちなみに、以下のURL中の「2AC632E5683C37F7C69425EA497007FA」という箇所が、上記のURLから得られたコレクションのidです。

https://us-central1-honkoku2.cloudfunctions.net/api/collections/2AC632E5683C37F7C69425EA497007FA

このURLにアクセスして返戻されたJSONデータを整形すると以下のようになります。

f:id:digitalnagasaki:20200106223750p:plain
jsonデータの画像

ここで、"entries": となっているキーの値が複数で列挙されています。これらの値がそれぞれのエントリのidということになります。この中の一つのエントリidを使って以下のURLを作ってアクセスしてみます。

https://us-central1-honkoku2.cloudfunctions.net/api/entries/6AC3A275993D8AC73941D97376426A61

ここでは、「6AC3A275993D8AC73941D97376426A61」がエントリidの部分になります。

このURLにアクセスすると、このエントリに含まれる画像とそれに対応する翻刻テキストのデータが入手できます。あとは、このテキストデータを検索できるようにして、画像ともリンクできるようにすればOKです。ちなみに、翻刻テキストデータは"transcriptions"以下にリストとして入っていて、各リストは辞書になっていて、その中の「text」というキーが翻刻テキストデータのようです。また、更新日付のキーは「timestamp」、といった案配です。画像に関しては、IIIF対応画像の翻刻をシステムの基盤の一つとしていることもあるのかもしれませんが、IIIF Manifestを継承した形になっているようで、これをきちんと理解しようと思うなら、IIIF Presentation API 2.1をみておくとよいかもしれません。

というわけで、今回は、Web APIで本文を取得する方法を最短距離でまとめてみました。

エントリのJSONデータからどのデータを取り出してどのように使ったか、という話は、また次の機会としましょう。

みんなで翻刻⇔みんなで検索

みんなで翻刻 」というサイトを知らない人は、このブログの読者にはいらっしゃらないと思います。しかしながら、○○業界なら必須アイテムになりそうだし、大体の人は知ってそうな…と思ってご紹介してみると意外とそうでもないことが多く、人が自分(の仕事)にとって必要(になりそう)な情報を入手する機会を作るということがいかに難しいことか、このサイトを話題にした際にも時折感じることです。

ところで、この年末年始の半分は、この「みんなで翻刻」の検索システムの作成に費やしておりました。日本の仏典の翻刻も最近取り込んでいただいたのですが、作業を進めていくにあたり、とりあえず、返り点や改行、いくつかのタグをまたいだ全文検索、そして異体字もまとめて検索できるようになっていると便利なのではないか、ということで、開発者の橋本雄太氏にお願いしてWeb APIを作っていただきました。これを使って「みんなで翻刻」のテキストデータをごそっと取り出して少し手を加えて検索用インデックスを作り、さらにそれを検索できるインターフェイスを作成する、という作業でした。

honkoku.dhii.jp

上記のリンクをご覧いただくと、とりあえず検索ができるようになっています。検索結果から、「みんなで翻刻」の該当頁に戻れるようになっていて、そこで画像とテキストが確認できます。なお、リンク先は、この検索システムで何ができるか一目でわかるように、検索結果の状態を表示しています。

いつもの作り方であれば全然時間はかからないのですが、今回は、若い人達に「もう古いっすよそれ」と言われるやり方を捨てて、「新しいWebアプリの書き方」を勉強しながら作成しました。Python3でFlaskというマイクロフレームワークを使ってみたのでした。ついでにjQueryというJavascriptのライブラリもやめてVue.jsに移行しようと思ったのですが、こちらは思ったほどすぐに簡単に動かすことができず、いつものjQueryで書いたら一瞬で書き終わったので、こちらはもう少し使い続けることになりそうです。

全体の構成としては、Web APIを用いて取得したテキストデータをApache Solrに入れて、それをPython3からURLのクエリを投げて結果をFlaskで整形して表示、という感じです。異体字同時検索はApache SolrのcharFilterで自作のマッピングファイルを読み込ませています。メニューの絞り込みとか継承にjQueryを少し使っていて、表示のところでもBootstrap4を使っているのでそちらでもどこかでjQueryが使われているかもしれない、という状況です。

当面の目標は、「みんなで翻刻」でデータの入力・更新があったらそれを検索結果に反映させることなのですが、その機能はまだできていません。そろそろいくつかの事務仕事に集中しなければなりませんので、そちらが片付いてからまた取り掛かりますので、もう少し時間がかかりそうです。ですが、そこまでは必ずやります。

せっかくですので、ここで得たノウハウをブログに開陳していきたいところなのですが、今はちょっと時間がないので、少し時間ができたらぼちぼちやっていきたいと思います。

ということで、本年もよろしくお願いいたします。

オープンアクセス出版『デジタル学術空間の作り方』が刊行されました

ここしばらく、文章を書く時間のほとんどを費やしていたものが、ついに刊行されました。

もうじきアマゾンで紙版が入手可能になる予定ですが、

https://www.amazon.co.jp/exec/obidos/ASIN/490965819X/hanmotocom-22www.amazon.co.jp

科研費事業の成果報告という位置づけの刊行物であり、オープンアクセスでも入手できるようになっています。このような試みに親切にも対応してくださった『文学通信』社のリポジトリにて全文を無料で閲覧できます。

repository.bungaku-report.com

第一部では、これまでほとんど語られることのなかったSAT大蔵経テキストデータベース研究会の通史が綴られています。後半部分の、テキストデータベース公開以降の話はあちこちで論文が出ていますのでCiNii等で探せばほとんどの話はみつかると思いますが、前半部分、とくに研究会の設立からテキストデータ完成に至る経緯は、日本でのデジタルアーカイブ構築の一事例としても、ある研究分野のデジタル技術への向き合い方の一例としても、興味深いものと思います。身内を褒めるようで恐縮ですが、一連のネゴシエーションを乗り切ってこられた関係者の先生方、とりわけ下田正弘先生の御尽力には改めて圧倒されるものがあります。

本書について個人的に面白いと思うところは第二部にも多くあります。仏教研究に長らく関わりつつデジタル技術を何らかの形で活用してきた方々、資料としての仏典に含まれる情報をデジタル技術を用いて探求する方々など、それぞれの立場から、仏典をめぐるデジタル技術の状況が語られており、情報技術の適用の仕方としても、テキスト研究のこれからを考える上でも、様々なヒントがちりばめられています。 第二部の個々の記事の解説はこちらにてご覧いただけますので、試しに読んでみる前にちょっと目を通してみていただくとご参考になるかもしれません。

まだまだできていないことも多いですが、これからも、デジタル学術空間をどう作っていくか、試行錯誤を続けつつ、良さそうなものは皆さんと共有しながら続けていきたいと思っております。

個人的には、あと1冊刊行しなければならないものがあるので、ブログ書きはもう少し遅延し続けるかもしれませんが、ここ数ヶ月に比べれば、この後しばらくは更新頻度は多少高まると思います。

今後とも、よろしくお願いいたします。

IIIF manifestファイルを簡単に作ってみよう

今回は、最低限のIIIF manifestファイルを簡単に作ってみる方法をご用意してみました。経緯等は後回しにして、とりあえずやり方をば。

画像ファイルは、前回記事のやり方でpyramid tiffになっているものとします。拡張子は.tif。 そして、一つの資料ごとに一つのフォルダ(ディレクトリ)にまとめられているものとします。

そこで、まずは以下のようなCSVファイルを作成します。エクセルで作ってCSV UTF-8で保存すれば 大丈夫かと思います。(一応実験済み)

dir,title,license,attribution,viewingDirection,translator,publisher
0040_01,大方廣佛華嚴經 序~巻第二,https://creativecommons.org/licenses/by/4.0/deed.ja,東京大学総合図書館・SAT大蔵経テキストデータベース研究会,right-to-left,實叉難陀,鉄眼禅師
0040_02,大方廣佛華嚴經 巻第三~六,https://creativecommons.org/licenses/by/4.1/deed.ja,東京大学総合図書館・SAT大蔵経テキストデータベース研究会,right-to-left,實叉難陀,鉄眼禅師
0040_03,大方廣佛華嚴經 巻第七~十,https://creativecommons.org/licenses/by/4.2/deed.ja,東京大学総合図書館・SAT大蔵経テキストデータベース研究会,right-to-left,實叉難陀,鉄眼禅師
0040_04,大方廣佛華嚴經 巻第十一~十四,https://creativecommons.org/licenses/by/4.3/deed.ja,東京大学総合図書館・SAT大蔵経テキストデータベース研究会,right-to-left,實叉難陀,鉄眼禅師
0040_05,大方廣佛華嚴經 巻第十五~十七,https://creativecommons.org/licenses/by/4.4/deed.ja,東京大学総合図書館・SAT大蔵経テキストデータベース研究会,right-to-left,實叉難陀,鉄眼禅師
0040_06,大方廣佛華嚴經 巻第十八~二十,https://creativecommons.org/licenses/by/4.5/deed.ja,東京大学総合図書館・SAT大蔵経テキストデータベース研究会,right-to-left,實叉難陀,鉄眼禅師

最も大事なのは、一番左の列です。ここには、画像のフォルダ(ディレクトリ)名を入れておきます。前後の スラッシュは無しです。ここの情報を使って画像フォルダと突合させますので、これは必ず正確に記述してください。 (コピペ推奨です)

その他の内容ですが、まず、一行目は項目を書いて、二行目からコンテンツに対応する各種情報を書いていきます。titleはタイトルを書いておきます。 license (利用条件), attribution (帰属)、viewingDirection(読んでいく方向)あたりは書いておいた方がよいです。特に 右から左にページめくりしていくような物(縦書きの日本語・漢文資料など)はviewingDirectionのところに right-to-leftを書いておくと後々いいことがあります。 licenseは、ライセンス(利用条件)情報が書かれたベージのURLを書いておくことに なっています。なお、項目名については、IIIF Presentation APIで定められているものは英語で書いた方がよいですが、 それ以外の独自の項目名は日本語でつけても今のところはあんまり問題ありません。

繰り返しになりますが、エクセルで作った場合はCSV UTF-8で、そうでなければ普通にUTF-8で保存して いただけば大丈夫かと思います。ここでは仮にファイル名を bib.csv としておきます。

それから、準備として、Python3から画像の大きさを取得できるように、以下のようにモジュールをインストールしておきます。

% sudo pip3 install pillow

さて、次に、以下のスクリプトを回して見ます。

#!/usr/bin/python3
import sys
import glob
import os
import csv
import json
from PIL import Image
base_url = 'https://candra.dhii.jp/iiif/tetsugen/0040/'
#ここ↑はマニフェストが設置されるURLに応じて書き換える
base_image_url = 'https://candra.dhii.jp/iiifimgs/tetsugen/0040/’
#ここ↑はIIIF Image APIのURLに応じて書き換える
all_bib = {}
all_bib2 = {}
bib_title = []
mani_keys = ['dir','title','license','attribution','within','logo', 'description','viewingHint','viewingDirection']
#ここ↑は、IIIF Presentation APIにて、トップレベルで規定される項目を入れておきます。必要に応じて適宜増やしてください。
with open(sys.argv[1], newline='', encoding='utf_8_sig') as csvfile:
  spamreader = csv.reader(csvfile, delimiter=',', quotechar='"')
  rn = 0
  for row in spamreader:
    if rn == 0:
      bib_title = row
    else:
      each_bib = {}
      each_bib.update(zip(bib_title,row))
      link_name = row[0]
      all_bib[link_name] = each_bib
    rn = rn + 1;
#print (all_bib)

for key in all_bib.keys():
  each_manifest = {}
  all_meta = []
  file_dir0 = key
  glob_name = key+"/*.tif"
  if os.path.isdir(key):
   list_file_names = sorted(glob.glob(glob_name))
   if len(list_file_names) == 0:
     glob_name = key+"/*.ptif"
     list_file_names = sorted(glob.glob(glob_name))
   for item in all_bib[key]:
     if item not in mani_keys:
       each_meta  = {}
       item_value = all_bib[key][item]
       each_meta['label'] = item
       each_meta['value'] = item_value
       all_meta.append(each_meta)
   each_manifest['@id'] = base_url+key+'/manifest.json'
   each_manifest['@type'] = 'sc:Manifest'
   each_manifest['@context'] = 'http://iiif.io/api/presentation/2/context.json'
   each_manifest['metadata'] = all_meta
   for mani_key in mani_keys:
     if all_bib[key].get(mani_key):
       if mani_key == 'title':
         each_manifest['label'] = all_bib[key][mani_key]
       elif mani_key != 'dir':
         each_manifest[mani_key] = all_bib[key][mani_key]
   cn = 0
   sequence = {}
   canvases = []
   for file_path in list_file_names:
     service = {}
     resource = {}
     mani_image = {}
     canvas = {}
     file_dir = os.path.split(file_path)[0]
     if os.path.isdir(file_dir):
       cn = cn + 1
       canvas_number = 'p'+str(cn)+'.json'
       image_url_id = base_image_url+file_path
       service['@context'] = 'http://iiif.io/api/image/2/context.json'
       service['@id']  = image_url_id
       service['profile'] = 'http://iiif.io/api/image/2/level1.json'
       img = Image.open(file_path)
       width, height = img.size
       resource['@type'] = 'dctypes:Image'
       resource['format'] = 'image/jpeg'
       resource['width'] = width
       resource['height'] = height
       resource['@id'] = image_url_id+'/full/full/0/default.jpg'
       resource['service'] = service
       mani_image['@type']  = 'oa:Annotation'
       mani_image['motivation']  = 'sc:painting'
       mani_image['resource']  = resource
       mani_image['@id']  = base_url+file_dir+'/annotation/'+canvas_number
       mani_image['on']  = base_url+file_dir+'/canvas/'+canvas_number
       canvas['label'] = 'p. '+str(cn)
       canvas['images'] = []
       canvas['images'].append(mani_image)
       canvas['width'] = width
       canvas['height'] = height
       canvas['@type'] = 'sc:Canvas'
       canvas['@id'] = base_url+file_dir+'/canvas/'+canvas_number
       canvases.append(canvas)
   sequence['@id'] =  base_url+file_dir0+'/sequence/s1.json'
   sequence['@type'] =  'sc:Sequence'
   sequence['label'] =  'Current Page Order'
   sequence['canvases'] = canvases
   each_manifest['sequences'] = []
   each_manifest['sequences'].append(sequence)
   write_file_path = file_dir0+'/manifest.json'
   with open(write_file_path, mode='w') as f:
     json.dump(each_manifest, f, ensure_ascii=False)

ちょっと長いですが、こちらを mk_manifest.pyというファイル名で保存します。 ただし、二箇所、どうしても書き換えねばならないところがありますので、 その箇所にコメントをつけています。その二箇所は 環境に応じて書き換えてください。

ここで、各ファイルの位置関係は、以下のようになっています。

---mk_manifest.py

---bib.csv

---0040_01---tiffファイル群

---0040_02---tiffファイル群

---0040_03---tiffファイル群

---0040_04---tiffファイル群

この状態で、以下のようにコマンドを走らせます。

% python3 mk_manifest.py bib.csv

そうすると、各画像フォルダの中に manifest.json ファイルができていると思います。これで、できあがりです。 ディレクトリ構成も適正になっている場合には、manifestファイル中のこのマニフェストファイルのURIを 示す@idを使ってWebブラウザで表示させてみてください。人間の目では見づらいですが、こんな風になって いれば多分大丈夫です。あとは、MiradorやUniversal viewer、IIIF Curation viewer、TIFYなどに読み込ませれば 普通に表示できるはずです。

閑話休題

さて、これを作った経緯についても簡単に書いておきますと、IIIF Manifestの書き方がよくわからない、という 話をしばしばいただいていて、そこがなんとなくハードルになっているように感じたためです。すでに 江草氏による解説記事も用意されていますが、もう少し別の角度から情報提供してみてもいいのかもしれないと 思って、こういうものをちょっと作ってご紹介してみました。

もう少し言えば、内製でこれから勉強して取り組まなければならない人がいる、ということを風の噂で耳にしたということもあります。

この記事は、少しだけプログラミングができる人を対象としたものです。ただ、本当に少々でいいというのが、上記のものを 見ていただくとわかると思います。CSVファイルの内容を読み込んで、画像の大きさとファイル名も読み込んで、 それらをIIIF Manifest の形にあわせてlist とdictを組み合わせて構造化し、最後にjsonとして書き出しをする、という 形になっています。画像フォルダの階層がもっと深い場合は glob.glob() に読み込ませるワイルドカードを 少し変更してみる、などの手立てが必要です。とはいえ、もっとエレガントな書き方もできますので、改良版を作成&公開してくださる人がおられたら 大変ありがたいところです。

画像フォルダとmanifestファイルの位置関係については、色々なやり方があると思いますので、場合によっては、 それにあわせてmanifestファイルの保存場所も変更したりする必要があるかもしれません。そこら辺は適宜 修正する必要があると思いますが、どうしてもよくわからないけどなんとかしたい・しなければならない という人はご相談ください。

なお、元々はPHPで書いていたものを簡素化してPythonで書き直したものですので、書き方にPHPっぽい(Pythonに最適化されてない)ところがあるかもしれませんが、 その点はご容赦ください。

IIIF Image サーバ (IIP Image server)構築のために(Python3+VIPSで)(Centos7用追記あり)

以前に、IIIF Imageサーバで大きな画像やたくさんの画像を高速に配信したい場合の有力な手段としてIIP Image serverのインストールの仕方をご紹介しました。

ただ、以前の記事では、「ピラミッド型タイル画像ファイルの用意」に関する説明があまり親切ではありませんでした。この点についての質問を時々いただくので、これについてもう少しご説明してみることにしました。

以前の記事ではImageMagickを使ったやり方を示していましたが、画像が多い場合はVIPSの方が高速で良いという話を聞きますので、VIPSを使った方法を見てみましょう。 動作環境は、Ubuntu18 + Python3です。

まず、こちらの指示に従って、VIPSを以下のコマンドにてインストールします。

% sudo apt install libvips-tools

これで依存関係のあるパッケージも一緒にインストールできるのではないかと思います。もしダメなら、その前に以下のコマンドでlibvipsそのものもインストールしておきましょう。

% sudo apt install libvips libvips-dev

次に、こちらの指示に従いつつ、Pyhon3環境があることを前提として、以下のコマンドにてインストールします。

% sudo apt-get install python3-gi gir1.2-vips-8.0

その後、以下のようにして、Pythonモジュールをダウンロード&設置します。

% sudo su

% wget https://raw.githubusercontent.com/jcupitt/libvips/8.4/python/packages/gi/overrides/Vips.py -O /usr/lib/python3/dist-packages/gi/overrides/Vips.py

これでVIPSをPython3から使えるようになったはずです。

次に、指定したフォルダ内のjpgファイル群からPyramid tif群をまとめて生成してみます。これは 以下のようなスクリプトでできました。

#!/usr/bin/python3
import sys
import gi
gi.require_version('Vips', '8.0')
from gi.repository import Vips
import glob
import os
file_names = sys.argv[1]+"/*.jpg"
list_file_names = glob.glob(file_names)
for file_path in list_file_names:
  new_file_path = os.path.splitext(file_path)[0] + ".tif"
  print(new_file_path)
  im = Vips.Image.new_from_file(file_path)
  new_file_path = new_file_path+'[compression=jpeg,Q=75,tile=1,tile-width=256,tile-height=256,pyramid=1]'
  im.write_to_file(new_file_path)

上記のスクリプトを mk_mani.pyというファイル名で保存した場合、

% python3 mk_mani.py [JPEG画像が保存されているフォルダ名]

という風にすると、上記のコマンドラインにて指定したフォルダの中の「.jpg」の拡張子を持つJPEG画像からPyramid Tiffファイルを生成できるはずです。

特にこれといった特別なことはしていませんが、ご参考になりましたら幸いです。

追記: Centos7で同じ事をするための手順も大体分かりましたので、とりあえず私の経験ということでご紹介しておきます。

まずはPython3をインストールしておきましょう。どうやら、baseリポジトリから入れられるようになっている みたいなので、epelやremiからインストールしてしまったという人はいったん削除してからbaseのものを 入れ直すと手順が楽になると思います。(削除することで他の問題が発生しそうだという場合は削除しないように お願いします)。

python3は開発パッケージも必要のようですので、

% sudo yum install python3-devel

としておきましょう。これでpython3がらみで必要なものはまとめてインストールされると思います。

それから、まだepelやremiをyumリポジトリとして設定していない人は、これを機会に設定して おきましょう。少なくともremiは以下の手順の中で必要になります。以下のサイトなどをご参考に。

https://www.kakiro-web.com/linux/remi-install.html

https://qiita.com/kodamacom/items/308f1c3e223d115103a9

さて、さっそくvipsのインストールなのですが、vipsの開発パッケージインストールのところで Remiに入っているlibwebp7-develが必要で、かつ、既存の libwebp-develとかち合ってしまうので既存のものは削除します。 そうすると、vips-develがインストールできるようになります。

% sudo yum erase libwebp-devel

% sudo yum --enablerepo=remi install libwebp7-devel

% sudo yum install vips-devel

ここからが、メモが甘くてややうろ覚えなのですが、

% sudo pip3 install pycairo

% sudo yum install gobject-introspection-devel

% sudo yum install cairo-gobject-devel

% sudo yum install pygobject3-devel

という風にしてから、最後に、以下のコマンドで、vips.pyを所定のディレクトリにダウンロードしておくと、 上記のようにPython3からVIPSを使えるようになりました。

% wget https://raw.githubusercontent.com/jcupitt/libvips/8.4/python/packages/gi/overrides/Vips.py -O /usr/local/lib64/python3.6/site-packages/gi/overrides/Vips.py

なるべくこまめにメモしながら作業したつもりですが、何か抜け落ちているかもしれず、うまくいかない場合は ご容赦ください。

デジタルアーカイブがサイズ感を得る時

まずはこちらの画像を見てください。何をしているのかというと、「サイズの異なる写真で、映り込んでいる定規をディープラーニングで解析してサイズをぴったりあわせて」います。 これで、2つの百鬼夜行絵巻のサイズの違い(片方は箱ですが)を、いちいちズームで調整することなく、ボタン一つで確認できるようになりました。

youtu.be

このサイズ調整機能を使うと、同じ二つ絵巻の内容を見るときも、二つの絵巻のなかのつづらのサイズはほぼ同じなのに片方の巻物は上下の余白が少ない、ということが簡単に確認できます。

youtu.be

デジタルアーカイブの画像は、これまで、ともすればサイズ感を見失ってしまいがちでしたが、このようにして簡便に 元サイズ同士の比率を反映した比較ができるようになると、これまでとはかなり印象が違ってくるようになると思います。

同時に、定規をいれて撮影することは、このように、技術の進歩によって非常に重要な要素になり得ることがわかります。

このビューワ自体はこちらで利用できます。ビューワ自体がまだそんなに使いやすくないですが、興味がある人はぜひお試ししてみてください。また、このビューワはgithub上で公開してますので、どなたでもソースコードを持って行って改良することができますので、もっと使いやすく作り直していただけますと大変ありがたく存じます。

さて、このようなものがどういう経緯でできたのかと言いますと、「ジャパンサーチ公開記念 GLAMデータを使い尽くそうハッカソン」という 国立国会図書館で開催されたイベントの中で作成されました。国立国会図書館でディープラーニング技術にも取り組んでいる青池亨さんが、私の無茶な要求に応えて開発して くださいました。

ここでどういうことが行われているのかというと、定規を移し込んだ画像を二つ重ねて表示してからサイズ調整ボタンをクリックすると、 こちらのビューワからは、IIIF Image APIで幅1024の画像のURLを2つ作ってGET Methodで送出し、あちら側では、おうかがいしている限りでは、 定規をディープラーニングで抽出してから、定規の目盛りをごにょごにょして(これはご本人に解説していただいた方がいいでしょう)サイズを取り出し、 二つの画像のサイズ比を返戻してもらいます。サイズ比を受け取ったら、あとはビューワの側でその数値に基づいてサイズを調整します。これで、 サイズ調整に際していちいち定規の目盛りを見ながら調整する必要がなくなりました。

ハッカソンというたったの二日間でこういうものを開発してしまう人が国立国会図書館で働いていて、さらに、そもそもそういう ものを開発しようという検討や、それをアプリに組み込んだりする時間と場を国立国会図書館が 提供してくれる、というのも、なかなかすごい時代になったものだと思います。

定規の入った二つの画像のサイズ比を取得する仕組みはAPIとして青池さんが公開しておられますので、使って見たい方は 上記のgithubのソースをみていただければと思います。この仕組みはさらに色々応用可能だと思いますので、今後の青池さんの ご活躍にはたいへん期待したいところです。

「デジタルアーカイブ研究」の観点?

今度、「第 7 回定例研究会:ジャパンサーチの課題と展望」というところでお話をさせていただくことになりました。 ここしばらくのジャパンサーチ試用は、そのご依頼を果たすための準備だったのですが、今回のご依頼は、実は使い勝手の 話ではなくて「 仕組み・社会的位置づけの観点から」ということでしたので、使い勝手の話は二の次です。 ここまでの試用を踏まえつつ、「 仕組み・社会的位置づけの観点から」の議論を組み立てようと思っております。 そこで、今回の研究会の紹介文を見てみますと、

第 7 回定例研究会:ジャパンサーチの課題と展望 (2019/9/24) | デジタルアーカイブ学会

試行版の評価や2020年に運用開始が予定されている正式版への期待・改善点の指摘などの議論を、デジタルアーカイブ研究の 観点から実施する。

という風になっており、ここには「デジタルアーカイブ研究の観点」という言葉が出てきます。しかしながら、 私はどちらかと言えばデジタルアーカイブの実践者であり、それを利用した研究やその基礎となる事についての研究はしておりますが、 デジタルアーカイブそのものの研究はあんまりしたことがないので、やや遠い立場ではありますが、少し気になっている点を整理してみたいと思います。

これまで、デジタルアーカイブに関わる研究集会としては、それをテーマとして長年掲げてきた じんもんこん(人文科学とコンピュータ)シンポジウムにずっと参加しておりましたので、 人文学向けのデジタル技術の応用という観点からのデジタルアーカイブについてはある程度議論ができるつもりでおりました。

しかしながら、デジタルアーカイブ学会の大会やデジタルアーカイブサミットに一般参加者として(一度、座長不在で急遽代理で座長を やる羽目になったことはありますが)ちょろちょろ参加させていただく中で、 議論が結構難しいということに気がつきました。たとえば、データの永続アクセスを保証しなければ、という 話をしようとすると、データを削除できなければコミュニティアーカイブでは問題だ、という話になり、 オープンアクセスの実現という話をしようとすると、有料でもアクセスできるならオープンアクセスだ(これは決して間違いではない)、 という話になり、定義に関する議論が大変なので、とりあえずは、とにかくデジタルコンテンツを集約した ものをデジタルアーカイブと呼ぼう、と言えば、コンテンツを持たない横断検索サイトもデジタルアーカイブに入れるべきだ、という 話がでてきたりして、「永続アクセスを保証するにはどうすれば」「無料で皆が自由にアクセスできるようにするには どうすれば」等の話に具体的に取りかかることが難しいことがあります。もちろん、「デジタルアーカイブ」全般について 考える際にコミュニティアーカイブのことを放置するなど話になりませんし、たとえ有料であっても門外不出の秘宝などを オープンにしていただけたのであればとてもありがたいことです。

そういうわけで、ここのところ、そういう状況を整理しながら議論する方法が 必要なのではないかと思っておりまして、そこで、議論を始める際に、以下のような見取り図を作ってみることを考えてみました。

f:id:digitalnagasaki:20190909030013p:plain

何か議論するときに、それぞれの項目について、どういう範囲を想定しているのか、ということを明示しながら話をすれば、 今は議論の対象になっていないだけで、論点を無視されているわけではないということが理解されやすくなって、 議論が多少進めやすくなるのではないかと思ったのです。これに従えば、たとえば、ユネスコ世界記憶遺産にも選ばれたかの有名な デジタルアーカイブは以下のようになると思います。(間違ってたらすみません)。

f:id:digitalnagasaki:20190909030353p:plain

あるいは、30万点の日本の歴史的典籍のデジタル化を目指す国文学研究資料館が有する巨大古典籍データベース、 日本古典籍総合目録データベースの場合、大体以下のような感じになるのではないかと思います。古典籍の中には 江戸時代の木版本もかなり含まれており、その中には、1点1点、刷りごとに微妙に異なるとは言え、 版が同じ複製本とも言えるようなものが含まれているので、複製物に少しシフトします。

f:id:digitalnagasaki:20190909030524p:plain

国立国会図書館デジタルコレクションの場合には、活版印刷本もたくさん入っているので複製物が 多いと考えることができます。永続アクセスが求められていて、著作権切れ資料はそのまま パブリックドメイン資料として公開していますが、一部に公開できないものもデジタル化してしまっていますので、 ちょっと飛んで「公開不可」にも丸がつきます。インターフェイスとしては一般向けを志向している面もあろうかと思います。 ということで、以下のような感じにしてみています。

f:id:digitalnagasaki:20190909030559p:plain

国宝をデジタル化したものを高精細画像で公開してくださっている貴重なサイト、e国宝だと以下のような感じでしょうか。

f:id:digitalnagasaki:20190909031005p:plain

一方、国立国会図書館東日本大震災アーカイブ(ひなぎく)の連携先の一番上に掲載されている「青森震災アーカイブ」を採り上げてみますと、おそらく 以下のように記述できるだろうかと思います。

f:id:digitalnagasaki:20190909031642p:plain

あるいは、今回の研究会を主宰する福島幸宏氏らが先週末のCode4Libジャパン2019で発表していた 「アーカイブズ構築のスリムモデル」であれば、大体以下のような感じに なるでしょうか。

f:id:digitalnagasaki:20190909032221p:plain

さて、ここでジャパンサーチの議論に戻りましょう。ジャパンサーチは統合検索を志向していますので、最終的には、こういった諸々のものをすべて 対象とした検索になるのだろうと想像されます。ですので、ジャパンサーチについて「どういうものをどう検索したいか」ということを 議論するのであれば、このような振れ幅を持つ色々な事項について議論することになると思われますので、お互いに、どの部分を前提として 議論しているのか、を時々確認しながら議論するとよいのではないかと思っております(が、いかがでしょうか?)。

なお、項目としては、他にも、

  • 「デジタルアーカイブ自体の位置づけ」:実験系⇔実装系

  • 「あるべき運営主体」:個人系⇔組織系

といったものも入れてみてもいいかもしれません。他にももしあればご提案いただけますと幸いです。