先日のエントリにえムナウさんからSilverlight2での大量テキストの表示に「XPSを使ってみたら?」とアドバイスを頂き、大量のテキストをXPSファイルを元に出力しようと実装を行ってみました。
XPSはWPFのプリント出力の勉強の時に少し触った位で、XPS自体の理解が全然ない状態だったので1から調べ始めましたが、結構解けない問題が多いです。
まず、XPSファイルはMS製のPDFと考えると分かり易いかと思います。XPSファイルは拡張子が「.xps」のファイルであり、.NET Framework3.0では標準でプレビューを行うことが出来ます。
またXPSファイルは圧縮ファイルになっているので、拡張子を「.zip」などにして解凍をする事が出来ます。Office2007のExcelやWordで作成されるファイルと同じような感じです。
解凍したファイル内にはXPSファイルで使用されるデータが多数にあります。また興味深い事に、XPSファイルはXAMLによって構成されており、内容はFlowDocumentで使用するクラス郡が多数使用されています。
次に、WPFではSystem.Windows.Xps名前空間が使用できるのでXPSの使用が簡単に行えます。また、FlowDocumentクラスが使用できるので、簡単にXPSファイルのプレビューが行えます。
ではSilverlight2は?と言うと、System.Windows.Xps名前空間がサポートされていません。またFlowDocumentクラスも使用出来ません。
ですので、Silverlight2でXPSファイルを使用するにはXPSファイルを独自に展開し、内部にあるXAMLで作成されているデータファイルを解析する必要があります。
また、単純にXAMLで作成されているデータファイルを抽出するだけでは使用する事が出来ません。このXAMLデータファイル内にはSilverlight2では使用出来ないマークアップ言語が多々有るためです。
よってXAMLデータファイルを抽出し、独自にXAMLをパースする必要があります。このパース処理自体はSystem.Xml.XmlReaderクラスを継承したパース用のカスタムクラスを作成する事で比較的簡単にパースは行えます。
このカスタムクラスの作成のサンプルになる情報がありましたのでリンクしておきます。
Delay's Blog
パース後のXAMLファイルの内容は、主にCanvasパネル内にGlyphsクラスで文字列が表示されていて、画像などはPathクラスにImageBrushを使用して表示しています。
ですのでそのXAMLデータをXamlReaderクラスで読み込みSilverlight2の描画要素内に挿入する事で、XPSファイルを表示する事を実現します。
ではXPSファイルのデータのパースの流れを簡単に書いて見ます。
- XPSファイルをSilverlight2プロジェクト内のリソースやコンテンツ、またはホストしているWebプロジェクトから取得する
- Application.GetResourceStreamメソッドを使用しStreamResourceInfoを取得する
- XPSファイル内の「/Document/1」ディレクトリ内にある「.fdoc」拡張子のファイルをApplication.GetResourceStreamメソッドによりStreamResourceInfoとして取得する
- 「.fdoc」ファイル内にはXPSのページ情報が格納されている(例えば3ページにわたるページであれば3つのページ情報が存在する)のでページ情報をXmlReaderクラスを使用して取得する
- 取得したページデータは「/Document/1/Pages」ディレクトリ内にあるので、1つ1つをXmlReaderクラスを使用しパースしてXAMLファイルを作成する
- 作成したXAMLファイルをXamlReaderクラスを使用してオブジェクトツリーを作成し、画面のSilverlight2要素内に挿入する
こんな感じです。
これで万事オーケーかと言うとそうでもありません。上記手順内にも多々問題があります。
まず一つ目に、上記のページデータファイルのXAMLデータファイルで使用されているGlyphsクラスはFontUriプロパティが存在し、そのFontUriプロパティに指定されているフォントデータによって文字列が表示されます。
このFontUriは必須項目であり、そのフォントはXPSファイルを作成した時にXPSファイル内に埋め込まれます。これはXPSファイルを解凍し、その中の「/Documents/1/Resources/Fonts」ディレクトリ内に「.odttf」拡張子として埋め込まれています。
Silverlight2ではGlyphsクラスを使用し、FontUriを設定するにはSilverlight2プロジェクト内にフォントデータが存在している必要があるのです。きまったフォントのみでXPSファイルを作成しているのであれば決まったフォントデータを配置しておけば済むのですが、読み込むXPSファイルが様々な物を使用している場合には対応が大変です。
次に、Application.GetResourceStreamメソッドを使用しても読み込めないXPSファイルがあるのです。
詳細はまだ分かっていないのですが、上記展開方法はOffice2007のWordで作成したXPSファイルであれば無事に展開出来るのですが、IE8(IE7等ではまだ未確認)で作成したXPSファイルは何故か読み込めません。
今回、htmlで表示された画面をXPSファイルで作成し、それをSilverlight2で使用しようと思っていたのでこれは困った結果です。
それとXPSファイル内の「/Document/1」ディレクトリ内にある「.fdoc」ファイルの名前も作成したアプリケーションによって違いがあるようなのです。
なのでApplication.GetResourceStreamメソッドに指定するUriも思いつく限りのファイル名で探さないといけないようなのです。
まだまだ課題は多そうです。
今後も検証を行っていきたいと思います。