かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

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();
        }
    }
}