Hatena::Groupsubtech

ういはるかぜの化学

Saturday, December 18, 2010

ASP.NETWPF をレンダリングする。 19:11  ASP.NET で WPF をレンダリングする。 - ういはるかぜの化学 を含むブックマーク はてなブックマーク -  ASP.NET で WPF をレンダリングする。 - ういはるかぜの化学

C# Advent Calendar jp: 2010の12月18日の担当です。こんにちは。

今日ご紹介するのは、ASP.NETWPFをレンダリングする方法です。

レンダリングというのはASP.NETのコード内でWPF(XAML)を組み立ててその結果をPNGなどの画像データとしてクライアントに返すということです。要するに普通にWPFアプリやExpression Blendで開いたときに見えるのと同じモノを画像にするという話です。

下準備

ASP.NETのプロジェクトを作成して、まずは参照設定でWPF/XAML関連のアセンブリを参照します。

  • PresentationCore
  • PresentationFramework
  • System.Windows.Presentation
  • System.Xaml
  • WindowsBase

Webページ(aspx)ファイルを適当な名前で追加します。とりあえずDefault.aspxとかにしておきます。

ファイルを追加したら一行目の @Page ディレクティブ(なければ追加して)に AspCompat="true" を追加します。

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication3.Default" AspCompat="true" %>

AspCompatを指定することでSTAThreadAttributeを指定するのと同等の効果を得ることができます。WPFのコンポーネントを利用するにはシングルスレッドアパートメントである必要があるのでこれは必須です。

ちなみにashxにしようかと思ったのですがAspCompatと同じような事をする方法がよくわからなかったのでaspxです。

という訳でPage_Load メソッドに適当にコードを書いていきます。CanvasにLabelが乗っかってるだけの簡単なモノを表示してみることにします。

まずは画像やVisualTreeのルートとなるCanvasをつくる

Canvas canvas = new Canvas
                    {
                        Width = 200,
                        Height = 200,
                        Background = Brushes.LightGray
                    };

そしてCanvasにLabelを追加します。

canvas.Children.Add(new Label { Content = "初春かわいい" });

で、Canvasの位置を合わせます。

canvas.Arrange(new Rect(00, canvas.Width, canvas.Height));

これで表示したいものは準備できました。

レンダリングする

RenderTargetBitmapというクラスを利用することで画像にレンダリングできます。

RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap((Int32)canvas.Width, (Int32)canvas.Height, 9696, PixelFormats.Default);

レンダリングしたいサイズを指定してクラスを生成したら、Renderメソッドでレンダリングします。

renderTargetBitmap.Render(canvas);

画像形式にエンコードする

レンダリングできても内部的なレンダリングなので、今度はそれを表示できるよう画像形式に変換します。変換にはBitmapEncoderクラスの実装クラスであるPngBitmapEncoderなどを利用します。

MemoryStream memoryStream = new MemoryStream();
BitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
encoder.Save(memoryStream);

エンコーダーを作成して、レンダリング結果を1フレームとして追加して、ストリームにエンコードしたモノを保存という流れです。ここではMemoryStreamに一旦画像データ(PNG)を保存しています。

最後にASP.NETのレスポンスとして画像データをクライアントへ送り返す

データをクライアントへ送信します。単なるバイナリデータなので普通に送るだけです。

Response.ContentType = "image/png";
Response.ClearContent();
Response.BinaryWrite(memoryStream.ToArray());

できあがったコードはこんな感じです。

https://gist.github.com/696fe81268b2daa7f9e4

表示してみる

そしておもむろにF5を押してDefault.aspxにアクセスすると画像が表示されるはずです。おめでとうございます。

f:id:mayuki:20101218185956p:image

今回はCanvasを直接作って生成しましたが、普通にXAMLを読み込んでごにょごにょいじってレンダリングすることも当然可能ですので是非ご活用ください。

トラックバック - http://subtech.g.hatena.ne.jp/mayuki/20101218