XPS ページのイベントベースの変更 | .NET
プログラミングにおけるイベントベースのアプローチとは?
プログラミングにおけるイベントベースのアプローチは、イベントとイベント処理の概念を中心としたパラダイムです。このモデルでは、プログラムの流れはイベントによって決定されます。イベントには、ユーザーアクション(マウスのクリックやキーの押下など)、システムによって生成される通知、または他のアプリケーションからのメッセージなどがあります。イベントベースのアプローチの主な側面は次のとおりです。
イベント:イベントは、プログラムにおける重要な出来事を表します。これには、ユーザーによる操作、データの変更、システムの他の部分からのメッセージなどが含まれます。たとえば、ボタンのクリックやファイルの読み込みによってイベントがトリガーされることがあります。
イベントリスナー:イベントに応答するために、プログラマーはイベントリスナー(またはハンドラー)を使用します。イベントリスナーは、特定のイベントが発生したときに実行されるように定義された関数またはメソッドです。たとえば、イベントリスナーは、ユーザーがボタンをクリックしたときに関数を実行するように設定できます。
非同期実行: イベントベースモデルは多くの場合、非同期プログラミングをサポートしており、イベントの発生を待機している間もプログラムは応答性を維持できます。たとえば、Webアプリケーションはサーバーからのデータを待機しながら動作を継続できます。
分離: イベントベースのアプローチは、プログラムの異なる部分間の分離を促進します。コンポーネントは互いの実装の詳細を意識することなくイベントを介して通信できるため、コードのモジュール化が進み、保守が容易になります。
一般的なユースケース: イベント駆動型プログラミングは、グラフィカルユーザーインターフェース (GUI)、Webアプリケーション、リアルタイムインタラクションを必要とするシステムで広く使用されています。Node.js、Reactなどの多くのフレームワークやライブラリは、イベント駆動型パターンを利用しています。
状態管理: イベント駆動型システムでは、ユーザーインタラクションやイベントに応じてアプリケーションがさまざまな状態になる可能性があるため、状態管理が非常に重要です。アプリケーションが期待どおりに動作することを保証するために、適切な状態管理戦略が採用されることがよくあります。
全体として、イベントベースのアプローチはプログラム内のインタラクションとワークフローを管理する強力な方法であり、応答性とユーザーインタラクションが求められるアプリケーションに特に効果的です。
XPSドキュメント変換中に発生するイベント
Aspose.Page APIを使用してXPSドキュメントの特定のページに変更を加える必要がある場合、通常はアクティブなドキュメント(XPSファイル内に複数のドキュメントがある場合)を選択し、アクティブなページを選択してから、変更を適用します。
ここで、XPSファイル内のすべてのページに繰り返し変更を加え、その結果をPDFまたは画像形式に変換する必要があるとします。このような変更の例として、ページに透かしを挿入したり、ナビゲーションハイパーリンクを追加したりすることが挙げられます。このような変更を直接行うには、XPSパッケージ内のドキュメントを走査し、現在アクティブなドキュメントのページを走査し、最後に変更を適用します。したがって、このタスクを実行するコードは次のようになります。
1for (int i = 1; i <= document.DocumentCount; i++)
2{
3 document.SelectActiveDocument(i);
4 for (j = 1; j <= document.PageCount; j++)
5 {
6 document.SelectActivePage(j);
7 // Your changes ...
8 }
9}
10document.SaveAsPdf("file-name.pdf", saveOptions);
繰り返しの変更の前に、不規則な変更も加える必要がある場合、このアプローチは混乱を招き、ドキュメントやページ間の移動が過度になるだけでなく、ループ処理が煩雑に感じられる可能性があります。
XPSドキュメントをPDFまたは画像に変換する場合、処理はページごとに実行されます。変換ジョブが次のページを処理する準備ができると、「before-page」イベントがトリガーされます。ユーザーは、 BeforePageSavingEventHandler クラスを拡張することで、このようなイベントの処理を定義できます。これにより、この記事の導入セクションで概説したいくつかのメリットを活用できます。
ナビゲーションハイパーリンクの追加例
ここでは、ナビゲーションハイパーリンクに関する例を示します。さらに、タスクを少し複雑にするために、PdfSaveOptions.PageNumbers
プロパティで指定された全ページのサブセットのみを PDF に変換します。
イベントハンドラークラス
以下は BeforePageSavingEventHandler
クラスの拡張です。
1// The class to handle the before-page event while converting an XPS document.
2class NavigationInjector : BeforePageSavingEventHandler
3{
4 // The font in which navigation hyperlinks and page numbers will be displayed.
5 private readonly XpsFont _font;
6 // The page numbers to convert.
7 private readonly SortedList<int, int> _pageNumbers;
8
9 public NavigationInjector(XpsFont font, int[] pageNumbers)
10 {
11 _font = font;
12 if (pageNumbers == null)
13 return;
14
15 // Turn the page number array into a sorted collection of unique values.
16 _pageNumbers = new SortedList<int, int>();
17 foreach (int pn in pageNumbers)
18 _pageNumbers[pn] = 0;
19 }
20
21 /// <summary>
22 /// The action itself to be triggered on a before-page event.
23 /// </summary>
24 /// <param name="args">The event arguments.</param>
25 public override void Handle(BeforeSavingEventArgs<PageAPI> args)
26 {
27 PageAPI api = args.ElementAPI;
28
29 XpsGlyphs glyphs;
30 // For all pages in the output PDF except the first one...
31 if (args.OutputPageNumber > 1)
32 {
33 // ...insert a hyperlink to the first page...
34 glyphs = api.CreateGlyphs(_font, 15f, 5f, api.Height - 10f, "[First]");
35 glyphs.Fill = api.CreateSolidColorBrush(Color.Blue);
36 glyphs.HyperlinkTarget = new XpsPageLinkTarget(_pageNumbers == null ? 1 : _pageNumbers.Keys[0]);
37 api.Add(glyphs);
38
39 // ...and to the previous page.
40 glyphs = api.CreateGlyphs(_font, 15f, 60f, api.Height - 10f, "[Prev]");
41 glyphs.Fill = api.CreateSolidColorBrush(Color.Blue);
42 glyphs.HyperlinkTarget = new XpsPageLinkTarget(
43 _pageNumbers == null ? args.AbsolutePageNumber - 1 : _pageNumbers.Keys[args.OutputPageNumber - 2]);
44 api.Add(glyphs);
45 }
46
47 // For all pages in the output PDF except the last one...
48 if ((_pageNumbers != null && args.OutputPageNumber < _pageNumbers.Count) ||
49 (_pageNumbers == null && args.OutputPageNumber < api.TotalPageCount))
50 {
51 // ...insert a hyperlink to the next page...
52 glyphs = api.CreateGlyphs(_font, 15f, 110f, api.Height - 10f, "[Next]");
53 glyphs.Fill = api.CreateSolidColorBrush(Color.Blue);
54 glyphs.HyperlinkTarget = new XpsPageLinkTarget(
55 _pageNumbers == null ? args.AbsolutePageNumber + 1 : _pageNumbers.Keys[args.OutputPageNumber]);
56 api.Add(glyphs);
57
58 // ...and to the last page.
59 glyphs = api.CreateGlyphs(_font, 15f, 160f, api.Height - 10f, "[Last]");
60 glyphs.Fill = api.CreateSolidColorBrush(Color.Blue);
61 glyphs.HyperlinkTarget = new XpsPageLinkTarget(
62 _pageNumbers == null ? api.TotalPageCount : _pageNumbers.Keys[_pageNumbers.Keys.Count - 1]);
63 api.Add(glyphs);
64 }
65
66 // Insert a page number in the bottom-right corner.
67 glyphs = api.CreateGlyphs(_font, 15f, api.Width - 20f, api.Height - 10f, args.OutputPageNumber.ToString());
68 glyphs.Fill = api.CreateSolidColorBrush(Color.Black);
69 api.Add(glyphs);
70
71 // Add an outline entry to display the links to the converted pages in the navigation pane of a PDF viewer.
72 api.AddOutlineEntry(string.Format("Page {0}", args.OutputPageNumber), 1, args.AbsolutePageNumber);
73 }
74}
ハンドラークラスは、適切なハイパーリンクターゲットを作成するために、PDF として保存するページを認識する必要があります。そのため、コンストラクターはオプションの配列プロパティを引数として受け取ります。ページ番号の配列が指定されている場合は、重複を避けながら、並べ替えられたコレクションを作成します。 (ちなみに、この解決策は完全に正確ではありません。出力に不一致が生じる原因は何でしょうか?) また、ハイパーリンク テキストのフォント データを含む XpsFont
オブジェクトも必要になります。
オーバーライドされた Handle()
メソッドで、すべての処理が行われます。このメソッドの引数は、現在のページの変更 API、XPS パッケージ内のドキュメント番号、すべてのドキュメントにわたる 絶対ページ番号、現在のドキュメント内の 相対ページ番号(パッケージ内にドキュメントが 1 つしかない場合は前の番号と同じ)、および 出力ページ番号(パッケージ全体を変換した場合の絶対ページ番号と同じ)を含むオブジェクトです。
次の 2 つの if
ブロックのロジックは非常に単純です。これは、OutputPageNumber
イベント引数の分析に基づいており、必要に応じて一部のリンクを省略します。[First]
および [Prev]
リンクは最初のページを除くすべての出力ページに追加され、[Next]
および [Last]
リンクは最後のページを除くすべてのページに表示されます。このロジックは、ページ番号が指定されているかどうかに関係なく、両方のケースに合わせて調整されます。
if
ブロックの後には、ページの右下隅にページ番号を追加するコードがあります。
最後の行では、ページのアウトラインエントリ(PDF ビューアのナビゲーションパネルに表示される項目)を追加します(サポートされている場合)。
変換コード
これで「before-page」イベントハンドラが定義されたので、ドキュメントを変換するコードを記述できます。
1// Modify page on conversion event.
2
3// Open an XPS document
4using (XpsDocument doc = new XpsDocument(DataDir + "Sample3.xps"))
5// Create a font
6using (Stream fontStream = File.OpenRead(DataDir + "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.PageNumbers = new int[] { 2, 6, 7, 13 };
12 // Add the event handler that will execute right before the conversion of each page
13 options.BeforePageSavingEventHandlers.Add(new NavigationInjector(doc.CreateFont(fontStream), options.PageNumbers));
14 // Save resultant XPS document
15 doc.SaveAsPdf(OutputDir + "ModifyPageOnConversion_out.pdf", options);
16}
XPSファイルを開き、フォントデータファイルを使用してストリームオブジェクトをインスタンス化します。次に、PdfSaveOptions
クラスのインスタンスを作成し、変換するページ数を指定します。次の行では、「before-page」イベントハンドラーがBeforePageSavingEventHandlers
コレクションオプションを介して変換ジョブに「接続」されます。
あとは、ドキュメントのSaveAsPdf()
メソッドを使用してPDFへの変換を実行するだけです。
まとめ
この記事では、プログラミングにおけるイベントベースのアプローチの要点を解説し、XPSドキュメントのページを直接変更する方法を検証しました。さらに、ナビゲーションハイパーリンクの挿入を例に、変換プロセス中にすべての出力ページに繰り返し変更を加えるための、より高度で洗練された手法を習得しました。
完全な例については、 サンプルプロジェクトをご覧ください。