かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

UWPでWin2Dを使ってオフスクリーンに描画する

画面に表示しない状態で描画したいときもあると思うのでやってみました。

手順としては、CanvasDevice.GetSharedDevice()でCanvasDeviceを取得して、それをもとにCanvasRenderTargetを作成します。CanvasRenderTargetができたらCreateDrawingSessionでCanvasDrawingSessionが作れるので、DrawXXXXを呼んでいきます。

選択した画像にオフスクリーンで文字を描きこんでファイルに保存するコードは以下のようになります。(画面にボタンを置いてクリックイベントでがりっとやってるコードです。)

using Microsoft.Graphics.Canvas;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Windows.Graphics.Display;
using Windows.Graphics.Imaging;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace App39
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
        }

        private async void ProcessButton_Click(object sender, RoutedEventArgs e)
        {
            var sourceFile = await this.PickOpenAsync();
            if (sourceFile == null) { return; }

            var device = CanvasDevice.GetSharedDevice();
            var image = default(CanvasBitmap);
            using (var s = await sourceFile.OpenReadAsync())
            {
                image = await CanvasBitmap.LoadAsync(device, s);
            }

            var offscreen = new CanvasRenderTarget(
                device, (float)image.Bounds.Width, (float)image.Bounds.Height, 96);

            using (var ds = offscreen.CreateDrawingSession())
            {
                ds.DrawImage(image, 0, 0);
                ds.DrawText("Hello world", 10, 10, Colors.Blue);
            }

            var displayInformation = DisplayInformation.GetForCurrentView();
            var destFile = await PickSaveAsync();
            using (var s = await destFile.OpenAsync(FileAccessMode.ReadWrite))
            {
                var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, s);
                encoder.SetPixelData(
                    BitmapPixelFormat.Bgra8,
                    BitmapAlphaMode.Ignore,
                    (uint)offscreen.Size.Width,
                    (uint)offscreen.Size.Height,
                    displayInformation.LogicalDpi,
                    displayInformation.LogicalDpi,
                    offscreen.GetPixelBytes());
                await encoder.FlushAsync();
            }
        }

        private async Task<StorageFile> PickOpenAsync()
        {
            var picker = new FileOpenPicker();
            picker.FileTypeFilter.Add(".png");
            picker.FileTypeFilter.Add(".jpg");
            picker.FileTypeFilter.Add(".jpeg");

            return await picker.PickSingleFileAsync();
        }

        private async Task<StorageFile> PickSaveAsync()
        {
            var picker = new FileSavePicker();
            picker.FileTypeChoices.Add("png", new List<string> { ".png" });
            return await picker.PickSaveFileAsync();
        }
    }
}