8.1用のWindowsストア・アプリでは、PDFファイルを表示できる新機能が追加された。その機能を使ってPDFファイルを画面に表示する方法を解説する。待ち望まれた機能、といってよいだろう。8.1アプリ)では、PDFファイルを表示できるようになったのだ。本稿では、新設されたWindows.Data.Pdf名前空間の機能を使ってPDFファイルを画面に表示する方法を解説する。8.1版)」からダウンロードできる。2013)が必要である。Windowsを使用している。8.1ストア・アプリ開発]」の記事をご参照いただきたい。2013でも構わない。Windows*1でもビルドできて正常に動作することを確認している。操作の手順や自動生成されるコードなどで、Preview版と製品版では細部が異なる可能性がある。ご承知おきいただきたい。Windows」から入手できる。8.1アプリ用に新設されたWindows.Data.Pdf名前空間の機能は、さほど多くない。端的に言えば、PDFファイルをページ単位でビットマップに変換できるだけである(次の図)。そのビットマップを画面に表示したり印刷したりする機能は、アプリ側で個別に実装することになる。Windows.Data.Pdf名前空間の機能Windows.Data.Pdf名前空間のPdfDocumentクラスがPDFファイルのストリームを解析しPdfPageクラスのオブジェクトを生成する。PdfPageオブジェクトがページごとのビットマップ描画を担当する。アプリの動作のイメージとしては、まずアプリでPDFファイルを開き、それをPdfDocumentクラスに読み込ませて、PdfDocumentオブジェクトを作る。次に、PdfDocumentオブジェクトにページごとのPdfPageオブジェクトを生成させる。用意しておいたビットマップ・ストリームに対して、PdfPageオブジェクトに描画させる。あとは、アプリ側でビットマップ・ストリームを表示する(あるいは、保存したり印刷したりする)。ユーザー・コントロールを作るPDFを表示するために、PdfDocumentオブジェクトや表示しているページ番号などをメンバ変数として維持しなければならない。画面のソース・コードの中でそれをやると煩雑になってしまってよくないので、PDFを表示する部分だけを別のクラスに独立させよう。今回はそのためにユーザー・コントロールを使う。2013のプロジェクトに新しい項目を追加する。コントロール]を選び、「PdfView.xaml」という名前を付ける。「PdfView.xaml」ファイルを開いて、次のコードのようにScrollViewerコントロールとImageコントロールを配置する。/></ScrollViewer></Grid></UserControl>「PdfView.xaml」ファイル(XAML)太字の部分を追加する。プロジェクトをいったんビルドしてから、アプリのメインとなる画面に今作ったユーザー・コントロールを配置する(次のコード)。ここでは、メイン画面にはGridコントロールがあって、それを3段(=3つのRowDefinitionオブジェクト)に分けてあるものとし、ユーザー・コントロールを3段目に置いた。/></Grid></Grid></Page>メイン画面にPdfViewコントロールを配置する(XAML)太字の部分を追加する。メイン画面にはこのほかに、ページを指定するUIなどを適宜構築してもらいたい。PdfDocumentオブジェクトを作るには?アプリでPDFファイルを開いて、そのStorageFileオブジェクトをPdfDocumentクラスのLoadPdfDocumentAsyncメソッドに渡せばよい。ユーザー・コントロールの側に次のコードのようなメソッドを作る。このメソッドは、渡されたStorageFileオブジェクトを使ってPdfDocumentオブジェクトを生成し、それをメンバ変数に保持するものだ。PdfDocumentオブジェクトが読み込んだPDFファイルの総ページ数がPageCountプロパティで取得できる。Functionユーザー・コントロール側でPdfDocumentオブジェクトを生成して保持する(上:C#、下:VB)PdfDocumentクラスのLoadFromFileAsyncメソッドにPDFファイルを表すStorageFileオブジェクトを渡すと、PdfDocumentオブジェクトが生成される。パスワードが掛かっているPDFファイルを開くなら、2番目の引数としてパスワードの文字列を渡す。総ページ数がPdfDocumentオブジェクトのPageCountプロパティで分かるので、それをメソッドの戻り値とするとともに、プロパティとして公開した。メイン画面の側には、ユーザー・コントロールのLoadPdfDocumentAsyncメソッド(=上記のメソッド)にPDFファイルを渡すメソッドを作る(次のコード)。ここでは、PDFファイルを「sample.pdf」という名前でプロジェクトのルート・フォルダに置いた*2。SubPDFファイルをユーザー・コントロールに渡すメソッド(上:C#、下:VB)メイン画面のコンストラクタでこのメソッドを呼び出す。アクション]を[コンテンツ]にしておく必要がある。このとき、ソリューション・エクスプローラでPDFファイルをクリックすると、テキスト・ファイルとして編集画面が開いてしまうので、うっかり上書き保存しないように注意してほしい。上記のメソッドをメイン画面の中で呼び出す。画面のインスタンスが作られて表示されるまでの間のどこかで呼び出せばよいが、ここではコンストラクタの最後に入れた。Subここまでで作成したメソッドを呼び出す(上:C#、下:VB)太字の部分をコンストラクタの末尾に追加する。VBのプロジェクトでコンストラクタがないときには新規に作成すること。以上で、PDFファイルからPdfDocumentオブジェクトを作成するコードが出来上がった。PdfPageオブジェクトに描画させるには?PdfDocumentオブジェクトのGetPageメソッドで1つのPdfPageオブジェクトが得られる。別途、描画データを書き込むためのストリームを用意しておき、PdfPageオブジェクトのRenderToStreamAsyncメソッドでストリームに書き込ませればよい。書き込むためのストリームは、あらかじめ画像ファイルを作っておいてそれを開いてもよいし、InMemoryRandomAccessStreamオブジェクト(メモリ上のストリーム)を使ってもよい。ユーザー・コントロールに、表示するページのインデックスを表すメンバ変数と、上記の処理を行うRenderPageBitmapAsyncメソッドを追加する(次のコード)。このメソッドから返されたInMemoryRandomAccessStreamオブジェクトには、PDFファイルの1ページが描き込まれていることになる。Functionユーザー・コントロール側でPdfPageオブジェクトを使ってメモリ上に描画する(上:C#、下:VB)PdfDocumentオブジェクトのGetPageメソッドにページのインデックス(1ページ目が0)を渡すと、PdfPageオブジェクトが得られる。PdfPageオブジェクトのRenderToStreamAsyncメソッドを呼び出すと、その引数に渡したストリームに対して、PdfPageオブジェクトが持っているページの画像データが書き込まれる。PdfPageオブジェクトは保持せず、使い終わったら捨てることにした。このメソッドから返されるInMemoryRandomAccessStreamオブジェクトは、呼び出した側で破棄しなければならない。画面に表示するには?PDFファイルの1ページが描き込まれたInMemoryRandomAccessStreamオブジェクトを使ってBitmapImageオブジェクトを作り、それをImageコントロールに表示させればよい。ユーザー・コントロールに、上記の処理を行うShowImageAsyncメソッドを追加する(次のコード)。Functionユーザー・コントロール側でInMemoryRandomAccessStreamオブジェクトを画面に表示する(上:C#、下:VB)このメソッドの引数には、PdfPageオブジェクトに1ページを描画してもらったInMemoryRandomAccessStreamオブジェクトを渡す。メソッド内部でBitmapImageオブジェクトを生成し、そのSetSourceAsyncメソッドにInMemoryRandomAccessStreamオブジェクトを渡すことで、表示可能なビットマップがストリームの内容から作成される。して作ったBitmapImageオブジェクトをImageコントロール(=image1オブジェクト。冒頭で示したPdfView.xamlファイルのリストを参照)のSourceプロパティにセットしてやると、画面に画像が表示される。画面上のImageコントロールはScrollViewerコントロールの中に配置されているので、画面からはみ出すサイズのビットマップを表示させてもスクロールできる。最後に、前述したRenderPageBitmapAsyncメソッドとこのShowImageAsyncメソッドを組み合わせて、指定したページを表示するためのRenderPageメソッドを仕立てる。このRenderPageメソッドは、メイン画面から呼び出せるようにpublicなメソッドにする。Subユーザー・コントロール側で指定ページを画面に表示する(上:C#、下:VB)ここまでのコードを組み合わせて、メイン画面から呼び出せるようにした。RenderPage()メソッドでは、現在表示されているページを表示するように指定された場合と、存在しないページを表示するように指定された場合には現在のページを表示したままとして、それ以外の場合にRenderPageAsync()メソッドを呼び出して実際にページ表示を行っている。戻り値は現在表示されているページのインデックスだ。RenderPageAsync()メソッドでは、using/Using構文を使ってInMemoryRandomAccessStreamオブジェクトを破棄するようにしている点に注意(RenderPageBitmapAsync()メソッドの説明を参照)。メイン画面に適当なUIを配置し、そのイベント・ハンドラで上記のRenderPageメソッドを呼び出せば、指定したページが画面に表示されるはずだ。このままではファイルをロードした直後に何も表示されないので、前述のLoadPdfDocumentAsyncメソッドの中にRenderPageAsyncメソッドの呼び出しを追加しておく(次のコード)。Functionユーザー・コントロール側のLoadPdfDocumentAsyncメソッド中でも画面に表示する(上:C#、下:VB)太字の部分を追加する。これでPDFファイルをロードしただけで最初のページが表示されるようになる。別のファイルをロードしたときにはまた最初のページを表示すべきなので、currentPageIndex変数を0に初期化している(PDFの表示機能を再利用可能なユーザー・コントロールとしてまとめてあるため)。描画させるビットマップのサイズを変えるには?PdfPageオブジェクトに描画してもらうときには、PdfPageRenderOptionsオブジェクトを渡せる。このPdfPageRenderOptionsオブジェクトで、描画される画像のサイズを指定すればよい。ほかにも描画するときの背景色などを指定できる。画面の回転はサポートされていないので、回転させる必要があるならそのような処理を別途記述しなければならない(本稿では説明しない)。画像の拡大率を表すメンバ変数を追加し、RenderPageBitmapAsyncメソッドを変更してみよう(次のコード)。Functionユーザー・コントロール側のRenderPageBitmapAsyncメソッドで拡大できるようにする(上:C#、下:VB)太字の部分を追加する。これで、例えばメンバ変数_zoomに2.0が入っていると、縦横2倍になって画面に表示される。DestinationHeightプロパティに設定するのは、倍率ではなくて、ピクセル単位の高さであることに注意。PdfPageオブジェクトのHeightプロパティで等倍時の画像サイズが得られるので、_zoom変数を掛けて必要な高さを算出している。実行結果メイン画面にページ送りと倍率変更のUIを配置してアプリに仕立ててみた*3。実行すると次の画像のようになる。上は等倍、下は2倍の拡大表示。サンプルに使ったPDFは筆者の講演資料だ。*3実際のコードは、別途公開のサンプル・コードを見てほしい。そちらには90°回転させる機能も実装してあるので参考にしてほしい。まとめWindows.Data.Pdf名前空間は画面への表示まではサポートしていないため、PDFを表示するにはストリームやBitmapImageオブジェクトを扱うスキルが必要だ。面倒だが、自分が必要とする機能をまとめたユーザー・コントロールに仕立てておけば、アプリからは簡単に利用できるようになる。メールマガジンをご購読ください。申し込みページへITmediaはアイティメディア株式会社の登録商標です。