画面上のオブジェクトを画像に変換にする「あの機能が」が帰って来た!

#win8dev_jp

今回はWindows 8.1 で追加された地味にうれしい機能をご紹介します。

WriteableBitmap.RenderがなかったWindows 8

Silverlight や WPF、もちろん Silverlight をベースとした Windows Phone のアプリケーションプラットフォームには、WriteableBimap という Bitmapオブジェクトがあります。このWriteableBitmap には、 Renderというメソッドがあり、これによって画面上のオブジェクトをそのままBitmapオブジェクトに変換することができます。

いわば、スクリーンショット メソッドとでも言いましょうか?

しかし、Windows 8 の WinRT のWriteableBitmap にはこの Render メソッドがなく、画面の要素をBitmapに擦ることができなかったのです。

この件は世界中の開発者からリクエストが来た項目の一つとなりました。

そしてWindows 8.1

そしてWindows 8.1になって、新しい手法がもたらされました。

Windows 8.1 では WriteableBitmap ではなく、RenderTargetBitmap が用意されここに実装されている RenderAsync メソッドにより同様の機能を実装することができます。

RenderTargetBitmap class

小ネタ:6月にサンフランシスコで開催されたBuildイベントで、このAPIについて発表された時には、セッション会場から拍手が沸き上がっていました。世界中の開発者が待っていたんです。

実装は簡単

実装はシンプルです。新規でインスタンスを作り、bitmapにする画面上のオブジェクトを指定します。

    RenderTargetBitmap rtb = new RenderTargetBitmap();
await rtb.RenderAsync(this.LayoutRoot);

これだけです。これで、画面上のオブジェクト LayoutRoot がBitmap となって、RenderTargetBitmap の中に生成されます。

image

画像ファイルに保存

もしこれをJpegでファイル保存しようとしたらこのようなメソッドに呼べばOKです。青い部分がファイルをファイルピッカーから作るところで、赤い部分が (RenderTargetBitmap でUIから作られた)画像データをJpgファイルに書きだしているところですね。

private static async System.Threading.Tasks.Task SaveImage(RenderTargetBitmap rtb)
{
    FileSavePicker savePicker = new FileSavePicker() { DefaultFileExtension = ".jpg" };
savePicker.FileTypeChoices.Add(".jpg", new List<string> { ".jpg" });
StorageFile saveFile = await savePicker.PickSaveFileAsync();
if (saveFile != null)
{
        using (var fileStream = await saveFile.OpenAsync(FileAccessMode.ReadWrite))
{
BitmapEncoder encoder =
await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, fileStream);
IBuffer pixelBuffer = await rtb.GetPixelsAsync();
byte[] pixels = pixelBuffer.ToArray();

            float dpi = DisplayInformation.GetForCurrentView().LogicalDpi;
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore,
(uint)rtb.PixelWidth, (uint)rtb.PixelHeight, dpi, dpi, pixels);
await encoder.FlushAsync();
}
}
}

ここまでできれば、あとは、RenderTargetBitmap を引数にして呼び出すだけですね。

    RenderTargetBitmap rtb = new RenderTargetBitmap();
await rtb.RenderAsync(this.graph);
    await SaveImage(rtb);

MSDNサンプル

MSDNのサンプルがこちらにあります。結構大き目でわかりにくいかもしれませんが、参考までにどうぞ。

XAML render to bitmap sample

これでいろいろ画像系のアプリケーションの処理が広がります。