Silverlight 4 で Webカメラキャプチャ & JPEG としてローカル保存
Silverlight 4 では、DirectShow でやろうとするとそれなりに面倒な、Webカメラが対応している解像度、フレームレートの一覧が VideoCaptureDevice.SupportedFormats であっさり取れてしまいます。.NET Framework 本家にも実装してほしいですね。
Silverlight 4 の標準ライブラリでは、JPEG 画像が生成できないので、Silverlight 界隈では、ほぼデファクトスタンダードとなっている FJCore で JPEG 画像を生成しています。
利用方法は以下のような感じ。
// 保存ボタンが押されたら、保存ダイアログを開き、 // WriteableBitmap を Jpeg に変換して保存 private void buttonSave_Click(object sender, RoutedEventArgs e) { bool? dialogResult = this.saveDialog.ShowDialog(); if (dialogResult == true) { // WriteableBitmap を JPEGに変換して保存 byte[] fileBytes = CreateImageAsJpeg(_bmp, 80); // ユーザーのボタン操作によってファイル保存処理を // 行わないとセキュリティ例外 using (Stream fs = (Stream)this.saveDialog.OpenFile()) { // ユーザーが指定したファイル名で保存 fs.Write(fileBytes, 0, fileBytes.Length); fs.Close(); } } }
CreateImageAsJpeg の中身はこのような感じ。http://blogs.msdn.com/b/davrous/archive/2009/12/18/silverlight-4-tutorial-adding-avatar-support-to-the-wcf-ria-services-business-template.aspx のコードを若干修正。
/// <summary> /// ビットマップをJpegのバイト列へ変換します /// </summary> /// <param name="bitmap">変換元画像</param> /// <param name="quality">圧縮品質(0:最高圧縮率〜100:最高品質)</param> /// <returns>Jpegエンコードされたバイト列</returns> private byte[] CreateImageAsJpeg(WriteableBitmap bitmap, int quality) { int width = bitmap.PixelWidth; int height = bitmap.PixelHeight; int bands = 3; byte[][,] raster = new byte[bands][,]; for (int i = 0; i < bands; i++) { raster[i] = new byte[width, height]; } for (int row = 0; row < height; row++) { for (int column = 0; column < width; column++) { int pixel = bitmap.Pixels[width * row + column]; raster[0][column, row] = (byte)(pixel >> 16); raster[1][column, row] = (byte)(pixel >> 8); raster[2][column, row] = (byte)pixel; } } ColorModel model = new ColorModel { colorspace = ColorSpace.RGB }; FluxJpeg.Core.Image img = new FluxJpeg.Core.Image(model, raster); // JPEG形式でエンコード MemoryStream stream = new MemoryStream(); FluxJpeg.Core.Encoder.JpegEncoder encoder = new FluxJpeg.Core.Encoder.JpegEncoder(img, quality, stream); encoder.Encode(); // MemoryStream の先頭に移動 stream.Seek(0, SeekOrigin.Begin); // MemoryStream の内容を配列にコピー byte[] binaryData = new Byte[stream.Length]; long bytesRead = stream.Read(binaryData, 0, (int)stream.Length); return binaryData; }
画像の生成そのものは、クライアントPC上のみで行っているので、サーバ側は静的なファイルを置くだけでOKです。
ただ、セキュリティの理由で、保存用ダイアログに、デフォルトの保存ファイル名を指定できないようです。