Знакомьтесь: Win2D это легкое в использование Windows Runtime API для более удобного использования возможностей DirectX. Прорисовка графики осуществляется с ускорением GPU. Win2D доступно для разработчиков C#, C++ и VB и в Windows 8.1 и в Windows 10.
С помощью Win2D вы сможете рисовать фигуры, линии, текст и изображения, а также добавлять ко всему этому различные эффекты. Кроме того, можно добавить какие-то эффекты к видеоизображению.
Предлагаю рассмотреть на примерах основной функционал библиотеки.
Установить Win2D.uwp можно из Visual Studio с помощью диспетчера пакетов NuGet. Github-страничка этого open-source проекта находится здесь. Англоязычная документация здесь: Win2D documentation
После установки в заголовок XAML страницы можно добавить:
xmlns:canvas="using:Microsoft.Graphics.Canvas.UI.Xaml"
А в разметку страницы элемент управления CanvasControl:
<canvas:CanvasControl Width="500" Height="300" x:Name="canv" Draw="CanvasControl_Draw" ClearColor="LightGray"/>
Это не тот же самый элемент Canvas, который является элементом компоновки страницы и может в качестве хоста содержать в себе другие элементы. Какое-то сходство между Canvas и CanvasControl есть, но производительность совершенно разная.
При прорисовке элемента CanvasControl происходит событие Draw, которому в примере назначен обработчик события CanvasControl_Draw. Официальный пример предлагает нарисовать для начала фигуру (эллипс) и текст:
void CanvasControl_Draw(CanvasControl sender, CanvasDrawEventArgs args) { args.DrawingSession.DrawEllipse(155, 115, 80, 30, Colors.Black, 3); args.DrawingSession.DrawText("Hello, world!", 100, 100, Colors.Yellow); }
Вот что получится:
Для того, чтобы избежать утечек памяти, необходимо всегда корректно уничтожать ресурсы. Делается это, как правило, при выгрузке страницы:
void Page_Unloaded(object sender, RoutedEventArgs e) { this.canv.RemoveFromVisualTree(); this.canv = null; }
Пока что ничего необычного. То же самое можно нарисовать и используя фигуры XAML. Кстати, примеры рисования в обычном XAML вы можете найти здесь: Draw shapes
Поработаем с изображениями. Это гораздо интереснее. Я добавил в проект файл mydog.jpg и выбрал в свойствах действие при сборке «Содержание» (если быть точным, то даже не выбирал, — оно выбралось само по умолчанию).
За изображения в Win2D отвечает класс CanvasBitmap из пространства имен Microsoft.Graphics.Canvas. Добавим в наше приложение переменную с именем cbi:
CanvasBitmap cbi;
Загрузка картинки происходит во время события элемента Canvas названием CreateResources, поэтому в наш XAML код добавим это событие:
<canvas:CanvasControl Width="500" Height="300" x:Name="canv" Draw="CanvasControl_Draw" CreateResources="CanvasControl_CreateResources" ClearColor="LightGray"/>
Сама загрузка происходит с помощью следующего кода:
cbi = await CanvasBitmap.LoadAsync(sender, "mydog.jpg");
Так как она происходит асинхронно, то нам предлагается вынести ее в отдельный таск:
private void CanvasControl_CreateResources(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.CanvasCreateResourcesEventArgs args) { args.TrackAsyncAction(CreateResourcesAsync(sender).AsAsyncAction()); } async Task CreateResourcesAsync(CanvasControl sender) { cbi = await CanvasBitmap.LoadAsync(sender, "mydog.jpg"); }
TrackAsyncAction в данном случае требует чтобы таск CreateResourcesAsync завершился до окончания CreateResources. Остается загрузить в Canvas:
private void CanvasControl_Draw(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasDrawEventArgs args) { args.DrawingSession.DrawImage(cbi); }

Загрузилось, но не особо пока что интересно просто отображать картинку. Добавим всего пару строк кода и получим эффект размытия по Гауссу
var blur = new GaussianBlurEffect(); blur.BlurAmount = 1.7f; blur.Source = cbi; args.DrawingSession.DrawImage(blur);
Полный списко эффектов доступен на странице описания пространства имен Microsoft.Graphics.Canvas.Effects документации. Кстати, эффекты также можно создавать еще и с помощью Lumia Imaging SDK. Исходный код Lumia-imaging-sdk можно тоже найти на GitHub. Кроме того, какие-то эффекты доступны с помощью пространства имен Windows.UI.Composition.
Иногда возникает необходимость отобразить графику не сразу, а во время исполнения программы. Сохранить ее в файл, вывести на экран или получить массив пикселей. Такой вариант работы называется Offscreen drawing.
Скажем, вот пример, в котором совсем не используется XAML элемент CanvasControl, а используется простой элемент image
<Image x:Name="img" Width="500" Height="300"></Image>
Обработать картинку и отобразить ее, добавив эффект насыщения, можно так:
CanvasDevice device = CanvasDevice.GetSharedDevice(); CanvasRenderTarget offscreen = new CanvasRenderTarget(device, 500, 300, 96); cbi = await CanvasBitmap.LoadAsync(device, "mydog.jpg"); using (var ds = offscreen.CreateDrawingSession()) { var satur = new SaturationEffect(); satur.Saturation = 0.2f; satur.Source = cbi; ds.DrawImage(satur); } using (var stream = new InMemoryRandomAccessStream()) { stream.Seek(0); await offscreen.SaveAsync(stream, CanvasBitmapFileFormat.Png); BitmapImage image = new BitmapImage(); image.SetSource(stream); img.Source = image; }
Мне так даже больше нравится (хотя о сравнении производительности сказать ничего не могу)
Для того чтобы составить небольшую композицию и наложить текст на картинку нам понадобятся пространство имен:
using Microsoft.Graphics.Canvas.Text;
И подобный сниппет:
CanvasDevice device = CanvasDevice.GetSharedDevice(); CanvasRenderTarget offscreen = new CanvasRenderTarget(device, 500, 300, 96); cbi = await CanvasBitmap.LoadAsync(device, "mydog.jpg"); using (var ds = offscreen.CreateDrawingSession()) { ds.DrawImage(cbi); var format = new CanvasTextFormat() { FontSize = 32, HorizontalAlignment = CanvasHorizontalAlignment.Left, VerticalAlignment = CanvasVerticalAlignment.Top, WordWrapping = CanvasWordWrapping.Wrap, FontFamily = "Decor", }; using (CanvasTextLayout tl = new CanvasTextLayout(ds, "10 июня 2010", format, 250, 50)) // ширина 250 и высота 50 { ds.DrawTextLayout(tl, 10, 10, Color.FromArgb(120, 20, 20, 20)); } format.Dispose(); } using (var stream = new InMemoryRandomAccessStream()) { stream.Seek(0); await offscreen.SaveAsync(stream, CanvasBitmapFileFormat.Png); BitmapImage image = new BitmapImage(); image.SetSource(stream); img.Source = image; }
Объединить 2 изображения можно с помощью эффекта blend:
CanvasBitmap cbi; CanvasBitmap cbi2; CanvasDevice device = CanvasDevice.GetSharedDevice(); CanvasRenderTarget offscreen = new CanvasRenderTarget(device, 500, 300, 96); cbi = await CanvasBitmap.LoadAsync(device, "mydog.jpg"); cbi2 = await CanvasBitmap.LoadAsync(device, "present.png"); using (var ds = offscreen.CreateDrawingSession()) { BlendEffect blendEffect = new BlendEffect() { Background = cbi, Foreground = cbi2, Mode = BlendEffectMode.SoftLight }; ds.DrawImage(blendEffect); } using (var stream = new InMemoryRandomAccessStream()) { stream.Seek(0); await offscreen.SaveAsync(stream, CanvasBitmapFileFormat.Png); BitmapImage image = new BitmapImage(); image.SetSource(stream); img.Source = image; }
Некоторые эффекты можно комбинировать. С помощью следующего сниппета, комбинирующего множество эффектов можно получить эффект свечения текста
var myTextBitmap = new CanvasRenderTarget(sender, 300, 100); using (var ds = myTextBitmap.CreateDrawingSession()) { ds.Clear(Color.FromArgb(0, 0, 0, 0)); ds.DrawText("Неоновый текст!", 0, 0, Colors.White, new CanvasTextFormat { FontSize = 24, FontWeight = Windows.UI.Text.FontWeights.Bold }); } var effectGraph = new CompositeEffect(); effectGraph.Mode = CanvasComposite.Add; effectGraph.Sources.Add(new ColorMatrixEffect { Source = new GaussianBlurEffect { Source = new MorphologyEffect { Source = myTextBitmap, Mode = MorphologyEffectMode.Dilate, Width = 7, Height = 4 }, BlurAmount = 3f }, ColorMatrix = new Matrix5x4 { M11 = 0f, M12 = 0f, M13 = 0f, M14 = 0f, M21 = 0f, M22 = 0f, M23 = 0f, M24 = 0f, M31 = 0f, M32 = 0f, M33 = 0f, M34 = 0f, M41 = 0f, M42 = 1f, M43 = 0f, M44 = 1f, M51 = 1f, M52 = -0.5f, M53 = 0f, M54 = 0f } }); effectGraph.Sources.Add(myTextBitmap); args.DrawingSession.DrawImage(effectGraph,100,100);
Интересный текстовый эффект, который очень часто ассоциируется с Win2D это анимационный эффект горящего текста.
Прямые ссылки на BurningTextExample.xaml и BurningTextExample.xaml.cs примера я, пожалуй, даже оставлю здесь: BurningTextExample.xaml / BurningTextExample.xaml.cs.
Точно также как и в случае с UWP Community Toolkit, есть возможность скачать приложение с примерами использования и для Win2D. Приложение называется Win2D Example Gallery. Исходный код приложения находится на github.
Лично мне больше всего понравилась следующая картинка:
Как оказалось, она полностью нарисована с помощью DrawLine, DrawEllipse, DrawCircle и т.п.
Библиотека обновляется регулярно и поэтому можно ожидать новые красивые эффекты.
