ホーム 記事一覧 ブック DH週間トピックス 検索 このサイトについて
English
Mirador:IIIF画像の比較・分析に最適なオープンソースビューア

Mirador:IIIF画像の比較・分析に最適なオープンソースビューア

はじめに デジタルヒューマニティーズの研究では、複数の資料を並べて比較検討することが頻繁に行われます。異なる写本を比較したり、修復前後の美術作品を並べて確認したりする場面では、高機能な画像ビューアが不可欠です。 本記事では、Stanford 大学と Harvard 大学が共同開発する IIIF 対応画像ビューア Mirador を紹介します。 Mirador とは Mirador は、IIIF(International Image Interoperability Framework)に対応した Web ベースの画像ビューアです。最大の特徴は、複数のウィンドウを同時に開いて画像を比較できるマルチウィンドウインターフェースです。 Apache 2.0 ライセンスで公開されており、学術機関を中心に世界中で広く利用されています。現在のバージョンは Mirador 3 で、React をベースとしたモダンなアーキテクチャで構築されています。 主な機能 マルチウィンドウ比較 Mirador のコア機能であるマルチウィンドウ表示により、複数の IIIF マニフェストから画像を同時に並べて比較できます。ウィンドウは自由にリサイズ・配置でき、研究者のワークスペースとして機能します。 アノテーション機能 IIIF のアノテーション仕様に対応しており、画像上に注釈を付けることができます。研究メモやタグ付けを画像に直接関連付けられるため、協調的な研究作業に適しています。 プラグインエコシステム Mirador 3 はプラグインアーキテクチャを採用しており、機能を拡張できます。代表的なプラグインには以下のようなものがあります。 mirador-image-tools — 画像の明るさ・コントラスト調整、反転、グレースケール変換 mirador-annotations — アノテーションの作成・編集 mirador-dl — 画像のダウンロード mirador-share — 共有リンクの生成 レイヤー表示 複数のレイヤーを重ねて表示する機能を備えており、例えば原本画像の上に翻刻テキストを重ねたり、異なる波長で撮影した画像を切り替えたりできます。 ドラッグ&ドロップ IIIF マニフェスト URL をドラッグ&ドロップでビューアに追加できます。異なる機関のコレクションから資料を集めて、一つのワークスペースで比較する作業が容易です。 導入方法 Mirador は npm パッケージとして提供されています。 npm install mirador React アプリケーションに組み込む場合は、以下のように設定します。 import Mirador from 'mirador'; const config = { id: 'mirador-viewer', windows: [{ manifestId: 'https://example.org/manifest.json' }] }; Mirador.viewer(config); DH における活用例 写本の比較研究 同じテキストの異なる写本を並べて表示し、文字の違いやレイアウトの差異を比較できます。中世ヨーロッパの写本研究や、日本の古典籍研究において効果的です。 ...

TETRAS-IIIF:Mirador 4向けアノテーション・動画・マルチユーザー拡張

TETRAS-IIIF:Mirador 4向けアノテーション・動画・マルチユーザー拡張

TETRAS-IIIFとは TETRAS-IIIFは、フランスのオープンソース企業Tetras Libre SARLを中心に開発が進められている、Mirador 4向けのプラグイン・ツール群です。アノテーション編集、動画対応、マルチユーザー協調など、Miradorの機能を大幅に拡張する複数のプロジェクトで構成されています。 従来のmirador-annotationsプラグインの課題を解決し、最新のReact 18/19、MUI 5/7に対応した次世代のアノテーション基盤を提供しています。 Mirador Annotation Editor(MAE) 概要 Mirador Annotation Editor(MAE)は、Mirador 4向けのアノテーション作成・編集プラグインです。従来のmirador-annotationsの後継として位置づけられており、Apache 2.0ライセンスで公開されています。 デモ: https://tetras-iiif.github.io/mirador-annotation-editor/ npm: mirador-annotation-editor 主な特徴 Konva.jsベースの描画エンジン mirador-annotationsがPaper.jsを使用していたのに対し、MAEはKonva.jsを採用しています。矩形、楕円、ポリゴン、フリーハンドなどの図形描画に加え、テキストや画像のオーバーレイにも対応しています。 テンプレートシステム MAEの特徴的な機能として「テンプレート」があります。アノテーションの構造をあらかじめ定義しておくことで、統一的なフォーマットでのアノテーション作成が可能になります。たとえば、コメントテンプレートでは見出しと本文を含むHTML構造が自動的に生成されます。 Dublin Coreメタデータ アノテーションにDublin Coreベースのメタデータを付与できます。作成者、日付、言語などの標準的なメタデータフィールドにより、アノテーションの管理・検索が容易になります。 アダプターアーキテクチャ アノテーションの永続化について柔軟なアダプター機構を備えています。ローカルストレージへの保存は標準で提供されており、IIIFアノテーションサーバーへの接続も可能です。 クロスマニフェストリンク 異なるマニフェスト間でアノテーションをリンクする機能を持ちます。これにより、複数のIIIFドキュメントにまたがるアノテーションのネットワークを構築できます。 MAEV(Mirador Annotation Editor for Video) 概要 MAEVは、MAEの機能を動画にまで拡張したプラグインです。IIIF Presentation API 3.0の動画コンテンツに対して、空間的・時間的なアノテーションを付与できます。 デモ: https://tetras-iiif.github.io/mirador-annotation-editor-video/ npm: mirador-annotation-editor-video ライセンス: GPL-3.0 動画アノテーションの特徴 動画アノテーションでは、画像アノテーションの空間的なターゲティング(画面上のどこ)に加えて、時間的なターゲティング(いつ)が可能です。特定の時刻範囲に限定したアノテーションを作成でき、動画の再生に合わせてアノテーションが表示されます。 MAEVの利用にはmirador-videoフォークが必要です。 mirador-video mirador-videoは、Mirador 4のフォークで、動画の表示・アノテーション・フィルタリング機能を追加したものです。React 18/19およびMUI 7に対応しており、Apache 2.0ライセンスで公開されています。 npmのエイリアス機能を使って、通常のMiradorの代わりにインストールできます。 npm install mirador@npm:mirador-video@^1.2.8 Mirador Multi User(MMU) 概要 Mirador Multi User(MMU)は、Miradorをマルチユーザー対応の協調ワークスペースに拡張するプラットフォームです。AGPL-3.0ライセンスで公開されています。 ライブインスタンス: https://app.mirador-multi-user.com/ Webサイト: https://www.mirador-multi-user.com/ 主な機能 ユーザー管理: ユーザーの登録・認証・権限管理 メディアコレクション管理: IIIFマニフェストの整理と共有 プロジェクトスナップショット: ワークスペースの状態を保存・復元 タグとテンプレート: プロジェクト単位でのアノテーションテンプレート管理 管理ダッシュボード: 利用状況の監視と管理 バックエンドはNestJSで構築され、MariaDBをデータベースとして使用しています。Docker/Caddyによるデプロイに対応しています。 ...

Mirador:IIIFコンテンツを比較・注釈できる高機能ビューア

Mirador:IIIFコンテンツを比較・注釈できる高機能ビューア

Miradorとは Miradorは、IIIF(International Image Interoperability Framework)に対応したオープンソースの画像ビューアです。MITライセンスで公開されており、ハーバード大学やスタンフォード大学をはじめとする世界中の大学、図書館、美術館、博物館で広く採用されています。 Miradorの最大の特徴は、複数の画像をマルチウィンドウで同時に表示し、比較・分析できる点にあります。デジタルヒューマニティーズの研究や、文化財のデジタルアーカイブにおいて欠かせないツールの一つとなっています。 主な機能 マルチウィンドウによる画像比較 Miradorのワークスペースでは、複数のウィンドウを自由に配置し、異なる資料を並べて比較することができます。たとえば、同じ写本の異なる所蔵機関のデジタル画像を横に並べて、テキストの異同を確認するといった作業が可能です。ウィンドウのサイズや配置は自由にドラッグ操作で変更でき、研究の目的に合わせた柔軟なレイアウトを構成できます。 高精細画像のディープズーム MiradorはOpenSeadragonを内部で使用しており、数万ピクセル規模の高精細画像でもスムーズに拡大・縮小・移動が可能です。IIIF Image APIに準拠した画像サーバーから、表示に必要な部分だけを動的に読み込むため、巨大な画像でもストレスなく閲覧できます。 アノテーション機能 IIIF Presentation API 3.0のアノテーション仕様に対応しており、画像上の特定領域にテキストやタグを付与できます。既存のアノテーションの閲覧だけでなく、プラグインを導入することで新規アノテーションの作成も可能です。研究者が画像の特定箇所についてコメントや分析結果を記録する用途に活用されています。 コンパニオンウィンドウ 各画像ウィンドウにはコンパニオンウィンドウと呼ばれるサイドパネルが備わっており、メタデータの表示、レイヤーの切り替え、目次(構造ナビゲーション)、検索などの機能を提供します。マニフェストに含まれるメタデータを確認しながら画像を閲覧できるため、資料の文脈を理解しやすくなっています。 デモを試してみよう Miradorの公式サイトでは、デモページが公開されています。ブラウザ上ですぐに試すことができるので、実際の操作感を確認するのに最適です。 デモページでは、あらかじめいくつかのIIIFマニフェストが読み込まれています。左上の「+」ボタンから新しいウィンドウを追加し、複数のコンテンツを並べて表示してみましょう。また、外部のIIIFマニフェストURLを入力して、任意のコンテンツを読み込むこともできます。 プラグインエコシステム Miradorはプラグインアーキテクチャを採用しており、機能を柔軟に拡張できます。コミュニティによって開発されているプラグインには以下のようなものがあります。 mirador-annotations: W3C Web Annotationに準拠したアノテーションの作成・編集 mirador-image-tools: 画像の明るさ・コントラスト調整、反転、グレースケール変換 mirador-share-plugin: ビューの共有URL生成 mirador-dl-plugin: 画像のダウンロード機能 プラグインはReactコンポーネントとして実装されており、JavaScriptの知識があれば独自のプラグインを開発することも可能です。 導入事例と活用シーン 大学・研究機関 ハーバード大学やスタンフォード大学、イェール大学など、多くの大学図書館がデジタルコレクションの閲覧インターフェースとしてMiradorを採用しています。手稿や古地図、歴史的写真などの高精細画像を、研究者が詳細に分析するためのツールとして活用されています。 美術館・博物館 絵画や工芸品のデジタル画像を高精細で提供する美術館でも採用が進んでいます。複数の作品を比較しながら鑑賞したり、修復前後の画像を並べて確認するといった活用が可能です。 デジタルヒューマニティーズ テキスト校訂、図像学的比較、地図の時系列比較など、デジタルヒューマニティーズの研究手法とIIIF・Miradorの親和性は非常に高いものがあります。異なる機関が所蔵する同一テキストの写本を並べて比較するなど、従来は物理的に困難だった作業をブラウザ上で実現できます。 技術的な特徴 Mirador 3はReactとReduxで構築されており、モダンなフロントエンドアーキテクチャを採用しています。IIIF Presentation API 3.0および2.1に対応しており、幅広いIIIFコンテンツを表示できます。また、npmパッケージとして公開されているため、既存のWebアプリケーションに組み込むことも容易です。 npm install mirador 設定はJSON形式で記述でき、表示するマニフェストやウィンドウの初期配置、UIの表示・非表示などを細かく制御できます。 まとめ Miradorは、IIIFエコシステムにおける中核的なビューアとして確固たる地位を築いています。マルチウィンドウ比較、ディープズーム、アノテーション、プラグイン拡張という豊富な機能を備えながら、オープンソースかつMITライセンスで提供されている点は大きな魅力です。 デジタルアーカイブやデジタルヒューマニティーズに関わる方はもちろん、高精細画像を扱うあらゆる分野の方にとって、Miradorは一度試してみる価値のあるツールです。まずはデモページで、その使い勝手を体験してみてください。

Mirador 4 で外部マニフェストのウィンドウタイトルだけを差し替える

Mirador 4 で外部マニフェストのウィンドウタイトルだけを差し替える

背景 Mirador は IIIF 対応の画像ビューアで、複数の IIIF マニフェストを並べて比較閲覧できる。複数機関が公開するマニフェストを一画面に並べて表示する際、各ウィンドウのタイトルにはマニフェストの label がそのまま表示される。 しかし、自プロジェクト独自の名称をウィンドウタイトルとして表示したいケースがある。例えば、マニフェストの label が個別の冊次情報を含む長い文字列であるのに対し、資料群を示す短い名称で表示したい場合などである。 制約:マニフェストの中身は変えてはいけない 他機関が公開している IIIF マニフェストを読み込んで表示する以上、その中身を改変して表示することは避けたい。fetch のインターセプトや Mirador 内部状態の書き換えでマニフェスト JSON の label を差し替える方法もあるが、これは実質的にマニフェストの改変にあたる。 変更すべきは Mirador が画面上に描画したウィンドウのタイトル表示(DOM)だけ であり、マニフェストのデータ自体はオリジナルのまま保持したい。 試したアプローチと結果 1. Mirador.actions.receiveManifest による内部状態の書き換え // Mirador の store を監視し、マニフェスト読み込み後に label を書き換え store.subscribe(function () { var state = store.getState(); if (manifests[manifestId] && manifests[manifestId].json && !overridden[manifestId]) { overridden[manifestId] = true; var updatedJson = JSON.parse(JSON.stringify(manifests[manifestId].json)); updatedJson.label = customTitle; store.dispatch(Mirador.actions.receiveManifest(manifestId, updatedJson)); } }); 結果:動作しない。 unpkg から配信される Mirador 4 の UMD ビルドでは Mirador.actions が undefined であり、この API は利用できなかった。 ...

Mirador ビューア埋め込み設定

Mirador ビューア埋め込み設定

IIIF画像の表示に Mirador ビューアを使用する方法について説明します。 参考実装 埋め込み方式は、Stanford University Libraries の Stanford Digital Repository を参考にしています。書誌情報の上部にビューアを埋め込み、メタデータと画像を同一ページで閲覧できるようにしています。 ファイル構成 apps/web/ ├── public/mirador/ │ └── index.html # Mirador ビューア本体 ├── src/components/item/ │ └── MiradorViewer.tsx # 埋め込みコンポーネント └── .env.local # 環境変数設定 URLパラメータ /mirador/index.html は以下のURLパラメータを受け付けます: パラメータ 説明 例 manifest IIIFマニフェストURL(必須)。セミコロン区切りで複数指定可能 https://example.com/iiif/manifest.json embed 埋め込みモード(trueで閉じるボタンと左側メニューを非表示) true theme テーマ(dark または light) dark lang 言語コード(デフォルト: ja) ja, en canvas 初期表示するキャンバスID - annotationState アノテーション表示モード(trueでサイドバー開く) true 使用例 /mirador/index.html?manifest=https://example.com/iiif/manifest.json&embed=true&theme=dark&lang=ja Mirador設定詳細 index.html の構成 DOCTYPE html> html lang="ja"> head> meta charset="utf-8" /> meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> title>Miradortitle> link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" /> head> body> div id="mirador" style="position: absolute; top: 0; bottom: 0; left: 0; right: 0">div> script src="https://unpkg.com/mirador@latest/dist/mirador.min.js">script> script> // 設定スクリプト script> body> html> URLパラメータの解析 var vars = {}; var param = location.search.substring(1).split("&"); for (var i = 0; i param.length; i++) { var keySearch = param[i].search(/=/); var key = ""; if (keySearch != -1) key = param[i].slice(0, keySearch); var val = param[i].slice(param[i].indexOf("=", 0) + 1); if (key != "") vars[key] = decodeURI(val); } ウィンドウ設定 var windows = []; if (vars["manifest"]) { var manifests = vars["manifest"]; var array = manifests.split(";"); // セミコロンで複数マニフェストを分割 for (var i = 0; i array.length; i++) { var manifest = decodeURIComponent(array[i]); var obj = { manifestId: manifest, thumbnailNavigationPosition: "far-right", // サムネイルを右端に表示 }; if (vars["canvas"]) { obj.canvasId = vars["canvas"]; // 初期表示キャンバス } windows.push(obj); } } ウィンドウ動作設定 var windowSettings = { allowClose: true, // 閉じるボタン表示 allowFullscreen: true, // 全画面ボタン表示 } // アノテーションモード if (vars["annotationState"]) { windowSettings.highlightAllAnnotations = true; windowSettings.sideBarOpen = true; windowSettings.defaultSideBarPanel = 'annotations'; } // 埋め込みモード: UIを簡素化 if (vars["embed"] === "true") { windowSettings.allowClose = false; windowSettings.allowMaximize = false; } ワークスペースコントロールパネル 左側のメニュー(マニフェスト追加、ワークスペース管理など)の表示制御: ...

Mirador 4用回転プラグインの開発とnpm公開

Mirador 4用回転プラグインの開発とnpm公開

はじめに IIIFビューアであるMiradorの最新版(Mirador 4)に対応した回転プラグイン「mirador-rotation」を開発し、npmで公開しました。本記事では、プラグインの開発から公開、そして実際に利用するための統合方法について解説します。 背景 Mirador 3からMirador 4へのメジャーアップデートに伴い、以下の変更がありました: React 16 → React 18 Material-UI v4 → MUI v7 その他多数の依存関係の更新 これにより、既存のMirador 3用プラグインはそのままでは動作しなくなりました。 mirador-rotation-pluginの開発 リポジトリ https://github.com/nakamura196/mirador-rotation-plugin 主な機能 画像の回転機能 Mirador 4のプラグインメニューへの統合 npmへの公開 開発したプラグインはnpmで公開しています: npm install mirador-rotation mirador-integrationの更新 公式のmirador-integrationリポジトリを参考に、Mirador 4対応の統合環境を構築しました。 主な変更点 項目 旧 新 Mirador 3.x 4.0.0 React 16.14.0 18.x ビルドツール Webpack Parcel UI Material-UI v4 MUI v7 package.json 最小限の依存関係で構成しています: { "dependencies": { "mirador": "^4.0.0", "mirador-rotation": "^4.0.0", "parcel": "^2.0.0", "react": "^18.0.0", "react-dom": "^18.0.0" } } 外部から利用するための工夫 問題 公式のmirador-integrationをそのままビルドすると、ESモジュール形式で出力されます。しかし、別のHTMLページから<script>タグで読み込んで使いたい場合、グローバル変数としてMiradorが定義されないという問題がありました。 script src="mirador.js">script> script> Mirador.viewer({...}); // Mirador is not defined script> 解決策 1. ライブラリ用エントリーポイントの作成 index.jsでグローバル変数として明示的にエクスポートします: ...

mirador-annotations を Mirador 4.x へ移行した記録

mirador-annotations を Mirador 4.x へ移行した記録

背景 mirador-annotations は、IIIF ビューア Mirador にアノテーション機能を追加するプラグインです。 従来のプロジェクトは以下の構成でした: ビルドツール : nwb (Create React App ベース) UI ライブラリ : Material-UI v4 Mirador : 3.x React : 17.x しかし、以下の問題が発生していました: nwb のメンテナンス停止 - nwb は長期間更新されておらず、依存関係の競合が頻発 npm install の失敗 - 古い依存関係により、新しい環境でのセットアップが困難に セキュリティ脆弱性 - 古いパッケージに多数の脆弱性警告 これらの問題を解決するため、以下への移行を決定しました: ビルドツール : Vite UI ライブラリ : MUI v7 Mirador : 4.x React : 18.x 移行作業の概要 1. ビルドツールの移行 (nwb → Vite) nwb の設定ファイルを削除し、vite.config.js を新規作成しました。 主なポイント: // vite.config.js export default defineConfig(({ mode }) => { const env = loadEnv(mode, process.cwd(), ''); return { // draft-js が global を参照するため define: { global: 'globalThis', }, // 重複パッケージの解決 resolve: { dedupe: [ '@emotion/react', '@emotion/styled', 'react', 'react-dom', ], }, }; }); 2. Material-UI の移行 (v4 → v7) @material-ui/* を @mui/* に変更 makeStyles を sx prop に置き換え Grid コンポーネントの API 変更に対応 (item と xs props が size に統合) // 変更前 (MUI v4) Grid item xs={12}> // 変更後 (MUI v7) Grid size={12}> 3. Mirador 4.x への対応 Mirador 4.x では、アクションやセレクターのインポート方法が変更されました: ...

mirador-rotation-plugin 機能拡張

mirador-rotation-plugin 機能拡張

概要 mirador-rotation-pluginに以下の機能を追加しました: 90度単位の回転ボタン URLパラメータによるマニフェスト・回転角度の指定 UIの改善(リセットボタンのアイコン変更) ヘルプ機能(使い方を説明するダイアログ) 新機能の詳細 1. 90度単位の回転ボタン 従来は1度単位のスライダーのみでしたが、90度単位で素早く回転できるボタンを追加しました。 実装内容 src/plugins/MiradorRotation.js に以下の変更を加えました: import RotateLeftIcon from '@mui/icons-material/RotateLeft'; import RotateRightIcon from '@mui/icons-material/RotateRight'; // 90度回転のハンドラー const handleRotate90 = (direction) => { const newRotation = rotation + (direction * 90); updateViewport(windowId, { rotation: newRotation }); }; UIには2つのボタンを追加: 左回転ボタン : 反時計回りに90度回転 右回転ボタン : 時計回りに90度回転 翻訳対応 src/translations.js に英語・日本語の翻訳を追加: { en: { rotateLeft: 'Rotate 90° left', rotateRight: 'Rotate 90° right', }, ja: { rotateLeft: '左に90度回転', rotateRight: '右に90度回転', }, } 2. URLパラメータ対応 デモページでURLパラメータからマニフェストと回転角度を指定できるようになりました。 対応パラメータ パラメータ 説明 区切り文字 manifest IIIFマニフェストURL ;(セミコロン) rotation 初期回転角度(度) ;(セミコロン) デモページURL https://nakamura196.github.io/mirador-rotation-plugin/ 使用例 # 単一マニフェスト https://nakamura196.github.io/mirador-rotation-plugin/?manifest=https://example.com/manifest.json&rotation=180 # 複数マニフェスト(同じ回転角度) https://nakamura196.github.io/mirador-rotation-plugin/?manifest=url1;url2&rotation=90 # 複数マニフェスト(異なる回転角度) https://nakamura196.github.io/mirador-rotation-plugin/?manifest=url1;url2&rotation=90;180 実装内容 demo/src/index.js の主な変更: ...

Mirador 4で任意の領域をハイライト表示する方法

Mirador 4で任意の領域をハイライト表示する方法

はじめに IIIFビューアのMiradorには検索機能があり、IIIF Search APIに対応したマニフェストでは検索結果をハイライト表示できます。しかし、Search APIに非対応のマニフェストでも、任意の領域をハイライト表示したいケースがあります。 本記事では、Miradorの内部APIを利用して、外部データソースからのアノテーション情報を基にハイライト表示を実現する方法を紹介します。 デモ Highlight Generator Form - フォームからハイライトを生成 ユースケース 独自のOCRシステムで抽出したテキスト領域のハイライト 機械学習で検出したオブジェクトの領域表示 外部データベースに保存されたアノテーションの可視化 Search API非対応のIIIFサーバーでの検索結果表示 実装方法 基本的な仕組み Miradorは内部でReduxを使用しており、receiveSearchアクションを通じて検索結果を登録できます。このアクションにIIIF Search API形式のJSONを渡すことで、任意のデータソースからのハイライトを表示できます。 必要な情報 ハイライトを表示するために必要な情報は以下の3つです: キャンバスURI - ハイライトを表示するページのURI 座標(xywh) - ハイライト領域の位置とサイズ(x, y, width, height) テキスト - ハイライトに関連付けるテキスト(検索パネルに表示される) サンプルコード 以下は、国立国会図書館デジタルコレクションの源氏物語で「いつれの御時にか…」の冒頭部分をハイライト表示するサンプルです。 <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Mirador Custom Highlight Sample</title> <style> body { margin: 0; padding: 0; } #mirador-viewer { width: 100%; height: 100vh; } </style> </head> <body> <div id="mirador-viewer"></div> <script src="https://unpkg.com/mirador@4.0.0-alpha.15/dist/mirador.min.js"></script> <script> // 設定パラメータ const config = { manifestUrl: 'https://dl.ndl.go.jp/api/iiif/3437686/manifest.json', canvasId: 'https://dl.ndl.go.jp/api/iiif/3437686/canvas/22', highlights: [ { xywh: '3095,694,97,2051', text: 'いつれの御時にか女御更衣あまたさふらひ給けるなかにいとやむことなきゝは', }, ], }; // Miradorを初期化 const miradorViewer = Mirador.viewer({ id: 'mirador-viewer', selectedTheme: 'light', language: 'ja', windows: [{ id: 'window-1', manifestId: config.manifestUrl, canvasId: config.canvasId, thumbnailNavigationPosition: 'far-right', }], window: { allowFullscreen: true, allowClose: false, allowMaximize: false, sideBarOpen: true, }, workspaceControlPanel: { enabled: false, }, }); // ハイライトを追加する関数 function addHighlights(viewer, canvasId, highlights) { // IIIF Search API形式のレスポンスを構築 const searchResponse = { '@context': 'http://iiif.io/api/search/1/context.json', '@id': canvasId + '/search', '@type': 'sc:AnnotationList', within: { '@type': 'sc:Layer', total: highlights.length, }, resources: highlights.map((highlight, index) => ({ '@id': canvasId + '/highlight-' + index, '@type': 'oa:Annotation', motivation: 'sc:painting', resource: { '@type': 'cnt:ContentAsText', chars: highlight.text, }, on: canvasId + '#xywh=' + highlight.xywh, })), }; // 検索パネルを右側に追加 const addAction = Mirador.addCompanionWindow('window-1', { content: 'search', position: 'right', }); viewer.store.dispatch(addAction); // companionWindowIdを取得 const state = viewer.store.getState(); const searchCompanionWindowId = Object.keys(state.companionWindows).find( id => state.companionWindows[id].content === 'search' ); if (searchCompanionWindowId) { // 検索結果を登録 const searchAction = Mirador.receiveSearch( 'window-1', searchCompanionWindowId, canvasId + '/search', searchResponse ); viewer.store.dispatch(searchAction); } } // マニフェストの読み込み完了を監視してハイライトを追加 let highlightAdded = false; const unsubscribe = miradorViewer.store.subscribe(() => { if (highlightAdded) return; const state = miradorViewer.store.getState(); const manifests = state.manifests || {}; const manifest = manifests[config.manifestUrl]; // マニフェストが読み込み完了したらハイライトを追加 if (manifest && !manifest.isFetching && manifest.json) { highlightAdded = true; unsubscribe(); addHighlights(miradorViewer, config.canvasId, config.highlights); } }); </script> </body> </html> コードの解説 1. 設定パラメータ const config = { manifestUrl: 'https://dl.ndl.go.jp/api/iiif/3437686/manifest.json', canvasId: 'https://dl.ndl.go.jp/api/iiif/3437686/canvas/22', highlights: [ { xywh: '3095,694,97,2051', text: 'いつれの御時にか...', }, ], }; manifestUrl: IIIFマニフェストのURL canvasId: ハイライトを表示するキャンバスのURI highlights: ハイライト情報の配列。複数のハイライトを追加可能 2. IIIF Search API形式のレスポンス構築 const searchResponse = { '@context': 'http://iiif.io/api/search/1/context.json', '@type': 'sc:AnnotationList', resources: highlights.map((highlight, index) => ({ '@type': 'oa:Annotation', motivation: 'sc:painting', resource: { '@type': 'cnt:ContentAsText', chars: highlight.text, }, on: canvasId + '#xywh=' + highlight.xywh, })), }; ポイントは on プロパティで、キャンバスURI#xywh=x,y,width,height の形式でハイライト領域を指定します。 ...

Mirador 4でキャンバス指定と検索語ハイライトを同時に実現する方法

Mirador 4でキャンバス指定と検索語ハイライトを同時に実現する方法

はじめに IIIF(International Image Interoperability Framework)ビューアとして広く使われているMiradorで、以下の要件を満たす実装を行いました: URLパラメータで指定したキャンバス(ページ)を初期表示する 指定したキャンバス内の検索語をハイライト表示する 本記事では、この要件を実現するためのアプローチと実装方法を共有します。 アプローチの検討 defaultSearchQueryオプション Mirador 4では、ウィンドウ設定に defaultSearchQuery オプションを指定することで、初期化時に自動的に検索を実行できます: const miradorViewer = Mirador.viewer({ windows: [{ manifestId: manifestUrl, canvasId: canvasId, defaultSearchQuery: '検索語', }], }); このオプションは検索を自動実行する便利な機能ですが、今回の要件では以下の点を考慮する必要がありました: ページ遷移の制御 - 検索実行時、最初のヒットのページに自動遷移する仕様のため、canvasId で指定したページに留まりたい場合は追加の制御が必要 検索完了タイミングの把握 - 非同期で検索が実行されるため、完了後に処理を行いたい場合はRedux状態の監視が必要 より直接的なアプローチ 検討の結果、receiveSearch アクションを直接使用するアプローチを採用しました。このアプローチでは: Search APIを直接呼び出して、指定キャンバスに該当するヒットのみを取得 IIIF Search API形式のレスポンスを構築 receiveSearch アクションで検索結果としてMiradorに登録 これにより、指定キャンバスの表示を維持しながら、Miradorの検索ハイライト機能をそのまま活用できます。 実装 1. Search APIからヒットを取得する関数 const getSearchHitsForCanvas = async ( manifestUrl: string, canvasId: string, query: string ): Promise<{ id: string; chars: string; xywh: string }[]> => { try { // manifestからsearch serviceのURLを取得 const manifestResponse = await fetch(manifestUrl); if (!manifestResponse.ok) return []; const manifest = await manifestResponse.json(); // IIIF Search API serviceを探す const services = manifest.service || []; const searchService = (Array.isArray(services) ? services : [services]).find( (s: { profile?: string }) => s.profile?.includes('search') ); if (!searchService) return []; const searchBaseUrl = searchService['@id'] || searchService.id; const searchUrl = `${searchBaseUrl}?q=${encodeURIComponent(query)}`; const response = await fetch(searchUrl); if (!response.ok) return []; const data = await response.json(); const resources = data.resources || []; // 指定キャンバスに該当するヒットのみを抽出 const hits: { id: string; chars: string; xywh: string }[] = []; for (const resource of resources) { const [resourceCanvas, fragment] = resource.on.split('#'); if (resourceCanvas === canvasId && fragment) { hits.push({ id: resource['@id'] || resource.id, chars: resource.resource?.chars || query, xywh: fragment.replace('xywh=', ''), }); } } return hits; } catch (error) { console.error('Failed to fetch search hits:', error); return []; } }; この実装では、manifestのserviceプロパティからIIIF Search APIのエンドポイントを動的に取得しています。これにより、任意のIIIF準拠サーバーで動作します。 ...

Miradorの表示方向を外部から制御する方法

Miradorの表示方向を外部から制御する方法

概要 Mirador viewerの表示方向(viewingDirection)をURLパラメータから動的に指定する実装について解説します。この機能により、同じマニフェストを左から右(left-to-right)または右から左(right-to-left)で表示することができます。 実装方法 1. URLパラメータの取得 URLからviewingDirectionパラメータを取得し、デフォルト値を設定します: // URLパラメータから表示方向を取得 const urlParams = new URLSearchParams(window.location.search); const viewingDirection = urlParams.get('viewingDirection') || 'right-to-left'; この実装では、パラメータが指定されていない場合は'right-to-left'(右から左)がデフォルトとして使用されます。 2. Mirador設定への適用 取得したviewingDirectionをMiradorの初期設定に組み込みます: const miradorConfig = { id: "viewer", windows: [{ id: 'known-window-id', loadedManifest: manifestUrl, viewingDirection: viewingDirection, // URLパラメータの値を使用 }], window: { allowClose: false, allowMaximize: false, allowFullscreen: false, hideWindowTitle: true, }, workspaceControlPanel: { enabled: false, }, }; 3. 使用例 右から左表示(デフォルト) https://example.com/viewer.xml または https://example.com/viewer.xml?viewingDirection=right-to-left 左から右表示 https://example.com/viewer.xml?viewingDirection=left-to-right XSLTでの実装 XSLTテンプレート内でこの機能を実装する場合、以下のコードをスクリプトセクションに追加します(mirador.xsl:222-230): <!-- URLパラメータから表示方向を取得 --> const viewingDirection = urlParams.get('viewingDirection') || 'right-to-left'; // Miradorの初期設定 const miradorConfig = { id: "viewer", windows: [{ id: 'known-window-id', loadedManifest: manifestUrl, viewingDirection: viewingDirection, }], // ... その他の設定 }; 利用可能な値 MiradorのviewingDirectionには以下の値が使用できます: left-to-right - 左から右へページをめくる(欧文書籍など) right-to-left - 右から左へページをめくる(和書、アラビア語書籍など) top-to-bottom - 上から下へ(巻物など) bottom-to-top - 下から上へ 注意点 マニフェストファイル内でviewingDirectionが指定されている場合、マニフェストの設定が優先されます。この方法は主にマニフェストファイル内で表示方向が指定されていない場合に有効です この設定はwindow単位で適用されます URLパラメータはページ読み込み時にのみ評価されます ユーザーがMirador UI上で表示方向を変更した場合、URLパラメータの値は上書きされます 関連ファイル xsl/mirador.xsl - XSLT変換テンプレート(実装箇所)

IIIF画像に対して、多角形のアノテーションを付与するツールを作成しました。

IIIF画像に対して、多角形のアノテーションを付与するツールを作成しました。

概要 IIIF画像に対して、多角形のアノテーションを付与するツールを作成しました。 https://next-fb-anno.vercel.app/ 本記事では、このツールについて説明します。 使い方 以下がトップ画面です。IIIFマニフェストファイルのURLを入力します。「入力例を使用」からもお試しいただけます。『百鬼夜行図』(東京大学総合図書館所蔵)を使用しています。 以下のようなアノテーション登録画面が表示されます。 画面右上のログインボタンからログインできます。 アノテーション付与の方法は、以下の動画を参考にしてください。 https://youtu.be/9RMqaXTaOzE 開発した背景 以下の記事で説明したように、Mirador 3の mirador-annotations プラグイン向けに、Firestore用のアダプタを開発しました。 このmirador-annotations プラグインについて、多角形のアノテーション付与を行いづらいという意見がありました。 そこで、主に多角形のアノテーション付与を支援するために、本ツールを開発しました。また、アノテーション付与を実装するためのライブラリであるAnnotoriousについて、Reactライブラリが公開されていたので、この調査も兼ねて実装しました。 https://annotorious.dev/react/openseadragon-iiif/ さらに、上記の記事で紹介したmirador-annotations プラグインのFirestore用のアダプタを流用することで、同じFirebaseのサービス(AuthenticationとFirestore)を使用するようにしました。 そのため、本ツールの右上のボタンに、Miradorへのリンクを付与しました。 これにより、本ツールで編集を行い、IIIFマニフェストファイルのメタデータを含む、情報の表示にはMiradorを使用する、といった使い方が可能になるかと思います。 多角形のアノテーションを付与するための既存ツール IIIF画像に対してアノテーションを付与する機能を持つ既存ツールは数多く存在します。ここでは、IIIF画像に対して多角形のアノテーションを付与する機能を有するツールと、本ツールとの差分を紹介します。 ここでは、国立国会図書館で公開されている「和泉国絵図」を例とします。 Omeka Classic + IIIF Toolkit 以下の記事でセットアップ方法や使い方を紹介しています。 https://zenn.dev/nakamura196/books/2a0aa162dcd0eb IIIF Toolkitでは、Mirador 2が使用されており、ポリゴンアノテーションが提供されています。 今回にニーズに対しては、多角形アノテーションではなくポリゴンアノテーションである点と、Omeka Classicのセットアップ(サーバの準備や維持)が必要になる点が課題として挙げられます。 Recogito Recogitoでは傾斜したボックス形式のアノテーションを付与することはできましたが、多角形のアノテーション付与はできないようでした。 また、以下のように、pctを用いてIIIF画像にアクセスするようで、画像が表示できないケースが多くありました。 Glycerine: Image Annotation Workbench 本ツールが最も今回のニーズに合致していました。 https://glycerine.io/ おそらく本ツールと同じ「Annotorious(のver.2)」が使用されており、多角形によるアノテーションのほか、複数人による共同作業も可能でした。 唯一の課題として、登録したアノテーションの一括登録機能が提供されていませんでした。この点に対して、今回開発したツールでは、読み込んだIIIFマニフェストファイルに対して、ログインユーザが登録したユーザが付与したアノテーションを一括エクスポートする機能を設けました。 これにより、本ツールで付与したアノテーションを一括エクスポートし、他の可視化ツールで使用する、といった使い方が容易になります。 なお、以下の記事で紹介したように、Mirador 3の mirador-annotations プラグインにも付与したアノテーションをダウンロードする機能が提供されています。しかい、この機能はCanvasごとにダウンロードする仕様となっており、複数ページから構成される場合には、ページごとにダウンロードする必要がありました。 工夫点および開発メモ 本ツールの開発にあたり、工夫した点などを紹介します。 入力するIIIFマニフェストのv2およびv3対応 入力するIIIFマニフェストファイルはv2とv3、どちらでも対応できるようにしました。この実現にあたり、以下の記事で紹介した@iiif/parserを使用しました。 ...

Mirador 4プラグイン開発:任意の角度で画像を回転するプラグインで、角度の初期値を設定できるようにしました。

Mirador 4プラグイン開発:任意の角度で画像を回転するプラグインで、角度の初期値を設定できるようにしました。

概要 任意の角度で画像を回転するMirador 4プラグインで、角度の初期値を設定できるようにしました。 リポジトリは以下です。 https://github.com/nakamura196/mirador-rotation-plugin デモページは以下です。角度および矩形を初期設定とともに、画像を回転させることができます。 https://nakamura196.github.io/mirador-rotation-plugin/ 背景 以下の記事で、本プラグインについて説明しています。 一方、課題として、角度の初期値を与えることができませんでした。 これに対して、以下の記事で紹介したように、Mirador 4の標準機能として、角度の初期値を与えることができるようでした。 合わせて、以下の「mirador-image-tools」プラグインについて、webpackからViteに変更されていたので、この変更を「mirador-rotation-plugin」にも反映することにしました。 https://github.com/ProjectMirador/mirador-image-tools GitHub Pagesでの公開 GitHub Pagesでの公開にあたり、「mirador-image-tools」のvite.config.jsを以下のように変更しています。これで、npm run build:demoにより、GitHub Pagesで公開するためのディレクトリを作成することができるようになりました。 https://github.com/nakamura196/mirador-rotation-plugin/blob/main/vite.config.js import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import fs from 'fs/promises'; import path from 'node:path'; import { fileURLToPath } from 'url'; import { globSync } from 'glob'; import pkg from './package.json'; /** * Vite configuration */ export default defineConfig({ base: process.env.GITHUB_PAGES ? (process.env.BASE_PATH || '/mirador-rotation-plugin/') : '/', ...( process.env.GITHUB_PAGES ? { build: { outDir: 'dist', emptyOutDir: true, rollupOptions: { external: ['__tests__/*', '__mocks__/*'], input: fileURLToPath(new URL('./demo/src/index.html', import.meta.url)), }, sourcemap: true, }, } : { build: { lib: { entry: './src/index.js', fileName: (format) => (format === 'umd' ? 'mirador-rotation.js' : 'mirador-rotation.es.js'), formats: ['es', 'umd'], name: 'MiradorDlPlugin', }, rollupOptions: { external: [...Object.keys(pkg.peerDependencies || {}), '__tests__/*', '__mocks__/*'], output: { assetFileNames: 'mirador-rotation.[ext]', globals: { react: 'React', 'react-dom': 'ReactDOM', }, }, }, sourcemap: true, }, } ), esbuild: { exclude: [], // Matches .js and .jsx in __tests__ and .jsx in src include: [/__tests__\/.*\.(js|jsx)$/, /src\/.*\.jsx?$/], loader: 'jsx', }, optimizeDeps: { esbuildOptions: { plugins: [ { name: 'load-js-files-as-jsx', // TODO: rename all our files to .jsx ... setup(build) { build.onLoad({ filter: /(src|__tests__)\/.*\.js$/ }, async (args) => ({ contents: await fs.readFile(args.path, 'utf8'), loader: 'jsx', })); }, }, ], }, }, plugins: [ react(), // カスタムプラグインを追加してディレクトリ構造を修正 { name: 'fix-output-structure', closeBundle: async () => { if (process.env.GITHUB_PAGES) { const distDir = path.resolve('dist'); const demoSrcDir = path.resolve(distDir, 'demo', 'src'); // demo/src/ディレクトリが存在するか確認 try { const demoSrcStats = await fs.stat(demoSrcDir); if (demoSrcStats.isDirectory()) { console.log('Moving files from demo/src to root directory...'); // demo/src内のファイルリストを取得 const files = await fs.readdir(demoSrcDir); // 各ファイルをルートディレクトリに移動 for (const file of files) { const srcPath = path.join(demoSrcDir, file); const destPath = path.join(distDir, file); const stats = await fs.stat(srcPath); if (stats.isFile()) { await fs.copyFile(srcPath, destPath); console.log(`Copied: ${srcPath} -> ${destPath}`); } } console.log('Files moved successfully.'); // demo/src階層を削除(オプション) // await fs.rm(demoSrcDir, { recursive: true, force: true }); // await fs.rm(path.resolve(distDir, 'demo'), { recursive: true, force: true }); // console.log('Removed original directory structure.'); } } catch (err) { if (err.code !== 'ENOENT') { console.error('Error processing output files:', err); } } } } } ], resolve: { alias: { '@tests/': fileURLToPath(new URL('./__tests__', import.meta.url)), }, }, server: { open: '/demo/src/index.html', port: '4446', }, }); まとめ Mirador 4のプラグイン開発にあたり、参考になりましたら幸いです。 ...

Mirador 4で、初期読み込み時に、画像の回転や範囲指定を行う

Mirador 4で、初期読み込み時に、画像の回転や範囲指定を行う

概要 Mirador 4で、初期読み込み時に、画像の回転や範囲指定を行う方法を紹介します。 背景 2025年3月現在、Mirador 4の開発が進められています。alpha版を以下で確認することができます。 https://github.com/ProjectMirador/mirador/releases おそらくMirador 4からの機能かと思いますが、以下のFAQで初期設定の方法が記述されています。 https://github.com/ProjectMirador/mirador/wiki/Frequently-Asked-Questions#q-how-do-i-change-the-view-of-an-image-to-zoom-to-a-certain-area 具体的には、以下のように、initialViewerConfigを用いることで、初期設定ができました。 https://github.com/ProjectMirador/mirador/blob/main/__tests__/integration/mirador/mirador-configs/initial-viewer-config.js export default { id: 'mirador', windows: [{ canvasId: 'https://iiif.harvardartmuseums.org/manifests/object/299843/canvas/canvas-47174892', initialViewerConfig: { thumbnailNavigationPosition: 'far-bottom', x: 934, y: 782, // you need to specify zoom for this to look good zoom: 0.0007, }, manifestId: 'https://iiif.harvardartmuseums.org/manifests/object/299843', }], }; 応用 上記を応用して、以下のような初期設定を行ってみました。 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="theme-color" content="#000000"> <title>Mirador - Table of contents</title> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500"> </head> <body> <div id="mirador" style="position: absolute; top: 0; bottom: 0; left: 0; right: 0;"></div> <script type="module"> import Mirador from '../../../src'; // import config from './mirador-configs/initial-viewer-config.js'; const xywh = '9554.0,8213.0,1000,1000'; const spl = xywh.split(','); // Box to zoom to const boxToZoom = { height: Number(spl[3]), width: Number(spl[2]), x: Number(spl[0]), y: Number(spl[1]) }; const zoomCenter = { x: boxToZoom.x + boxToZoom.width / 2, y: boxToZoom.y + boxToZoom.height / 2 }; const config = { id: 'mirador', windows: [{ canvasId: "https://iiif.dl.itc.u-tokyo.ac.jp/repo/iiif/187cc82d-11e6-9912-9dd4-b4cca9b10970/canvas/p2", initialViewerConfig: { rotation: 180, x: zoomCenter.x, y: zoomCenter.y, zoom: 1 / Math.max(boxToZoom.width, boxToZoom.height) }, // manifestId: 'https://purl.stanford.edu/sn904cj3429/iiif/manifest', manifestId: "https://iiif.dl.itc.u-tokyo.ac.jp/repo/iiif/187cc82d-11e6-9912-9dd4-b4cca9b10970/manifest", }], }; Mirador.viewer(config); </script> </body> </html> これにより、わかりにくいですが、以下のように、180度回転しつつ、xywhにフォーカスした形で初期読み込みできました。 ...

Miradorで画像を表示し、CETEIceanでテキストを表示するサンプルアプリ

Miradorで画像を表示し、CETEIceanでテキストを表示するサンプルアプリ

概要 TEI/XMLファイルを読み込み、Miradorで画像を表示し、CETEIceanでテキストを表示するサンプルアプリを作成しました。以下のURLからお試しいただけます。 デモサイト https://nakamura196.github.io/ceteicean-mirador/ 背景 これまでにも、同様の機能を提供するアプリケーションを開発してきました。 Next.js を使用した実装例 XSLT を使用した実装例 今回は、HTMLとプレーンなJavaScriptのみを使用して実装する方法をご紹介します。 対象データ 以下の校異源氏物語テキストDBを対象とします。 https://kouigenjimonogatari.github.io/ 実装方法 ソースコードは以下のリポジトリで公開しています。 https://github.com/nakamura196/ceteicean-mirador 実装のポイント 1. CETEIcean の behaviors を利用した pb タグの処理 以下のコードでは、CETEIcean の behaviors を利用して pb タグのクリック時の挙動を定義しています。 ct.addBehaviors({ tei: { // 不要な要素を非表示 graphic: () => document.createDocumentFragment(), figure: () => document.createDocumentFragment(), // pbタグの処理 pb: function (el) { let pb = document.createElement("tei-pb"); // 属性を引き継ぐ if (el.hasAttribute("n")) { pb.setAttribute("n", el.getAttribute("n")); } // corresp属性からzoneIdを取得 const corresp = el.getAttribute("corresp"); if (corresp) { const zoneId = corresp.replace('#', ''); pb.setAttribute("data-zone-id", zoneId); } // ページ番号を表示 const pageNum = el.getAttribute("n") || ""; pb.textContent = `[Page ${pageNum}]`; // クリックイベントを追加 pb.addEventListener("click", function() { const zoneId = this.getAttribute("data-zone-id"); if (zoneId) { const zoneElement = document.querySelector(`tei-zone[id="${zoneId}"]`); if (zoneElement) { const surfaceElement = zoneElement.closest("tei-surface"); if (surfaceElement && surfaceElement.hasAttribute("sameAs")) { goToPage(surfaceElement.getAttribute("sameAs")); } } } }); return pb; } }, }); 2. Mirador でのページ遷移処理 pb タグをクリックした際に、TEI/XML ファイルから Canvas の URI を取得し、Mirador のページ遷移を実行します。 ...

Mirador3のFirebase連携annotationsプラグインにおいて、メールアドレスによる登録を可能にしました。

Mirador3のFirebase連携annotationsプラグインにおいて、メールアドレスによる登録を可能にしました。

概要 Mirador3のFirebase連携annotationsプラグインを開発しています。 こちらについて、これまではGoogleアカウントによるログイン機能のみを提供していましたが、メールアドレスによるログイン機能を追加しました。 機能紹介 以下、ログインボタンを押した場合です。 メールアドレスによるログインの場合、アカウントの新規作成が可能です。 ログイン後、ユーザに関する情報を表示するようにしました。 アイコンをクリックすると、ログアウトボタンが表示されます。 まとめ IIIFを用いたアノテーションの作成と共有において、参考になりましたら幸いです。

Mirador 3の mirador-annotations プラグインで、付与したアノテーションをダウンロードする

Mirador 3の mirador-annotations プラグインで、付与したアノテーションをダウンロードする

概要 Mirador 3の mirador-annotations プラグインで、付与したアノテーションをダウンロードするための設定に関する備忘録です。 https://mirador-annotations.vercel.app/ 背景 以下の記事で、アノテーションをGoogleのFirestoreに登録する方法を紹介しました。 ここで登録したアノテーションをダウンロードするにあたり、mirador-annotationsプラグインでダウンロードオプションが提供されていたので、その方法について紹介します。 方法 以下がデモページのソースコードになりますが、exportLocalStorageAnnotationsというオプションをtrueにすることで、ダウンロードアイコンが表示されました。 import mirador from 'mirador/dist/es/src/index'; import annotationPlugins from '../../src'; import LocalStorageAdapter from '../../src/LocalStorageAdapter'; import AnnototAdapter from '../../src/AnnototAdapter'; const endpointUrl = 'http://127.0.0.1:3000/annotations'; const config = { annotation: { adapter: (canvasId) => new LocalStorageAdapter(`localStorage://?canvasId=${canvasId}`), // adapter: (canvasId) => new AnnototAdapter(canvasId, endpointUrl), exportLocalStorageAnnotations: false, // display annotation JSON export button }, id: 'demo', window: { defaultSideBarPanel: 'annotations', sideBarOpenByDefault: true, }, windows: [{ loadedManifest: 'https://iiif.harvardartmuseums.org/manifests/object/299843', }], }; mirador.viewer(config, [...annotationPlugins]); ダウンロードによって得られるJSONファイルの例は以下です。canvas毎にダウンロードできます。 { "id": "https://dl.ndl.go.jp/api/iiif/3437686/canvas/1/annotations", "items": [ { "body": { "type": "TextualBody", "value": "<p>Cを変更</p>" }, "type": "Annotation", "motivation": "commenting", "target": { "selector": [ { "type": "FragmentSelector", "value": "xywh=5314,1983,195,206" }, { "type": "SvgSelector", "value": "<svg xmlns='http://www.w3.org/2000/svg'><path xmlns=\"http://www.w3.org/2000/svg\" d=\"M5314.21383,2086.96256c0,-56.89385 43.74418,-103.01543 97.70536,-103.01543c53.96118,0 97.70536,46.12158 97.70536,103.01543c0,56.89385 -43.74418,103.01543 -97.70536,103.01543c-53.96118,0 -97.70536,-46.12158 -97.70536,-103.01543z\" data-paper-data=\"{"state":null}\" fill=\"none\" fill-rule=\"nonzero\" stroke=\"#00bfff\" stroke-width=\"3\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\" stroke-miterlimit=\"10\" stroke-dasharray=\"\" stroke-dashoffset=\"0\" font-family=\"none\" font-weight=\"none\" font-size=\"none\" text-anchor=\"none\" style=\"mix-blend-mode: normal\"/></svg>" } ], "source": { "id": "https://dl.ndl.go.jp/api/iiif/3437686/canvas/1", "type": "Canvas", "partOf": { "id": "https://dl.ndl.go.jp/api/iiif/3437686/manifest.json", "type": "Manifest" } } }, "canvasId": "https://dl.ndl.go.jp/api/iiif/3437686/canvas/1", "created": { "seconds": 1739524276, "nanoseconds": 522000000 }, "id": "exlXeaswdsiuhcFiLWSl", "userName": "中村覚", "manifestId": "https://dl.ndl.go.jp/api/iiif/3437686/manifest.json", "modified": { "seconds": 1739526046, "nanoseconds": 354000000 } }, { "motivation": "commenting", "id": "rx2JMkwtwuQDgbtAIOoO", "created": { "seconds": 1739524259, "nanoseconds": 611000000 }, "manifestId": "https://dl.ndl.go.jp/api/iiif/3437686/manifest.json", "body": { "type": "TextualBody", "value": "<p>校異源氏物語</p>" }, "userName": "中村覚", "canvasId": "https://dl.ndl.go.jp/api/iiif/3437686/canvas/1", "target": { "selector": [ { "type": "FragmentSelector", "value": "xywh=478,307,748,3424" }, { "value": "<svg xmlns='http://www.w3.org/2000/svg'><path xmlns=\"http://www.w3.org/2000/svg\" d=\"M478.38073,3732.45418v-3424.85175h748.39353v3424.85175z\" data-paper-data=\"{"state":null}\" fill=\"none\" fill-rule=\"nonzero\" stroke=\"#00bfff\" stroke-width=\"3\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\" stroke-miterlimit=\"10\" stroke-dasharray=\"\" stroke-dashoffset=\"0\" font-family=\"none\" font-weight=\"none\" font-size=\"none\" text-anchor=\"none\" style=\"mix-blend-mode: normal\"/></svg>", "type": "SvgSelector" } ], "source": { "partOf": { "id": "https://dl.ndl.go.jp/api/iiif/3437686/manifest.json", "type": "Manifest" }, "type": "Canvas", "id": "https://dl.ndl.go.jp/api/iiif/3437686/canvas/1" } }, "modified": { "seconds": 1739524259, "nanoseconds": 611000000 }, "type": "Annotation" } ], "type": "AnnotationPage" } まとめ Mirador 3の mirador-annotations プラグインの利用にあたり、参考になりましたら幸いです。 ...

Mirador 3の mirador-annotations プラグイン向けに、Firestore用のアダプタを開発しました。

Mirador 3の mirador-annotations プラグイン向けに、Firestore用のアダプタを開発しました。

概要 Mirador 3の mirador-annotations プラグイン向けに、Firestore用のアダプタを開発したので備忘録です。以下でお試しいただけます。 https://mirador-annotations.vercel.app/ 背景 Mirador 3の mirador-annotations プラグインは、デフォルトではローカルストレージにアノテーションが保存されます。 一方、以下の記事で紹介したように、アダプタを変更することで、ローカルストレージではない場所にアノテーションを保存することもできます。 そこで、今回はGoogleのFirestoreに保存するためのアダプタを開発しました。 使い方 ユーザごとにアノテーションを保存できる仕組みとしました。 そのため、まず以下のボタンから、ログインを行います。 ログイン後、自分が付与したアノテーションが表示されます。 アノテーションの登録方法に違いはありません。 ログアウトすると、アノテーションが非表示となります。 リポジトリ ソースコードは以下で公開しています。 https://github.com/nakamura196/mirador-annotations 特に、以下が今回開発したアダプタです。 https://github.com/nakamura196/mirador-annotations/blob/master/src/FirestoreAnnotationAdapter.js また、以下がログインを行うためのボタンです。 https://github.com/nakamura196/mirador-annotations/blob/master/src/GoogleAuthButton.js 開発される際には、.env.exampleを参考に、FirebaseのAPIキーなどを.envに記入します。 https://github.com/nakamura196/mirador-annotations/blob/master/.env.example まとめ 本アプリを使用することで、ユーザごとに、IIIF画像に対するアノテーションを簡単に管理できるようになると思います。 なお、冒頭でご紹介した本アプリのデモ環境に登録されたデータは任意のタイミングで削除する可能性があるのでご注意ください。

XSLTを使ってIIIFとTEIの対照表示を実現する

XSLTを使ってIIIFとTEIの対照表示を実現する

概要 XSLTを使ってIIIFとTEIの対照表示を実現してみる機会がありましたので、備忘録です。 結果は以下からご確認いただけます。「校異源氏物語テキストDB」を利用しています。 https://kouigenjimonogatari.github.io/xml/xsl/01.xml 背景 TEI/XMLの可視化にあたって、これまでは、TEI XMLをHTMLに変換してブラウザ上で表示するためのJavaScriptライブラリであるCETEICeanを使うことが多かったです。 これらの取り組みではJavaScriptのフレームワークと合わせて、柔軟な開発が可能でした。 しかし、この方法ではTEI/XMLとは別に、ビューアのデプロイが必要であるなど、課題を感じる点もありました。 対策 そこで、XSLTを使ったIIIFとTEIの対照表示に取り組みました。以下のXSLファイルを用意しました。実装にあたっては、ChatGPTを利用しました。 https://github.com/kouigenjimonogatari/kouigenjimonogatari.github.io/blob/master/xsl/mirador.xsl そして、XMLファイルからは、以下のように参照します。相対パスとなっている点は、適宜読み替えてください。 <?xml version="1.0" ?> ... <?xml-stylesheet type="text/xsl" href="../../xsl/mirador.xsl"?> <TEI xmlns="http://www.tei-c.org/ns/1.0"> <teiHeader> <fileDesc> <titleStmt> <title>校異源氏物語・きりつぼ</title> <author>池田亀鑑</author> ... これにより、以下のようなXMLファイルをブラウザで表示すると、 https://kouigenjimonogatari.github.io/xml/xsl/01.xml 以下のように、IIIFとTEIの対照表示を実現することができました。ページのリンクやMiradorビューアの前後ボタンのクリックにより、テキストと画像が同期します。 このようにXSLTによる可視化を行うことにより、別途のビューア開発やデプロイが不要となり、またxslファイルの更新による容易なカスタマイズを実現することができました。 考察 Next.jsのようなフレームワークとCETEIceanを組み合わせてビューアを作成する方法と、本記事で紹介したようなXSLTを使った可視化方法について、ChatGPTに使い分けを聞いてみました。 結果、以下のように、比較的単純な可視化ではXSLT、高度なインタクラションが求められる場合はCETEIcean、を選択するのがよさそうでした。 1. 高度なインタラクションが必要な場合: Next.js + CETEIcean Next.js はReactベースのフレームワークで、クライアントサイドレンダリングやサーバーサイドレンダリング、APIの統合などを柔軟に行えます。Next.jsを使うと、複雑なUIや状態管理、ナビゲーション、動的なデータ処理が必要なアプリケーションの構築が簡単です。 CETEIcean は、TEI XMLをそのままHTMLにレンダリングするためのライブラリで、特にクライアントサイドでTEIを動的に表示したい場合に便利です。CETEIceanを使うと、JavaScriptを使ってTEI要素を直接操作できるため、ユーザーがクリックした際に特定のページに遷移したり、アノテーションの追加など、インタラクティブな機能を実装できます。 利点 : リッチなインタラクション(ページナビゲーション、フィルタリング、ユーザーの操作に応じた動的なUIの更新など)が容易。 コンポーネントベースの設計が可能で、保守性が高く再利用性も高い。 さまざまなJavaScriptライブラリやプラグイン(Mirador、Annotoriousなど)との統合が容易。 2. 単純な表示や静的な構造でよい場合: XSLT XSLT は、XMLデータをHTMLなどに変換するためのテンプレート言語で、サーバーサイドまたはクライアントサイドでの静的な表示に適しています。XSLTを使用すると、TEI XMLをシンプルなHTMLとして表示できます。 利点 : 軽量で設定がシンプル。ブラウザがXSLTをサポートしていれば、特別な環境を必要とせずに、直接HTML表示が可能。 HTMLとして生成されるため、CSSによるスタイルの適用が容易で、簡単なナビゲーションや静的なページリンク程度なら実装も比較的簡単。 静的なレポートや閲覧専用のデータの表示に最適。 判断基準のまとめ 高度な機能やインタラクティブな要素が求められる :Next.js + CETEIcean 例:クリックやスクロールに応じて動的にデータをロード、複数のナビゲーションや検索機能の提供、アノテーションや画像ビューワーの統合。 単純な表示がメイン :XSLT 例:TEIドキュメントをただ表示するだけ、特定の要素にスタイルを適用して閲覧しやすくする、シンプルなページナビゲーション。 まとめ ビューアを使用せずに、TEI/XMLファイルとXSLファイルのみで閲覧環境を実現することは、管理や運用コストの低減にもつながるように思いました。 ...

IIIF Presentation API v3でsvgを使ったアノテーション記述

IIIF Presentation API v3でsvgを使ったアノテーション記述

概要 IIIF Presentation API v3でsvgを使ったアノテーション記述を行う機会がありましたので、備忘録です。 方法 以下のように記述することで、svgを使ったアノテーションを表示することができました。 { "@context": "http://iiif.io/api/presentation/3/context.json", "id": "http://127.0.0.1:62816/api/iiif/3/11/manifest", "type": "Manifest", "label": { "none": [ "きりつぼ" ] }, "rights": "http://creativecommons.org/licenses/by/4.0/", "requiredStatement": { "label": { "none": [ "Attribution" ] }, "value": { "none": [ "Provided by Example Organization" ] } }, "items": [ { "id": "http://127.0.0.1:62816/api/iiif/3/11/canvas/p1", "type": "Canvas", "width": 6642, "height": 4990, "label": { "none": [ "[1]" ] }, "thumbnail": [ { "format": "image/jpeg", "id": "https://iiif.dl.itc.u-tokyo.ac.jp/iiif/genji/TIFF/A00_6587/01/01_0023.tif/full/200,/0/default.jpg", "type": "Image" } ], "annotations": [ { "id": "http://127.0.0.1:62816/api/iiif/3/11/canvas/p1/annos", "type": "AnnotationPage", "items": [ { "id": "http://127.0.0.1:62816/api/iiif/3/11/canvas/p1/annos/1", "type": "Annotation", "motivation": "commenting", "body": { "type": "TextualBody", "value": "<p>校異源氏物語 p.21 開始位置</p><p><a href=\"http://dl.ndl.go.jp/info:ndljp/pid/3437686/30\">国立国会図書館デジタルコレクション</a>でみる</p>" }, "target": { "source": "http://127.0.0.1:62816/api/iiif/3/11/canvas/p1", "type": "SpecificResource", "selector": { "type": "SvgSelector", "value": "<svg xmlns='http://www.w3.org/2000/svg'><path xmlns=\"http://www.w3.org/2000/svg\" d=\"M2798,1309c0,-34 17,-68 51,-102c0,-34 -17,-51 -51,-51c-34,0 -51,17 -51,51c34,34 51,68 51,102z\" id=\"pin_abc\" fill-opacity=\"0.5\" fill=\"#F3AA00\" stroke=\"#f38200\"/></svg>" } } } ] } ], "items": [ { "id": "http://127.0.0.1:62816/api/iiif/3/11/canvas/p1/page", "type": "AnnotationPage", "items": [ { "id": "http://127.0.0.1:62816/api/iiif/3/11/canvas/p1/page/imageanno", "type": "Annotation", "motivation": "painting", "body": { "id": "http://127.0.0.1:62816/api/iiif/3/11/image", "type": "Image", "format": "image/jpeg", "service": [ { "id": "https://iiif.dl.itc.u-tokyo.ac.jp/iiif/genji/TIFF/A00_6587/01/01_0023.tif", "type": "ImageService2", "profile": "level2" } ], "width": 6642, "height": 4990 }, "target": "http://127.0.0.1:62816/api/iiif/3/11/canvas/p1" } ] } ] } ] } 表示結果は以下です。 ...