IIIFの古地図をWMTSで配信する(Allmapsを土台に、Next.jsポートフォリオに統合)
IIIFの古地図をWMTSで配信する(Allmapsを土台に、Next.jsポートフォリオに統合)
iiifwmtsallmapsnextjsgeoreferencing
台本(フルテキスト)
動画の掛け合いを書き起こしたものです。音声を再生しづらい場合はこちらをお読みください。
オープニング
- IIIF古地図をWMTSタイルサーバとして配信
- Allmapsを土台にNext.js + SSRで実装
- つむぎ
- こんにちは。今日はIIIFの古地図をWMTSで配信する仕組みを実装した記録を紹介します。
- そら
- IIIFとWMTSは何ですか?
- つむぎ
- IIIFはInternational Image Interoperability Frameworkの略で、画像配信の国際相互運用仕様です。WMTSはOGCのWeb Map Tile Service、タイル画像配信の標準仕様です。
- そら
- 古地図をOpenStreetMapの地図と重ねて表示できるんですか?
- つむぎ
- そうです。Allmapsというツールで地理参照したIIIF古地図を、OpenLayersで現代地図の上に重ねて表示できます。
- そら
- Allmapsというのは既存のツールですか?
- つむぎ
- そうです。Allmapsチームが開発したツール群で、アノテーション編集、タイル配信、レンダリングまで含みます。今回はそれを土台にして薄いラッパーを実装しました。
なぜ自前実装が必要だったか
- 一部IIIFサーバにUAフィルタがありallmaps.xyzから取得できない
- OGC WMTS正規仕様・POI統合・ローカル開発対応が必要
- そら
- Allmapsがあるなら自前で実装する必要はないんじゃないですか?
- つむぎ
- 4つの理由があります。まず一部のIIIFサーバ、たとえばCloudFront配下のCantaloupeがUser-Agentフィルタで403を返すケースです。
- そら
- 他には何がありますか?
- つむぎ
- OGC WMTSの正規仕様、CapabilitiesとGetFeatureInfoをQGISのようなクライアントに対応させたいこと、POIのアノテーション統合、ローカル開発で動作させたいことです。
- そら
- ローカル開発で動かないと困るんですか?
- つむぎ
- allmaps.xyzのCloudflare WorkersからはlocalHostに到達できないため、ローカル検証では空の透明タイルが返ってきます。細かな調整ができないので自前レンダリングが必要でした。
APIの構成とエンドポイント
- ベースパス /api/iiif-wmts/ 配下に全エンドポイント
- ピクセル空間WMTS・地理座標WMTS・Georef・IIIF proxyの4カテゴリ
- そら
- どんなAPIを実装したんですか?
- つむぎ
- Next.jsのApp Routerで/api/iiif-wmts/配下に複数のエンドポイントを実装しました。大きく分けるとピクセル空間WMTS、地理座標WMTS、アノテーション取得、IIIFリバースプロキシです。
- そら
- ピクセル空間WMTSと地理座標WMTSはどう違うんですか?
- つむぎ
- ピクセル空間は地理参照なしでIIIF画像のピクセル座標系でタイル配信します。地理座標はジオリファレンスされた古地図をWeb MercatorのPNGタイルで配信します。
- そら
- Swagger UIで確認できるそうですが、どこで見られますか?
- つむぎ
- nakamura196-projects.vercel.app/ja/iiif-georef/docsでSwagger UIを公開しています。全エンドポイントを対話的に確認できます。
座標変換のハマりどころ
- GcpTransformerとProjectedGcpTransformerは別物
- transformToGeoとtransformToResourceは独立な最小二乗fit
- そら
- 実装中に難しかった点はありましたか?
- つむぎ
- 座標変換のずれが主な問題でした。@allmaps/transformのGcpTransformerと@allmaps/projectのProjectedGcpTransformerを混在させると4隅でずれが出ます。
- そら
- なぜずれが出るんですか?
- つむぎ
- @allmaps/renderのWarpedMapはProjectedGcpTransformerを使ってMercator空間でfitしていますが、アノテーション側でGcpTransformerのlon/lat空間fitを使っていたのが原因でした。
- そら
- さらにtransformToGeoとtransformToResourceも別物なんですね。
- つむぎ
- そうです。この2つは独立に最小二乗fittingされていて数学的逆ではありません。renderがtransformToResourceを使っているので、annotation側にはその数学的逆行列を使う必要がありました。
自前ホストの位置付けとまとめ
- 速度はallmaps.xyzが有利、自前はデータ主権・認証・ローカル開発に強み
- Allmapsを再実装する必要はなく、薄いラッパーを置くスタイル
- そら
- allmaps.xyzと自前実装、どちらを使うべきですか?
- つむぎ
- 速度面ではallmaps.xyzが有利です。コールドスタート時でも25ミリ秒程度で返ります。自前のNode RuntimeはコールドスタートがIIIF取得込みで10秒前後かかります。
- そら
- 自前実装の強みはどんな点ですか?
- つむぎ
- データ主権、認証やUAフィルタ下のIIIFへの対応、WMTS正規仕様対応、POIとアノテーション統合、ローカル開発での検証ができる点です。
- そら
- Allmapsを再実装するわけではないんですね。
- つむぎ
- そうです。Allmapsの上に薄いラッパーを置くスタイルです。@allmaps/renderや@allmaps/projectをそのまま使い、足りない機能だけを追加しています。
- そら
- ポートフォリオサイトと合わせて公開されているんですね。
- つむぎ
- はい。nakamura196-projects.vercel.appで実際に動いているデモを確認いただけます。