読者です 読者をやめる 読者になる 読者になる

Intelligent Technology's Technical Blog

株式会社インテリジェントテクノロジーの技術情報ブログです。

Windowsストアアプリ内でPDFを表示するための、ある1つの方法

ストアアプリ内ではPDFを表示できない?!

こんにちは。中山です。

ストアアプリからPDFファイルを表示したいなぁという場合、通常は

  • 外部のビューアアプリ(標準の「リーダー」アプリなど)を起動して、そちらのアプリでPDFファイルを表示する。

という方法がまず考えられます。
たいていの場合は、これで解決するのですが、ときには、どうしても、アプリ内で独自にPDFを制御したい(拡大・縮小表示、ページ送り、手描き編集などなど)、というシチュエーションが出てくるかもしれません。

しかし、ここでひとつ問題が出てきます。
Windowsストアアプリの標準SDKでは、PDFを操作するための機能が提供されていないのです。
(※2013/10/29追記: Windows8.1からは、ストアアプリ内でPDFを表示するためのAPIが提供されているようですね。)

やはり、ストアアプリ内部でPDFを表示する、ということは難しいのか・・・。
ほとんどあきらめかけていたそのとき、ある方法で、この問題を解決できることがわかったのでした。

サードパーティ製のライブラリもあるが・・・

実は、以下のようなサードパーティ製のライブラリもいくつか提供されており、これらを用いることで、Windowsストアアプリ内でのPDFファイル表示というのは実現可能です。

しかし、これらはいずれも「有料」のライブラリなのです。
したがって、気軽にちょっと試してみる、というわけにいかないのがつらいところです。

やはり「お金」で解決するしかないのかも・・・、と思っていたときに見つけたのが、これ。
Mozillaが提供している、

というライブラリです。

「pdf.js」とは

pdf.jsとは、Mozillaが開発している、HTML5ベースのPDFビューアです。
このpdf.jsを用いることで、ブラウザ上でPDFファイルをレンダリングして表示する、ということが可能になります。

この仕組み、どこかで見たことあるなぁと思ったら、最近のバージョンのFirefoxブラウザでPDFを開こうととしたときに、ブラウザ内に表示されるアレが、この「pdf.js」でした。

pdf.jsを、ストアアプリに組み込んでみる

ここでひとつひらめきました。

  • pdf.jsをストアアプリ内に組み込んで、そのストアアプリのウェブビューで表示するようにすれば、「アプリ内でのPDF表示」というのが実現できてしまうのではないか!?

幸いなことに、pdf.jsは、Apacheバージョン2.0ライセンスのオープンソースとして提供されているため、利用する上でも問題なさそうです。

さっそく作業にとりかかりました。
その結果、できたのがこれです。

f:id:IntelligentTechnology:20130812171521p:plain

表示のパフォーマンスも、なんとか実用レベルにはなっていると思われます。
さらに、「アプリ内でPDFファイルが表示できること」の利点を示すために、手描き機能も実装してみました。
(エラー処理など、機能的に不完全なところもあるかもしれませんが、ご容赦ください。)

f:id:IntelligentTechnology:20130812171615p:plain

ウェブビューを通じて、という形ではありますが、ストアアプリ内でのPDFファイル表示を実現することができました。

このサンプルアプリのソースコードは、こちらからダウンロードすることができます。
(なお、こちらのソースコードを使用、または第三者に提供することによって生じた、いかなる損害に対しても、一切責任を負いません。ご了承ください。)

実装のポイント

実装するにあたり、いちばんのネックとなったのが、ウェブビューで表示するHTMLコンテンツの配置場所です。
「pdf.js」ライブラリは、PDFレンダリングを担当する「pdf.js」ファイルのほかにも、「viewer.html」「viewer.js」など、いくつかのHTMLファイル、JavaScriptファイルなどから構成されています。

ストアアプリの場合、こういったファイルを格納するのは、プロジェクト内の「Assets」フォルダです。

しかし、この「Assets」フォルダに配置したままでは、正しくPDFファイルを表示することができませんでした。
ストアアプリのウェブビューから「Assets」フォルダのファイルにアクセスするには、

ms-appx-web:///Assets/web/viewer.html

という独自のプロトコルのURLを用いる必要があります。しかしながらこのようなURLは、「pdf.js」ライブラリ側では、うまく取り扱えないようでした。

これを解決するために、

  1. アプリ内で独自のHTTPサーバを稼働
  2. Assetsフォルダ内のファイル(HTML、JavaScriptなどのファイル)を、アプリのローカルデータフォルダ(=「ApplicationData.Current.LocalFolder」でアクセスできるフォルダ)にコピー
  3. アプリ内HTTPサーバを経由して、そのローカルデータフォルダにコピーしたファイルにアクセス

という方法をとりました。
独自のHTTPサーバを稼働させることで、

http://localhost:8088/web/viewer.html

といった形で、通常のhttpプロトコルでコンテンツにアクセスすることが可能となり、「pdf.js」ライブラリの機能も、問題なく動作するようになりました。
この独自のHTTPサーバに関する部分は、ソースコード内にある「HttpServer」クラスが担当しています。

なお、画面起動時に任意のPDFファイルを表示するには、

http://localhost:8088/web/viewer.html?file=/pdf/mysample.pdf

というふうに、URLの「file」パラメータに、表示対象のPDFファイルのパスを指定します。
この場合、対象のPDFファイルは、同じドメインのドキュメントルート内に配置しておく必要があります。
(他のサイトのPDFファイルのパスを、「file」パラメータに指定して表示することはできません。)

このあたりの処理については、ソースコード内の「PdfPage」クラスが担当しています。

ストアアプリの可能性

iOSAndroidのアプリ開発に慣れていると、ストアアプリの標準SDKは、実現できることに対しての制約が多いのかなぁという印象を持たれるかもしれません。
しかし、今回の例のように、HTML5の機能を組み合わせたりすることで、より柔軟に機能を拡張していける、という可能性も見えてきました。
Windowsストアアプリ界隈も、まだまだ面白くなっていく余地があるのかもしれませんね。