イベント発生時のXPSページの変更 | Java
プログラミングにおけるイベントベースアプローチの理解
プログラミングにおけるイベントベースアプローチは、イベントとその処理に重点を置いたパラダイムです。このモデルでは、プログラムの流れはイベントによって決定されます。イベントには、ユーザーアクション(マウスのクリックやキーの押下など)、システムによって生成される通知、他のアプリケーションからのメッセージなどが含まれます。以下は、イベントベースアプローチの主要な側面です。
イベント:イベントは、プログラム内で発生した重要な事象を表します。イベントには、ユーザーによる操作、データの変更、システムのさまざまなコンポーネントからのメッセージなどが含まれます。たとえば、ボタンのクリックやファイルの読み込みによってイベントがトリガーされることがあります。
イベントリスナー:イベントを処理するために、プログラマーはイベントリスナー(またはハンドラー)を使用します。イベントリスナーは、特定のイベントが発生したときに実行されるように指定された関数またはメソッドです。たとえば、イベントリスナーは、ユーザーがボタンをクリックしたときに関数を実行するように設定できます。
非同期実行:イベントベースモデルは、通常、非同期プログラミングを容易にし、イベントを待機しながらプログラムが応答性を維持できるようにします。たとえば、Web アプリケーションは、サーバーからのデータを待機しながら機能し続けることができます。
分離: イベントベースのアプローチは、プログラム内の様々なコンポーネント間の分離を促進します。これらのコンポーネントは、互いの実装の詳細を意識することなくイベントを介して相互作用できるため、モジュール化と保守性が向上します。
一般的なユースケース: イベント駆動型プログラミングは、グラフィカルユーザーインターフェース (GUI)、Web アプリケーション、リアルタイムインタラクションを必要とするシステムで一般的に採用されています。Node.js、React などのフレームワークやライブラリは、イベント駆動型パターンを活用しています。
状態管理: イベント駆動型システムでは、ユーザーインタラクションやイベントに応じてアプリケーションが様々な状態になる可能性があるため、効果的な状態管理が不可欠です。通常、アプリケーションが意図したとおりに機能することを保証するために、適切な状態管理戦略が実装されます。
全体として、イベントベースのアプローチは、プログラム内のインタラクションとワークフローを管理する効果的な方法であり、応答性とユーザーインタラクションが求められるアプリケーションに特に適しています。
XPS ドキュメントの変換とイベント
Aspose.Page API を使用して XPS ドキュメントの特定のページを変更する必要がある場合、通常はアクティブなドキュメント(XPS ファイル内に複数のドキュメントがある場合)を選択し、アクティブなページを選択して変更を適用します。
さて、XPSファイルの全ページにわたって繰り返し変更を実装し、その結果をPDFまたは画像形式に変換する必要があるとします。このような変更の例としては、ページへの透かしの追加やナビゲーションハイパーリンクの挿入などが挙げられます。このような変更を行う最も簡単な方法は、XPSパッケージ内のドキュメントを走査し、現在アクティブなドキュメントのページを走査し、最後に変更を適用するというものです。したがって、このタスクを実現するコードは次のようになります。
1for (int i = 1; i <= document.getDocumentCount(); i++)
2{
3 document.selectActiveDocument(i);
4 for (j = 1; j <= document.getPageCount(); j++)
5 {
6 document.selectActivePage(j);
7 // Your changes ...
8 }
9}
10document.saveAsPdf("file-name.pdf", saveOptions);繰り返し変更を適用する前に、不規則な変更も加える必要がある場合、このアプローチは混乱を招き、ドキュメントやページ間のトラバーサルが過剰になる可能性があります。また、これらのループはやや煩雑に見えるかもしれません。
XPSドキュメントをPDFまたは画像に変換する場合、処理は1ページずつ実行されます。変換ジョブが次のページの処理を準備すると、「before-page」イベントがトリガーされます。ユーザーは、 BeforePageSavingEventHandlerクラスを拡張することで、このようなイベント時の動作(イベント処理)を定義できます。これにより、この記事の導入セクションで説明した利点の一部を活用できます。
ナビゲーションハイパーリンクの追加例
このセクションでは、ナビゲーションハイパーリンクを使用する例を示します。さらに、タスクを少し複雑にするために、PdfSaveOptions.setPageNumbers() メソッドで定義されているように、全ページのサブセットのみを PDF に変換します。
イベントハンドラークラス
以下は、BeforePageSavingEventHandler クラスの拡張です。
1// The class to handle the before-page event while converting an XPS document.
2private static class NavigationInjector extends BeforePageSavingEventHandler {
3 // The font in which navigation hyperlinks and page numbers will be displayed.
4 private final XpsFont font;
5 // The page numbers to convert.
6 private final TreeMap<Integer, Integer> pageNumbers;
7
8 public NavigationInjector(XpsFont font, int[] pageNumbers) {
9 this.font = font;
10 if (pageNumbers == null) {
11 this.pageNumbers = null;
12 return;
13 }
14
15 // Turn the page number array into a sorted collection of unique values.
16 this.pageNumbers = new TreeMap<>();
17 for (int pn : pageNumbers) {
18 this.pageNumbers.put(pn, 0);
19 }
20 }
21
22 /**
23 * The action itself to be triggered on a before-page event.
24 *
25 * @param args The event arguments.
26 */
27 @Override
28 public void handle(BeforeSavingEventArgs<PageAPI> args) {
29 PageAPI api = args.getElementAPI();
30
31 XpsGlyphs glyphs;
32 // For all pages in the output PDF except the first one...
33 if (args.getOutputPageNumber() > 1) {
34 // ...insert a hyperlink to the first page...
35 glyphs = api.createGlyphs(font, 15f, 5f, api.getHeight() - 10f, "[First]");
36 glyphs.setFill(api.createSolidColorBrush(Color.BLUE));
37 glyphs.setHyperlinkTarget(new XpsPageLinkTarget(pageNumbers == null ? 1 : pageNumbers.firstKey()));
38 api.add(glyphs);
39
40 // ...and to the previous page.
41 glyphs = api.createGlyphs(font, 15f, 60f, api.getHeight() - 10f, "[Prev]");
42 glyphs.setFill(api.createSolidColorBrush(Color.BLUE));
43 glyphs.setHyperlinkTarget(new XpsPageLinkTarget(
44 pageNumbers == null ? args.getAbsolutePageNumber() - 1 :
45 pageNumbers.keySet().toArray(new Integer[0])[args.getOutputPageNumber() - 2]));
46 api.add(glyphs);
47 }
48
49 // For all pages in the output PDF except the last one...
50 if ((pageNumbers != null && args.getOutputPageNumber() < pageNumbers.size()) ||
51 (pageNumbers == null && args.getOutputPageNumber() < api.getTotalPageCount())) {
52 // ...insert a hyperlink to the next page...
53 glyphs = api.createGlyphs(font, 15f, 110f, api.getHeight() - 10f, "[Next]");
54 glyphs.setFill(api.createSolidColorBrush(Color.BLUE));
55 glyphs.setHyperlinkTarget(new XpsPageLinkTarget(
56 pageNumbers == null ? args.getAbsolutePageNumber() + 1 :
57 pageNumbers.keySet().toArray(new Integer[0])[args.getOutputPageNumber()]));
58 api.add(glyphs);
59
60 // ...and to the last page.
61 glyphs = api.createGlyphs(font, 15f, 160f, api.getHeight() - 10f, "[Last]");
62 glyphs.setFill(api.createSolidColorBrush(Color.BLUE));
63 glyphs.setHyperlinkTarget(new XpsPageLinkTarget(
64 pageNumbers == null ? api.getTotalPageCount() :
65 pageNumbers.lastKey()));
66 api.add(glyphs);
67 }
68
69 // Insert a page number in the bottom-right corner.
70 glyphs = api.createGlyphs(font, 15f, api.getWidth() - 20f, api.getHeight() - 10f,
71 String.valueOf(args.getOutputPageNumber()));
72 glyphs.setFill(api.createSolidColorBrush(Color.BLACK));
73 api.add(glyphs);
74
75 // Add an outline entry to display the links to the converted pages in the navigation pane of a PDF viewer.
76 api.addOutlineEntry(String.format("Page %d", args.getOutputPageNumber()), 1, args.getAbsolutePageNumber());
77 }
78}ハンドラークラスは、正しいハイパーリンクターゲットを確立するために、PDF として保存するページを認識する必要があります。そのため、コンストラクターはオプションの getPageNumbers() 配列プロパティを引数として受け取る必要があります。ページ番号の配列が指定された場合は、重複を除外しながらソートされたコレクションを作成します。さらに、クラスにはハイパーリンクテキストのフォントデータを含む XpsFont オブジェクトが必要です。
オーバーライドされた handle() メソッドですべてが行われます。このメソッドの引数は、現在のページの変更 API、XPS パッケージ内のドキュメント番号、すべてのドキュメントにわたる 絶対ページ番号、現在のドキュメント内の 相対ページ番号(パッケージ内にドキュメントが 1 つしかない場合は前の番号と同じ)、および 出力ページ番号(パッケージ全体を変換した場合の絶対ページ番号と同じ)を含むオブジェクトです。
次の 2 つの if ブロックのロジックは非常にシンプルです。 getOutputPageNumber() イベント引数を分析し、必要に応じて一部のリンクを省略します。[First] および [Prev] リンクは最初のページには追加されず、[Next] および [Last] リンクは最後のページには表示されません。また、ページ番号が指定されているかどうかに関係なく、両方のシナリオに対応できるようにロジックが設計されています。
if ブロックの後に、ページの右下隅にページ番号を追加するコードがあります。
最後の行では、ページのアウトラインエントリを追加します。これは、PDF ビューアー(サポートされている場合)のナビゲーションパネルに表示される項目です。
変換用のコード
「before-page」イベントハンドラが定義されたので、ドキュメント変換用のコードを記述できます。
1// Modify page on conversion event.
2
3// Open an XPS document
4try (XpsDocument doc = new XpsDocument(getDataDir() + "Sample3.xps");
5 // Create a font
6 FileInputStream fontStream = new FileInputStream(getDataDir() + "arialbd.ttf")) {
7
8 // Create options for conversion to PDF
9 PdfSaveOptions options = new PdfSaveOptions();
10 // Set the filter for the pages that need conversion
11 options.setPageNumbers(new int[] { 2, 6, 7, 13 });
12 // Add the event handler that will execute right before the conversion of each page
13 options.getBeforePageSavingEventHandlers().add(new NavigationInjector(doc.createFont(fontStream), options.getPageNumbers()));
14 // Save resultant XPS document
15 doc.saveAsPdf(getOutputDir() + "ModifyPageOnConversion_out.pdf", options);
16}XPSファイルを開き、フォントデータファイルを含むストリームオブジェクトを作成します。次に、PdfSaveOptionsクラスをインスタンス化し、変換するページ番号を指定します。次の行は、getBeforePageSavingEventHandlers()コレクションを介して、「before-page」イベントハンドラーを変換ジョブに「接続」します。
あとは、ドキュメントのsaveAsPdf()メソッドを使用してPDFへの変換を実行するだけです。
まとめ
この記事では、プログラミングにおけるイベントベースのアプローチの基本的な側面を解説し、XPSドキュメントのページを直接変更する方法を検証しました。さらに、ナビゲーションハイパーリンクの挿入を例に、変換プロセス中にすべての出力ページに繰り返し変更を加えるためのより高度な手法についても考察しました。
完全な例については、 サンプルプロジェクトをご覧ください。