先日のエントリにえムナウさんから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ファイルのデータのパースの流れを簡単に書いて見ます。

  1. XPSファイルをSilverlight2プロジェクト内のリソースやコンテンツ、またはホストしているWebプロジェクトから取得する
  2. Application.GetResourceStreamメソッドを使用しStreamResourceInfoを取得する
  3. XPSファイル内の「/Document/1」ディレクトリ内にある「.fdoc」拡張子のファイルをApplication.GetResourceStreamメソッドによりStreamResourceInfoとして取得する
  4. 「.fdoc」ファイル内にはXPSのページ情報が格納されている(例えば3ページにわたるページであれば3つのページ情報が存在する)のでページ情報をXmlReaderクラスを使用して取得する
  5. 取得したページデータは「/Document/1/Pages」ディレクトリ内にあるので、1つ1つをXmlReaderクラスを使用しパースしてXAMLファイルを作成する
  6. 作成した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も思いつく限りのファイル名で探さないといけないようなのです。

まだまだ課題は多そうです。
今後も検証を行っていきたいと思います。

フィードバック

# re: [Silverlight] Silverlight2での大量テキストの表示(XPS編)

2009/05/21 9:45 by 青柳 臣一
商品なんですが Document Toolkit というのがあります。
Silverlight 2、3 beta で XPS を表示するコントロールです。
http://silverlightspy.com/documenttoolkit/

↑にデモへのリンクもあります。
196ページある 「ASP.NET MVC 1.0」 を見ても特にストレスは感じません。
ローカルのファイルを読み込むこともできるので Word から XPS で出力したものを見てみましたが、日本語も特に問題ないようです。

私もデモを見ただけなのでこれをお勧めするというわけではないのですが、こういったものもありますよ、という参考まで。

# re: [Silverlight] Silverlight2での大量テキストの表示(XPS編)

2009/05/21 10:14 by kazuto
>青柳さん
コメント有難う御座います。
有益な情報有難う御座います。
Document ToolkitはエントリでリンクしたDelay's Blogより拝見させて頂いておりました。
ソースコードもダウンロードして拝見していましたが、Document Toolkitは文字列にGlyphsではなくTextBlockを使用しているようです。
また、Viewerもページのスクロールに合わせてデータの取得を行っているのでそのような工夫をしないと大量のテキストをスムーズに表示出来ないようですね。
GlyphsとTextBlockでのパフォーマンスの差はまだ検証していないので分かりませんが、TextBlock単体では動作が凄く重たくなってしまいます。
自身のホームページに使用しようと思っているので、商品購入までとは思っていないのですが、Silverlight2でXPSを独自に展開するのは結構大変そうです。
またXPSを単純に展開しても結局はCanvas内に文字列を配置しているだけなので、ページ内のリンクやソースコードのコピーなどは出来ないのでまだまだ課題があります。
また何か分かったことがありましたらエントリさせて頂きます。

# re: [Silverlight] Silverlight2での大量テキストの表示(XPS編)

2009/05/21 15:05 by gtk2k
ピクセル単位での滑らかなスクロールでなくてもいいというのでしたら、TextBlockとScrollBarを使用してプログラムで実装することにより、一応かくかくしない(見た目)スクロールができます。
とりあえずサンプル作ってみました。
私はまだSilverlightは触り始めたばかりで、特にXAMLはいまだに要領をつかめていませんのでサンプルプログラムは体裁が悪いです。ごめんなさい。
http://vnayew.bay.livefilestore.com/y1papk-2lf_uLuffb4fKWAiSHnJmuKXdjwlQQfxhOy30Wp4pQBqAg2VVYOwedzCVdRRpYq0jPEUjgiYL5AuIhsulIRSWW323FNf/TextBlockScrollSample.zip?download

# re: [Silverlight] Silverlight2での大量テキストの表示(XPS編)

2009/05/21 15:58 by kazuto
>gtk2kさん
コメント有難う御座います。
わざわざサンプルコードまで頂いて大変申し訳ないです。
実際試してみましたが、とても軽快に動作すること確認いたしました。
TextBlock以外に様々な要素が存在する場合はまた違う形での実装となりそうですが(今回の目的はSilverlight2でホームページを作成する為、画像なども使用するので)、とても参考になる情報です。
時間が空いたときに試してみたいと思います。
コメントの入力
タイトル
名前
Url
コメント