読者です 読者をやめる 読者になる 読者になる

マイクロソフト エバンジェリストのブログ

日本マイクロソフトのエバンジェリストが、技術情報を発信するブログです!

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

UI系エバンジェリスト高橋です。

今回は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

 

実装は簡単

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

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

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

 

画像ファイルに保存

もしこれをJpegでファイル保存しようとしたらこのようなメソッドに呼べばOKです。

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

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