Using Graphic Effects in UWP Applications Using Win2D


    Meet: Win2D is an easy-to-use Windows Runtime API for more convenient use of DirectX features. Graphics are drawn with GPU acceleration. Win2D is available for C #, C ++, and VB developers on both Windows 8.1 and Windows 10.

    With Win2D, you can draw shapes, lines, text, and images, as well as add various effects to all of this. In addition, you can add some effects to the video image.

    I propose to consider the examples of the main functionality of the library.

    You can install Win2D.uwp from Visual Studio using the NuGet package manager. The github page of this open-source project is here . English documentation here: Win2D documentation

    After setting the page in the XAML header, you can add:

    xmlns:canvas="using:Microsoft.Graphics.Canvas.UI.Xaml"

    And in the page layout, the CanvasControl control:


    This is not the same Canvas element, which is a page layout element and can contain other elements as a host. There is some similarity between Canvas and CanvasControl, but the performance is completely different.

    When drawing a CanvasControl element, the Draw event occurs, which in the example is assigned the CanvasControl_Draw event handler. The official example suggests drawing a figure (ellipse) and text for starters:

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

    Here's what happens:



    In order to avoid memory leaks, you must always correctly destroy resources. This is usually done when the page is unloaded:

    void Page_Unloaded(object sender, RoutedEventArgs e)
      {
          this.canv.RemoveFromVisualTree();
          this.canv = null;
      }

    So far, nothing unusual. The same can be done using XAML shapes. By the way, you can find examples of drawing in regular XAML here: Draw shapes Let's

    work with images. This is much more interesting. I added the mydog.jpg file to the project and selected the action for the “Content” assembly in the properties (to be precise, I didn’t even choose it — it was selected by default).

    For images in Win2D, the CanvasBitmap class from the Microsoft.Graphics.Canvas namespace is responsible. Add a variable called cbi to our application:

    CanvasBitmap cbi;

    The image is loaded during the event of the Canvas element called CreateResources, so we will add this event to our XAML code:


    The download itself is performed using the following code:

    cbi = await CanvasBitmap.LoadAsync(sender, "mydog.jpg");

    Since it happens asynchronously, we are invited to put it in a separate task:

    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 in this case requires the CreateResourcesAsync task to complete before the end of CreateResources. It remains to load into Canvas:

    private void CanvasControl_Draw(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasDrawEventArgs args)
         {
             args.DrawingSession.DrawImage(cbi);
         }



    It was loaded, but not really interesting for now, just to display a picture. Add just a couple of lines of code and get a Gaussian blur effect

    var blur = new GaussianBlurEffect();
      blur.BlurAmount = 1.7f;
      blur.Source = cbi;
      args.DrawingSession.DrawImage(blur);
    



    A complete list of effects is available on the Microsoft.Graphics.Canvas.Effects namespace description page of the documentation. By the way, effects can also be created using the Lumia Imaging SDK . The source code for Lumia-imaging-sdk can also be found on GitHub . In addition, some effects are available using the Windows.UI.Composition namespace .

    Sometimes it becomes necessary to display graphics not immediately, but during program execution. Save it to a file, display it or get an array of pixels. This option is called Offscreen drawing.

    Say, here is an example in which the XAML CanvasControl element is not used at all, but a simple image element is used


    You can process the image and display it, adding a saturation effect, as follows:

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

    I like it even more (although I can’t say anything about performance comparison)



    In order to compose a small composition and overlay text on a picture, we need a namespace:

    using Microsoft.Graphics.Canvas.Text;

    And a similar snippet:

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



    You can combine 2 images using the blend effect:

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



    Some effects can be combined. Using the following snippet combining many effects, you can get the effect of text glow

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



    An interesting text effect that is often associated with Win2D is the animated effect of burning text.



    Direct links to the BurningTextExample.xaml and BurningTextExample.xaml.cs examples I will probably leave here: BurningTextExample.xaml / BurningTextExample.xaml.cs .

    Just like in the case of the UWP Community Toolkit, it is possible to download the application with examples of use for Win2D. The application is called Win2D Example Gallery . The source code for the application is on github .

    Personally, I liked the following picture most of all:



    As it turned out, it was completely drawn using DrawLine, DrawEllipse, DrawCircle, etc.

    The library is updated regularly and therefore new beautiful effects can be expected.

    Also popular now: