# Introduction

`Bézier curves` have been a fascinating and intriguing concept to me. Simply put, Bézier curves allow us to define curves using mathematical equations. Harnessing these equations to bend the curves to our will can be daunting for those who are unfamiliar with the concept. If you wish to know about Bézier curves in details, look at this excellent tutorial on Bézier Curves.

Often, I have come across node graphs which show a set of nodes connected together, not by straight lines but nice curved lines. The curved lines give the graph a more sophisticated look. Here is a cool example of connectors used in BitWig Studio 3.

If you moved the nodes around, the curved lines adjusted their curvature accordingly. Initially I thought that, to accomplish this, some really complicated mathematical calculations need to be done to get the precise curvature in the connectors. However, when I gave it a closer look, I realized it was a simple Cubic Bézier. In this post I will tell you how I achieved this

# Cubic Bézier

To define a cubic bézier, you need four points – two endpoints and two control points. The curve will always pass through the endpoints while they may or may not pass through the control points. The control points influence the curvature (see the image below).

(The above image was created from this awesome site.)

# Creating a Cubic Bézier connector

Say we are drawing a node graph and we need to connect two nodes with a Cubic Bézier. To create a Cubic Bézier, we already have the endpoints i.e. the predefined points within the node. What we need to calculate is the control points.

If you draw the tangent of the curve at the endpoints, you will see that the tangent is horizontal. It means that the curve is horizontal at the endpoints. To achieve this, the control point and its corresponding endpoint must lie on a horizontal line (i.e. their y-ordinate must be same). That makes matter more simple. We just need to calculate how far are the control points from their respective endpoints on the x-axis. To keep the curve uniform, I just calculate it the following way

``````var controlPointDistance = Math.Abs(endPoint1.X - endPoint2.X) / 2f;
``````

Now that we have all the required points, we can render the bézier curve using the APIs provided by Windows. For example, using Win2d, you can create the curve in the following way

``````using (var pathBuilder = new CanvasPathBuilder(sender))
{
pathBuilder.BeginFigure(endPoint1);
pathBuilder.EndFigure(CanvasFigureLoop.Open);
var geometry = CanvasGeometry.CreatePath(pathBuilder);
drawingSession.DrawGeometry(geometry, Vector2.Zero, color, strokeThickness);
}
``````

Using the above code you can render your own Bézier connector.

The source code for the sample project is available in GitHub.

Happy Coding!

## Having fun with CompositionGeometricClip and CompositionProToolkit v0.9!

In this post, I will be telling you about the new features available in the CompositionProToolkit v0.9 and will also explain in detail, how I used these features to create the following effect.

Today I am releasing CompositionProToolkit v0.9 which includes new extension methods and updates to existing features which will help the users use Composition APIs more efficiently. This release focuses on the CompositionGeometry related APIs.

NOTE: CompositioProToolkit v0.9 is built using Windows Insider SDK 17723. If you are not a Windows Insider and you are still on the April 2018 Update, this version might not work for you. Kindly use v0.8.

You can now use the Win2d Mini Path Language to create `CompositionPath`, `CompositionPathGeometry`, `CompositionGeometricClip`, `CompositionSpriteShape` objects. (If you want to know more about Win2d Mini Path Language see here)

Here are the APIs

```public static CompositionPath CreatePath(this Compositor compositor, string pathData);
public static CompositionPathGeometry CreatePathGeometry(this Compositor compositor, string pathData);
public static CompositionSpriteShape CreateSpriteShape(this Compositor compositor, string pathData);
public static CompositionGeometricClip CreateGeometricClip(this Compositor compositor, CanvasGeometry geometry);
public static CompositionGeometricClip CreateGeometricClip(this Compositor compositor, string pathData);
```

Example

```var pathData = "M 100, 100 L 200, 200 L100,300Z";
var shape = compositor.CreateSpriteShape(pathData);

var clipGeometry = compositor.CreateGeometricClip("O 200 200 150 150");
```

# FrostedGlass Control

This new control has been added to CompositionProToolkit and it provides an efficient way of displaying an acrylic background (with rounded corners) to floating dialogs like Flyout, ContentDialog etc.

`FrostedGlass` control has the following properties

Dependency Property Type Description Default Value
TintColor `Color` The tint of the FrostedGlass. Colors.White
TintOpacity `Double` The opacity of the tint color 0.6
MultiplyAmount `Double` Indicates how much the multiplication result (Tint * Backdrop) should be included in the output image 1.0
BlurAmount `Double` The amount of blurring that should be done. 15.0
BackdropAmount `Double` The amount of backdrop brush that should be present in the Frosted Glass. Value should be within 0 and 1 (inclusive). 0.75
DisplayShadow `Boolean` Whether the shadow of the FrostedGlass should be displayed. True
ShadowColor `Color` The color of the shadow. Colors.Black
ShadowOpacity `Double` The opacity of the shadow. 0.5
ShadowBlurRadius `Double` The Blur Radius of the shadow. 16.0
ShadowOffsetX `Double` The offset of the shadow on the x-axis 4.0
ShadowOffsetY `Double` The offset of the shadow on the y-axis 4.0

Here is an example of creating a custom acrylic flyout

```<Page.Resources>
<Style x:Key="CustomFlyoutPresenterStyle" TargetType="FlyoutPresenter">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Background" Value="{ThemeResource SystemControlBackgroundChromeMediumLowBrush}" />
<Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundChromeHighBrush}" />
<Setter Property="BorderThickness" Value="{ThemeResource FlyoutBorderThemeThickness}" />
<Setter Property="MinWidth" Value="800" />
<Setter Property="MaxWidth" Value="800" />
<Setter Property="MinHeight" Value="650" />
<Setter Property="MaxHeight" Value="650" />
<Setter Property="ScrollViewer.HorizontalScrollMode" Value="Auto" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.VerticalScrollMode" Value="Auto" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.ZoomMode" Value="Disabled" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="FlyoutPresenter">
<Grid Background="Transparent">
<ContentPresenter
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<Flyout x:Key="CustomFlyout" FlyoutPresenterStyle="{StaticResource CustomFlyoutPresenterStyle}">
<Grid>
MultiplyAmount="1"
TintColor="#EFEFEF" />
<!-- Additional Content goes below -->
</Grid>
</Flyout>
</Page.Resources>

<Button
x:Name="CalligraphyPenButton"
Margin="10,4,0,4"
VerticalAlignment="Center"
HorizontalAlignment="Center"
FlyoutBase.AttachedFlyout="{StaticResource CustomFlyout}">
</Button>

private void CalligraphyPenButton_OnClick(object sender, RoutedEventArgs e)
{
FlyoutBase.ShowAttachedFlyout(CalligraphyPenButton);
}

```

Here is an example of a flyout using `FrostedGlass` in my Symmetro app

# Fun with CompositionGeometricClip

Normally, the content of a `Visual` is rectangular in shape.

You can now use the `CompositionGeometricClip` class to give the visual content a non-rectangular look.

And the best feature of it – just like a `Visual`, `CompositionGeometricClip` has animatable properties!

Now let us see how we can use the `CompositionGeometricClip` to create a cool effect.

## Creating the visuals

In this example, we will be using a sample image (400 x 400 pixel resolution). We will use this to create a `CompositionSurfaceBrush` to apply to the visual of the same size.

```var imageSurface = await _generator.CreateImageSurfaceAsync(
new Uri("ms-appx:///Assets/Images/Cat.png"),
new Size(400, 400),
ImageSurfaceOptions.Default);
var imageBrush = _compositor.CreateSurfaceBrush(imageSurface);
```

We will now create a bunch of visuals which will have the same `CompositionSurfaceBrush` applied. They will be stacked one on top of the other just like you stack a set of plates. If you try to visualize how the visual would look when viewed from a side it would be something like this.

Now starting from the bottom, we need to apply a circular clip to each of the visual. The diameter of the circular clip will reduce as we move up from the bottom visual to the topmost. The side view would look something like this.

The area colored red represents the clipped part of the visual (which will not be visible) while the area in blue will be displayed.

```for (var i = 0; i < 145; i++)
{
var visual = _compositor.CreateSpriteVisual();
visual.Offset = new Vector3(400, 400, 0);
visual.Size = new Vector2(400, 400);
visual.Brush = imageBrush;
visual.AnchorPoint = new Vector2(0.5f);
var radius = 290 - (i * 2);
// Create the GeometricClip for this visual
var clipGeometry = CanvasGeometry.CreateCircle(null, new Vector2(200, 200), radius);
visual.Clip = _compositor.CreateGeometricClip(clipGeometry);

_rootVisual.Children.InsertAtTop(visual);
}
```

Here is a sample stack of clipped visuals

## Animating the offset of the visuals

Now we need to track the pointer when the pointer is pressed & dragged, and move the visuals in a buttery smooth way.

For this purpose we will divide the visuals into two groups.

The first group will consist of the top most visual only and it will track the pointer and animate its offset accordingly.

```// Get the CompositionPropertySet which tracks the pointer position on the RootGrid
_pointerTrackerSet = ElementCompositionPreview.GetPointerPositionPropertySet(RootGrid);
// Animate the topmost visual so that it tracks and follows the pointer position
_pointerTrackerAnimation = _compositor.GenerateVector3KeyFrameAnimation()
.HavingDuration(PointerTrackerAnimationDuration)
.RepeatsForever();

_pointerTrackerAnimation.InsertExpressionKeyFrame(0f, c => new VisualTarget().Offset);
_pointerTrackerAnimation.InsertExpressionKeyFrame(
1f,
c => c.Lerp(new VisualTarget().Offset, _pointerTrackerSet.Get("Position"), DefaultLerpAmount),
_compositor.CreateEaseOutQuinticEasingFunction());
```

When the pointer is pressed we will start the above animation for the topmost visual and stop it when the pointer is released.

The second group will contain the rest of the visuals and each visual will track the position of the visual above it and animate its own offset accordingly.

```public sealed partial class CompositionGeometricClipPage : Page
{
private Compositor _compositor;
private ICompositionGenerator _generator;
private SpriteVisual _dragVisual;
private CompositionPropertySet _pointerTrackerSet;
private SpriteVisual _rootVisual;
private List<SpriteVisual> _visuals;
private KeyFrameAnimation<Vector3> _pointerTrackerAnimation;

private const float DefaultLerpAmount = 0.75f;
private readonly TimeSpan ChildOffsetAnimationDuration = TimeSpan.FromSeconds(0.097f);
private readonly TimeSpan PointerTrackerAnimationDuration = TimeSpan.FromSeconds(1f);

public CompositionGeometricClipPage()
{
this.InitializeComponent();
_visuals = new List<SpriteVisual>();
}

private async void OnPageLoaded(object sender, RoutedEventArgs e)
{
_compositor = Window.Current.Compositor;
_generator = _compositor.CreateCompositionGenerator();
var gridSize = new Vector2((float)RootGrid.ActualWidth, (float)RootGrid.ActualHeight);
var anim =_compositor.CreatePathKeyFrameAnimation();
_rootVisual = _compositor.CreateSpriteVisual();
_rootVisual.Size = gridSize;

// Create the surface brush from the image
var imageSurface = await _generator.CreateImageSurfaceAsync(
new Uri("ms-appx:///Assets/Images/Cat.png"),
new Size(400, 400),
ImageSurfaceOptions.Default);
var imageBrush = _compositor.CreateSurfaceBrush(imageSurface);

// Create the clipped visuals
for (var i = 0; i < 145; i++)
{
var visual = _compositor.CreateSpriteVisual();
visual.Offset = new Vector3(400, 400, 0);
visual.Size = new Vector2(400, 400);
visual.Brush = imageBrush;
visual.AnchorPoint = new Vector2(0.5f);
var radius = 290 - (i * 2);
// Create the GeometricClip for this visual
var clipGeometry = CanvasGeometry.CreateCircle(null, new Vector2(200, 200), radius);
visual.Clip = _compositor.CreateGeometricClip(clipGeometry);

_rootVisual.Children.InsertAtTop(visual);
}

// Display the rootVisual
ElementCompositionPreview.SetElementChildVisual(RootGrid, _rootVisual);

// Reverse the visuals list so that the items in the list are now sorted
// in z-order from top to bottom
_visuals.Reverse();
// The topmost visual would track the pointer position
_dragVisual = _visuals.First();

// Get the CompositionPropertySet which tracks the pointer position on the RootGrid
_pointerTrackerSet = ElementCompositionPreview.GetPointerPositionPropertySet(RootGrid);
// Animate the topmost visual so that it tracks and follows the pointer position
_pointerTrackerAnimation = _compositor.GenerateVector3KeyFrameAnimation()
.HavingDuration(PointerTrackerAnimationDuration)
.RepeatsForever();

_pointerTrackerAnimation.InsertExpressionKeyFrame(0f, c => new VisualTarget().Offset);
_pointerTrackerAnimation.InsertExpressionKeyFrame(
1f,
c => c.Lerp(new VisualTarget().Offset, _pointerTrackerSet.Get<Vector3>("Position"), DefaultLerpAmount),
_compositor.CreateEaseOutQuinticEasingFunction());

// Animate the remaining visuals in such a way that each visual tracks and follows the
// position of the visual above it.
var prevChild = _dragVisual;
foreach (var child in _visuals.Skip(1))
{
var offsetAnimation = _compositor.GenerateVector3KeyFrameAnimation()
.HavingDuration(ChildOffsetAnimationDuration)
.RepeatsForever();

offsetAnimation.InsertExpressionKeyFrame(0f, c => new VisualTarget().Offset);
offsetAnimation.InsertExpressionKeyFrame(
1f,
c => c.Lerp(new VisualTarget().Offset, prevChild.Offset, DefaultLerpAmount),
_compositor.CreateEaseOutQuinticEasingFunction());

child.StartAnimation(() => child.Offset, offsetAnimation);

prevChild = child;
}
}

/// <summary>
/// Starts the animation to follow the pointer position
/// </summary>
/// <param name="sender">Pointer</param>
/// <param name="e">PointerRoutedEventArgs</param>
private void OnPointerPressed(object sender, PointerRoutedEventArgs e)
{
_dragVisual.StartAnimation(() => _dragVisual.Offset, _pointerTrackerAnimation);
}

/// <summary>
/// Starts the animation to follow the pointer position
/// </summary>
/// <param name="sender">Pointer</param>
/// <param name="e">PointerRoutedEventArgs</param>
private void OnPointerReleased(object sender, PointerRoutedEventArgs e)
{
_dragVisual.StopAnimation(() => _dragVisual.Offset);
}
}
```

You can check out the complete code in SampleGallery

You must have noticed that, in the above code, around 145 animations are simultaneously executing. I was initally doubtful whether running so many animations would have high CPU utilization.

However, upon executing the code, I was amazed to find that the CPU utilization never went over 1% and the whole animation was buttery smooth! Kudos to the Composition team!

The latest source code is available in GitHub and the Nuget package is available here.

Happy Coding! 🙂

## CompositionProToolkit v0.7 Released

This update of CompositionProToolkit brings a breaking change and introduces two new controls which are completely written using Composition APIs.

# Breaking Change : CompositionGeneratorFactory is deprecated!

CompositionGeneratorFactory class has been deprecated and removed. Now you can use the Compositor‘s CreateCompositionGenerator() method to instantiate the  CompositionGenerator.

``````
var generator = compositor.CreateCompositionGenerator();
``````

# FluidToggleSwitch

FluidToggleSwitch is a toggleswitch control which uses Composition Visuals to render its components and provides a richer look and feel to the ToggleSwitch control. There are three primary components within the ToggleSwitch

• Background – The outermost circular area.
• Track – The pill shaped area.
• Thumb – The innermost circular area.

The reason FluidToggleSwitch is encapsulated with a circular background component is because the hit area for a touch input is normally circular.

The following properties allow you to customize the FluidToggleSwitch

Dependency Property Type Description Default Value
ActiveColor `Color` Gets or sets the Color of the FluidToggleSwitch in Checked state. #4cd964
InactiveColor `Color` Gets or sets the Color of the FluidToggleSwitch in Unchecked state. #dfdfdf
DisabledColor `Color` Gets or sets the Color of the FluidToggleSwitch in Disabled state. #eaeaea

The above properties define the color of the Background component. The color of the Track component is derived automatically from the above properties. The color of the Thumb is white.

# ProfileControl

ProfileControl allows you to display an image (normally a user profile image) in an intuitive way. This control is mainly implemented using Composition Visuals and animations which provide a rich user experience. Depending on the width and height of the ProfileControl, its shape can be either circular or elliptical. There are two main components within the ProfileControl

• Background Visual – The outermost circular or elliptical area. This area is filled with the CompositionBackdropBrush which blends the control with whatever is rendered beneath the control.
• Image Visual – The innermost circular or elliptical area. This area renders the image provided.

The following properties allow you to customize the ProfileControl

Dependency Property Type Description Default Value
BlurRadius `Double` Gets or sets the amount by which the brush of the Background Visual must be blurred. 20.0
BorderGap `Double` Gets or sets the uniform gap between the Background visual and the Image visual. 10.0
FluidReveal `Boolean` Indicates whether the reveal animation should automatically be played when the Source property of the ProfileControl changes. If set to False, the image specified by the Source property is displayed directly without any animation. True
RevealDuration `TimeSpan` Gets or sets the duration of the reveal animation. 1 sec
Source `Uri` Gets or sets the Uri of the image to be displayed in the ProfileControl. null
Stretch `Stretch` Indicates how the image content is resized to fill its allocated space in the Image Visual. Stretch.Uniform
Tint `Color` Gets or sets the color overlay on the background of the ProfileControl. Colors.White

I shall provide more details into how these controls were implemented using Composition APIs in my next post.

# Source Code, Nuget & Documentation

Happy Coding! 🙂

## CompositionProToolkit v0.6 Released!

Well, it has been almost 6 months since my last post. I have been busy working on a few apps and learning a few new technologies. In the meantime, Windows 10 Creators update was released, Build 2017 happened and Microsoft introduced the Fluent Design System (a much needed feature for Windows 10 UX). The Windows Composition team also open sourced the Expression Builder code which allows you to define the expressions in ExpressionAnimations in a more intuitive way.

A couple of weeks ago, I felt it was time to revisit my code in CompositionProToolkit and update it to the latest Windows SDK features. CompositionProToolkit version 0.5.x releases were more biased towards Win2d. So I decided to dedicate version 0.6 to the CompositionProToolkit.Expressions namespace.

I had a look at the Expression Builder code to understand its features. It helps the developers to create type-safe expressions using `ExpressionNode` (and its derivatives). I was wondering if there was a way to modify the authoring feature in such a way that the `ExpressionNode` (and its derivatives) remain hidden from view to the developer and s/he may use a more simpler way to specify the expression with type-safety (using Lambda expressions).

It was then I realized the code in CompositionProToolkit.Expressions namespace did not support creation of expression templates.

I realized that there was a huge scope of improvement in the CompositionProToolkit.Expressions namespace and it was possible to introduce templates within the lambda expressions.

Thus, I am happy to announce that with the release of CompositionProToolkit v0.6, Expression parsing is more robust now. A lot of extension methods have been added to help the developer minimize the code written to create animations.

# Defining the ExpressionAnimation and KeyFrameAnimation

The following extension methods have been defined on the Compositor to create the appropriate `ExpressionAnimation` object.

``````public static ExpressionAnimation CreateColorExpressionAnimation(this Compositor compositor);
public static ExpressionAnimation CreateQuaternionExpressionAnimation(this Compositor compositor);
public static ExpressionAnimation CreateScalarExpressionAnimation(this Compositor compositor);
public static ExpressionAnimation CreateVector2ExpressionAnimation(this Compositor compositor);
public static ExpressionAnimation CreateVector3ExpressionAnimation(this Compositor compositor);
public static ExpressionAnimation CreateVector4ExpressionAnimation(this Compositor compositor);
public static ExpressionAnimation CreateMatrix4x4ExpressionAnimation(this Compositor compositor);
``````

The following extension method is defined for the `Compositor` to create a `KeyFrameAnimation` object for the appropriate animating property

``````public static KeyFrameAnimation GenerateColorKeyFrameAnimation(this Compositor compositor);
public static KeyFrameAnimation GenerateQuaternionKeyFrameAnimation(this Compositor compositor);
public static KeyFrameAnimation GenerateScalarKeyFrameAnimation(this Compositor compositor);
public static KeyFrameAnimation GenerateVector2KeyFrameAnimation(this Compositor compositor);
public static KeyFrameAnimation GenerateVector3KeyFrameAnimation(this Compositor compositor);
public static KeyFrameAnimation GenerateVector4KeyFrameAnimation(this Compositor compositor);
``````

After creating the `ExpressionAnimation` object you can set its `Expression` property with the appropriate Expression.

The following extension methods allow StartAnimation to be called directly using an `ExpressionAnimation` or a `KeyFrameAnimation` object.

``````public static void StartAnimation(this CompositionObject compositionObject,
Expression expression, KeyFrameAnimation keyframeAnimation);
public static void StartAnimation(this CompositionObject compositionObject,
Expression expression, ExpressionAnimation expressionAnimation);
``````

# Using CompositionPropertySet within the Expression

In order to use a CompositionPropertySet within the Expression the following `GetXXX` extension methods have been defined

``````public static bool GetBoolean(this CompositionPropertySet propertySet, string key);
public static Color GetColor(this CompositionPropertySet propertySet, string key);
public static Matrix3x2 GetMatrix3x2(this CompositionPropertySet propertySet, string key);
public static Matrix4x4 GetMatrix4x4(this CompositionPropertySet propertySet, string key);
public static Quaternion GetQuaternion(this CompositionPropertySet propertySet, string key);
public static float GetScalar(this CompositionPropertySet propertySet, string key);
public static Vector2 GetVector2(this CompositionPropertySet propertySet, string key);
public static Vector3 GetVector3(this CompositionPropertySet propertySet, string key);
public static Vector4 GetVector4(this CompositionPropertySet propertySet, string key);
``````

# Expression Targets and Templates

It is now possible to use the `new` operator inside expressions. You can also define Expression Targets and Expression Templates within the Expression.

Expression Targets allow you to access the composition object (on which the expression animation is executed) within the expression.

Expression Templates allow you to reuse an expression by connecting them to different references (thus creating separate animations). It is similar to the way C# Generics allows you to define a class template and reuse the template for different types.

Here is an example

``````var visual = _compositor.CreateSpriteVisual();
visual.Offset = new Vector3(20, 30, 40);
visual.Size = new Vector2(200, 100);

var delta = new Vector3(50);

var offsetAnimation = _compositor.CreateVector3ExpressionAnimation();
offsetAnimation.Expression =
c => new VisualReference("myVisual").CenterPoint + new Vector3(10, 20, 30) + delta;
offsetAnimation.SetReference("myVisual", visual);

visual.StartAnimation(() => visual.CenterPoint, offsetAnimation);

var visual2 = _compositor.CreateSpriteVisual();
visual2.Offset = new Vector3(10, 10, 10);
visual2.Size = new Vector2(100, 100);

offsetAnimation.SetReference("myVisual", visual2);
offsetAnimation.SetReference("delta", new Vector3(100));

visual2.StartAnimation(() => visual2.CenterPoint, offsetAnimation);
``````

# Using Arrays in Expression

You can use an `Array` of objects deriving from CompositionObject within your Expression.

## Example

``````var visual1 = compositor.CreateSpriteVisual();
...
var visual2 = compositor.CreateSpriteVisual();
...
var visualArray = new Visual[] { visual1, visual2 };

var offsetAnimation = compositor.CreateVector3ExpressionAnimation();
offsetAnimation.Expression = c => visualArray[0].Offset + new Vector(20);

visualArray[1].StartAnimation(() => visualArray[1].Offset, offsetAnimation);
``````

# Using List<> in Expression

You can use a `List<>` of objects deriving from CompositionObject within your Expression.

## Example

``````var visual1 = compositor.CreateSpriteVisual();
...
var visual2 = compositor.CreateSpriteVisual();
...
var visualList = new List { visual1, visual2 };

var offsetAnimation = compositor.CreateVector3ExpressionAnimation();
offsetAnimation.Expression = c => visualList[0].Offset + new Vector(20);

visualList[1].StartAnimation(() => visualList[1].Offset, offsetAnimation);
``````

# Using Dictionary<,> in Expression

You can use a `Dictionary<TKey, TValue>` within your Expression.

`TKey` can be of types – `int`, `float`, `double` or `string`.

`TValue` should be an object deriving from `CompositionObject`.

## Example

``````var visual1 = compositor.CreateSpriteVisual();
...
var visual2 = compositor.CreateSpriteVisual();
...
var visualDictionary = new Dictionary<string, Visual>
{
["first"] = visual1,
["second"] = visual2
};

var offsetAnimation = compositor.CreateVector3ExpressionAnimation();
offsetAnimation.Expression = c => visualDictionary["first"].Offset + new Vector(20);

visualDictionary["second"].StartAnimation(() => visualDictionary["second"], offsetAnimation);
``````

# Custom Cubic Bezier Easing Functions

The following extension methods have been added to `Compositor` to create predefined `CubicBezierEasingFunctions` (these custom cubic bezier easing functions are based on the Robert Penner’s Easing Equations and the values are obtained from Ceaser CSS Easing Animation Tool )

``````public static CubicBezierEasingFunction CreateEaseInBackEasingFunction();
public static CubicBezierEasingFunction CreateEaseInCircleEasingFunction();
public static CubicBezierEasingFunction CreateEaseInCubicEasingFunction();
public static CubicBezierEasingFunction CreateEaseInExponentialFunction();
public static CubicBezierEasingFunction CreateEaseInQuarticEasingFunction();
public static CubicBezierEasingFunction CreateEaseInQuinticEasingFunction();
public static CubicBezierEasingFunction CreateEaseInSineEasingFunction();

public static CubicBezierEasingFunction CreateEaseOutBackEasingFunction();
public static CubicBezierEasingFunction CreateEaseOutCircleEasingFunction();
public static CubicBezierEasingFunction CreateEaseOutCubicEasingFunction();
public static CubicBezierEasingFunction CreateEaseOutExponentialFunction();
public static CubicBezierEasingFunction CreateEaseOutQuarticEasingFunction();
public static CubicBezierEasingFunction CreateEaseOutQuinticEasingFunction();
public static CubicBezierEasingFunction CreateEaseOutSineEasingFunction();

public static CubicBezierEasingFunction CreateEaseInOutBackEasingFunction();
public static CubicBezierEasingFunction CreateEaseInOutCircleEasingFunction();
public static CubicBezierEasingFunction CreateEaseInOutCubicEasingFunction();
public static CubicBezierEasingFunction CreateEaseInOutExponentialFunction();
public static CubicBezierEasingFunction CreateEaseInOutQuarticEasingFunction();
public static CubicBezierEasingFunction CreateEaseInOutQuinticEasingFunction();
public static CubicBezierEasingFunction CreateEaseInOutSineEasingFunction();
``````

# DeviceLostHelper

CompositionProToolkit now uses the `DeviceLostHelper` class (provided in the WindowsUIDevLabs Sample Gallery application) to watch for `CanvasDevice` and it raises an appropriate event when the device is lost.

# Project structure and Nuget

CompositionProToolkit v0.6 also revamps the project structure. The CompositionProToolkit.Ref project has been discarded and the CompositionDeviceHelper project has been added. It is a C++/CX project which encapsulates the `DeviceLostHelper` class.

The `CompositionProToolkit.nuspec` has also been updated. Now it includes the XML documentation file to provide better Intellisense support when using CompositionProToolkit in your code. I had some issues creating a single Nuget package targeting x86, x64 & ARM – which internally contained a UWP library and a Windows Runtime Component. There is no clear documentation provided for this scenario. I had to refer through numerous blogs and forum posts to finally get the nuget structure right. I will write in more detail about this in my next blog post.

# Source Code, Nuget & Documentation

Happy Coding!

## CompositionProToolkit v0.5.1 released : Win2d Mini Language

Well, this is the first update for CompositionProToolkit in 2017, and it has turned out to be a huge update. I continued to build upon the work which I had started in the previous update i.e. parsing the SVG path language to convert it to CanvasGeometry. Now I am happy to announce that in this version, I have added more features to the existing path language, more commands to represent new shapes, brushes and strokes. It has now evolved into a more robust language which I am terming as the Win2d Mini Language.

In this post, I shall be explaining the work done to incorporate Win2d Mini Language into CompositionProToolkit and other related features.

# ICanvasStroke and CanvasStroke

In Win2d, the stroke, that is used to render an outline to a CanvasGeometry, is comprised of three components

• Stroke Width – defines the width of the stroke.
• Stroke Brush – defines the ICanvasBrush that will be used to render the stroke.
• Stroke Style – defines the CanvasStrokeStyle for the stroke.

ICanvasStroke interface, defined in the CompositionProToolkit.Win2d namespace, encapsulates these three components and the CanvasStroke class implements this interface. It provides several constructors to define the stroke.

``````public interface ICanvasStroke
{
ICanvasBrush Brush { get; }
float Width { get; }
CanvasStrokeStyle Style { get; }
Matrix3x2 Transform { get; set; }
}

public sealed class CanvasStroke : ICanvasStroke
{
public float Width { get; }
public CanvasStrokeStyle Style { get; }
public ICanvasBrush Brush { get; }
public Matrix3x2 Transform { get; set; }
public CanvasStroke(ICanvasBrush brush, float strokeWidth = 1f);
public CanvasStroke(ICanvasBrush brush, float strokeWidth, CanvasStrokeStyle strokeStyle);
public CanvasStroke(ICanvasResourceCreator device, Color strokeColor, float strokeWidth = 1f);
public CanvasStroke(ICanvasResourceCreator device, Color strokeColor, float strokeWidth,
CanvasStrokeStyle strokeStyle);
}
``````

The Transform property in CanvasStroke gets or sets the Transform property of the stroke brush.

# IGeometrySurface

The IGeometrySurface interface is now updated to include ICanvasStroke to specify the definition of the stroke to be rendered on its geometry.

The following APIs are provided in ICompositionGenerator to create a IGeometrySurface

``````IGeometrySurface CreateGeometrySurface(Size size, CanvasGeometry geometry,
ICanvasStroke stroke);
IGeometrySurface CreateGeometrySurface(Size size, CanvasGeometry geometry,
Color fillColor);
IGeometrySurface CreateGeometrySurface(Size size, CanvasGeometry geometry,
ICanvasStroke stroke, Color fillColor);
IGeometrySurface CreateGeometrySurface(Size size, CanvasGeometry geometry,
Color fillColor, Color backgroundColor);
IGeometrySurface CreateGeometrySurface(Size size, CanvasGeometry geometry,
ICanvasStroke stroke, Color fillColor, Color backgroundColor);
IGeometrySurface CreateGeometrySurface(Size size, CanvasGeometry geometry,
ICanvasBrush fillBrush);
IGeometrySurface CreateGeometrySurface(Size size, CanvasGeometry geometry,
ICanvasStroke stroke, ICanvasBrush fillBrush);
IGeometrySurface CreateGeometrySurface(Size size, CanvasGeometry geometry,
ICanvasBrush fillBrush, ICanvasBrush backgroundBrush);
IGeometrySurface CreateGeometrySurface(Size size, CanvasGeometry geometry,
ICanvasStroke stroke, ICanvasBrush fillBrush, ICanvasBrush backgroundBrush);
IGeometrySurface CreateGeometrySurface(Size size, CanvasGeometry geometry,
ICanvasBrush fillBrush, Color backgroundColor);
IGeometrySurface CreateGeometrySurface(Size size, CanvasGeometry geometry,
ICanvasStroke stroke, ICanvasBrush fillBrush, Color backgroundColor);
IGeometrySurface CreateGeometrySurface(Size size, CanvasGeometry geometry,
Color fillColor, ICanvasBrush backgroundBrush);
IGeometrySurface CreateGeometrySurface(Size size, CanvasGeometry geometry,
ICanvasStroke stroke, Color fillColor, ICanvasBrush backgroundBrush);
IGeometrySurface CreateGeometrySurface(Size size, CanvasGeometry geometry,
Color foregroundColor);
IGeometrySurface CreateGeometrySurface(Size size, CanvasGeometry geometry,
Color foregroundColor, Color backgroundColor);
IGeometrySurface CreateGeometrySurface(Size size, CanvasGeometry geometry,
ICanvasBrush foregroundBrush);
IGeometrySurface CreateGeometrySurface(Size size, CanvasGeometry geometry,
ICanvasBrush foregroundBrush, ICanvasBrush backgroundBrush);
IGeometrySurface CreateGeometrySurface(Size size, CanvasGeometry geometry,
ICanvasBrush foregroundBrush, Color backgroundColor);
IGeometrySurface CreateGeometrySurface(Size size, CanvasGeometry geometry,
Color foregroundColor, ICanvasBrush backgroundBrush);
``````

IGeometrySurface now provides several additional APIs which allow you to update its geometry, size, stroke, fill and background (and thus the shape of the Visual).

``````void Redraw(CanvasGeometry geometry);
void Redraw(ICanvasStroke stroke);
void Redraw(Color fillColor);
void Redraw(ICanvasStroke stroke, Color fillColor);
void Redraw(Color fillColor, Color backgroundColor);
void Redraw(ICanvasStroke stroke, Color fillColor, Color backgroundColor);
void Redraw(ICanvasBrush fillBrush);
void Redraw(ICanvasStroke stroke, ICanvasBrush fillBrush);
void Redraw(ICanvasBrush fillBrush, ICanvasBrush backgroundBrush);
void Redraw(ICanvasStroke stroke, ICanvasBrush fillBrush,
ICanvasBrush backgroundBrush);
void Redraw(Color fillColor, ICanvasBrush backgroundBrush);
void Redraw(ICanvasStroke stroke, Color fillColor,
ICanvasBrush backgroundBrush);
void Redraw(ICanvasBrush fillBrush, Color backgroundColor);
void Redraw(ICanvasStroke stroke, ICanvasBrush fillBrush,
Color backgroundColor);
void Redraw(Size size, CanvasGeometry geometry);
void Redraw(Size size, CanvasGeometry geometry, ICanvasStroke stroke);
void Redraw(Size size, CanvasGeometry geometry, Color fillColor);
void Redraw(Size size, CanvasGeometry geometry, ICanvasStroke stroke,
Color fillColor);
void Redraw(Size size, CanvasGeometry geometry, Color fillColor,
Color backgroundColor);
void Redraw(Size size, CanvasGeometry geometry, ICanvasStroke stroke,
Color fillColor, Color backgroundColor);
void Redraw(Size size, CanvasGeometry geometry, ICanvasBrush fillBrush);
void Redraw(Size size, CanvasGeometry geometry, ICanvasBrush fillBrush,
ICanvasBrush backgroundBrush);
void Redraw(Size size, CanvasGeometry geometry, ICanvasStroke stroke,
ICanvasBrush fillBrush, ICanvasBrush backgroundBrush);
void Redraw(Size size, CanvasGeometry geometry, ICanvasBrush fillBrush,
Color backgroundColor);
void Redraw(Size size, CanvasGeometry geometry, ICanvasStroke stroke,
ICanvasBrush fillBrush, Color backgroundColor);
void Redraw(Size size, CanvasGeometry geometry, Color fillColor,
ICanvasBrush backgroundBrush);
void Redraw(Size size, CanvasGeometry geometry, ICanvasStroke stroke,
Color fillColor, ICanvasBrush backgroundBrush);
``````

## CanvasDrawingSession extension methods

The following extension methods have been created for CanvasDrawingSession to incorporate ICanvasStroke in its DrawXXX() methods

``````public static void DrawCircle(this CanvasDrawingSession session,
Vector2 centerPoint, float radius, ICanvasStroke stroke);
public static void DrawCircle(this CanvasDrawingSession session,
float x, float y, float radius, ICanvasStroke stroke);
public static void DrawEllipse(this CanvasDrawingSession session,
public static void DrawEllipse(this CanvasDrawingSession session,
public static void DrawGeometry(this CanvasDrawingSession session,
CanvasGeometry geometry, ICanvasStroke stroke);
public static void DrawGeometry(this CanvasDrawingSession session,
CanvasGeometry geometry, Vector2 offset, ICanvasStroke stroke);
public static void DrawGeometry(this CanvasDrawingSession session,
CanvasGeometry geometry, float x, float y, ICanvasStroke stroke);
public static void DrawLine(this CanvasDrawingSession session, Vector2 point0,
Vector2 point1, ICanvasStroke stroke);
public static void DrawLine(this CanvasDrawingSession session, float x0,
float y0, float x1, float y1, ICanvasStroke stroke);
public static void DrawRectangle(this CanvasDrawingSession session, Rect rect,
ICanvasStroke stroke) ;
public static void DrawRectangle(this CanvasDrawingSession session, float x,
float y, float w, float h, ICanvasStroke stroke);
public static void DrawRoundedRectangle(this CanvasDrawingSession session,
public static void DrawRoundedRectangle(this CanvasDrawingSession session, float x,
float y, float w, float h, float radiusX, float radiusY, ICanvasStroke stroke);
``````

# Win2d MiniLanguage specification

The CanvasGeometry class facilitates the drawing and manipulation of complex geometrical shapes. These shapes can be outlined with a stroke and filled with a brush (which can be a solid color, a bitmap pattern or a gradient).

While the CanvasGeometry class provides various static methods to create predefined shapes like Circle, Ellipse, Rectangle, RoundedRectangle, the CanvasPathBuilder class provides several methods to create freeform CanvasGeometry objects.

Creation of a complex freeform geometric shape may involve invoking of several CanvasPathBuilder commands. For example, the following code shows how to create a triangle geometry using CanvasPathBuilder

``````CanvasPathBuilder pathBuilder = new CanvasPathBuilder(device);

pathBuilder.BeginFigure(1, 1);
pathBuilder.EndFigure(CanvasFigureLoop.Closed);

CanvasGeometry triangleGeometry = CanvasGeometry.CreatePath(pathBuilder);
``````

Win2d Mini Language is a powerful and sophisticated language which facilitates specifying complex geometries, color, brushes, strokes and stroke styles in a more compact manner.

Using Win2d Mini-Language, the geometry in above example can be created in the following way

``````string pathData = “M 1 1 300 300 1 300 Z”;
CanvasGeometry triangleGeometry = CanvasObject.CreateGeometry(device, pathData);
``````

Win2d Mini Language now contains additional commands which allow easy creation of ICanvasBrush, ICanvasStroke, Color and CanvasStrokeStyle.

Win2d Mini Language is based on the SVG (Scalable Vector Graphics) Path language specification.

The following specification document describes the Win2d Markup Language in detail.

Win2d Mini Language Specification.pdf

# Parsing Win2d Mini Language with CanvasObject

The CanvasObject static class replaces the CanvasGeometryParser static class and provides APIs that parse the Win2d Mini Language and instantiate the appropriate objects.

### Color

There are two APIs that convert the hexadecimal color string in #RRGGBB or #AARRGGBB format to the corresponding Color object. The ‘#‘ character is optional.

``````public static Color CreateColor(string hexColor);
public static bool TryCreateColor(string hexColor, out Color color);
``````

The first API will raise an ArgumentException if the argument is not in the correct format while the second API will attempt to convert the color string without raising an exception.

#### From High Dynamic Range Color string

The following API Converts a Vector4 High Dynamic Range Color to Color object. Negative components of the Vector4 will be sanitized by taking the absolute value of the component. The HDR Color components should have value in the range [0, 1]. If their value is more than 1, they will be clamped at 1. Vector4’s X, Y, Z, W components match to Color’s R, G, B, A components respectively.

``````public static Color CreateColor(Vector4 hdrColor);
``````

### CanvasGeometry

The following API converts a CanvasGeometry path string to CanvasGeometry object

``````public static CanvasGeometry CreateGeometry(ICanvasResourceCreator resourceCreator,
string pathData,
StringBuilder logger = null);
``````

The logger parameter in this method is an option argument of type StringBuilder which can be used to obtain the CanvasPathBuilder commands in text format. It is mainly intended for information/debugging purpose only.

NOTE: This method replaces CanvasGeometryParser.Parse() method (defined in CompositionProToolkit v0.5).

### ICanvasBrush

The following API converts a brush data string to ICanvasBrush object

``````public static ICanvasBrush CreateBrush(ICanvasResourceCreator resourceCreator,
string brushData);
``````

### CanvasStrokeStyle

The following API converts a style data string to CanvasStrokeStyle object

``````public static CanvasStrokeStyle CreateStrokeStyle(string styleData);
``````

### ICanvasStroke

The following API converts a stroke data string to ICanvasStroke object

``````public static ICanvasStroke CreateStroke(ICanvasResourceCreator resourceCreator,
string strokeData);
``````

# CanvasPathBuilder extension methods

Two extension methods have been added to CanvasPathBuilder to add a Rectangle Figure and a RoundedRectangle figure to the path.

``````public static void AddRectangleFigure(this CanvasPathBuilder pathBuilder, float x, float y,
float width, float height)
public static void AddRoundedRectangleFigure(this CanvasPathBuilder pathBuilder, float x, float y,
``````

Check out the Sample Gallery project where you can interact with the CanvasObject class by providing the SVG/XAML path data and converting it to CanvasGeometry. You can alter the StrokeThickness, StrokeColor and FillColor of the rendered geometry.

You can view the CanvasPathBuilder commands called to create the parsed geometry.

# Creating multilayer Vector shapes with CanvasElement

The CanvasElement class allows the creation of multilayer vector shapes. Each layer is represented by the CanvasRenderLayer class. The CanvasRenderLayer implements the ICanvasRenderLayer interface which encapsulates three properties required for rendering a layer

• CanvasGeometry – The geometry to be rendered on the layer.
• ICanvasBrush – The brush to fill the geometry.
• ICanvasStroke – The stroke to outline the geometry.

The CanvasRenderLayer provides several constructors which accept the CanvasGeometry, ICanvasBrush and ICanvasStroke objects or their respective data definition strings.

``````public CanvasRenderLayer(CanvasGeometry geometry, ICanvasBrush brush,
ICanvasStroke stroke);
public CanvasRenderLayer(ICanvasResourceCreator creator, string geometryData,
string brushData, string strokeData);
public CanvasRenderLayer(ICanvasResourceCreator creator, string geometryData,
ICanvasBrush brush, Color strokeColor, float strokeWidth = 1f);
public CanvasRenderLayer(ICanvasResourceCreator creator, string geometryData,
ICanvasBrush brush, Color strokeColor, float strokeWidth,
CanvasStrokeStyle strokeStyle);
public CanvasRenderLayer(ICanvasResourceCreator creator, string geometryData,
ICanvasBrush brush, ICanvasBrush strokeBrush, float strokeWidth = 1);
public CanvasRenderLayer(ICanvasResourceCreator creator, string geometryData,
ICanvasBrush brush, ICanvasBrush strokeBrush, float strokeWidth,
CanvasStrokeStyle strokeStyle);
``````

The CanvasElement class implements the ICanvasElement interface which provides the following properties and APIs

``````interface ICanvasElement
{
List Layers { get; set; }
bool ScaleStroke { get; set; }``````
``````void Render(CanvasDrawingSession session, float width, float height, Vector2 offset,

SpriteVisual CreateVisual(ICompositionGenerator generator, float width, float height,
Vector2 offset, Vector4 padding, float rotation);
``````

}

The Render API renders the CanvasElement layers on a CanvasControl or a CanvasAnimated control for the given dimensions, offset, padding and rotation.

The CreateVisual API creates a SpriteVisual which contains several SpriteVisuals, each representing a layer of the CanvasElement.

The constructor of CanvasElement requires the base dimensions of the element, the layers of the CanvasElement and an option whether to scale the stroke width when the CanvasElement is scaled (default is true).

``````public CanvasElement(float baseWidth, float baseHeight, IEnumerable layers,
bool scaleStroke = true);
``````

Using the base dimension, the CanvasLayer is able to scale its layers to any valid dimensions.

The layers are rendered based on their order in the layers list, i.e. the first layer in the list is rendered first and the subsequent layers are drawn on top of the previous layer. Thus the first layer in the list appears at the bottom and the last layer in the list is rendered top most.

CanvasElement can be primarily used to create vector based icons for UWP applications.

The following example code

``````CanvasElement _element;

private void OnCanvas_CreateResources(CanvasControl sender, CanvasCreateResourcesEventArgs args)
{
var geom1 = CanvasObject.CreateGeometry(sender, "O 116 116 128 128");
var fill1 = CanvasObject.CreateBrush(sender, "SC #00adef");
var stroke1 = CanvasObject.CreateStroke(sender, "ST 8 SC #2a388f");
var layer1 = new CanvasRenderLayer(geom1, fill1, stroke1);

var geom2 = CanvasObject.CreateGeometry(sender, "U 56 56 64 64 8 8");
var fill2 = CanvasObject.CreateBrush(sender, "SC #ed1c24");
var stroke2 = CanvasObject.CreateStroke(sender, "ST 2 SC #404041");
var layer2 = new CanvasRenderLayer(geom2, fill2, stroke2);

var geom3 = CanvasObject.CreateGeometry(sender, "U 136 56 64 64 8 8");
var fill3 = CanvasObject.CreateBrush(sender, "SC #38b449");
var layer3 = new CanvasRenderLayer(geom3, fill3, stroke2);

var geom4 = CanvasObject.CreateGeometry(sender, "U 56 136 64 64 8 8");
var fill4 = CanvasObject.CreateBrush(sender, "SC #fff100");
var layer4 = new CanvasRenderLayer(geom4, fill4, stroke2);

var geom5 = CanvasObject.CreateGeometry(sender, "R 96 96 64 64");
var fill5 = CanvasObject.CreateBrush(sender, "SC #f7931d");
var layer5 = new CanvasRenderLayer(geom5, fill5, stroke2);

var layers = new List { layer1, layer2, layer3, layer4, layer5 };
_element = new CanvasElement(256f, 256f, layers);
}

private void OnCanvas_Draw(CanvasControl sender, CanvasDrawEventArgs args)
{
_element?.Render(args.DrawingSession, 512f, 512f, Vector2.Zero, new Vector4(10), 0f);
}
``````

will create the following

# Utility methods and Constants

## Float constants

The following floating point constants have been defined in the static class Float

• Float.Pi – same as (float)Math.PI radians (180 degrees).
• Float.TwoPi – Two times (float)Math.PI radians (360 degrees).
• Float.PiByTwo – half of (float)Math.PI radians (90 degrees).
• Float.PiByThree – one third of (float)Math.PI radians (600 degrees).
• Float.PiByFour – one fourth of (float)Math.PI radians (45 degrees).
• Float.PiBySix – one sixth of (float)Math.PI radians (30 degrees).
• Float.ThreePiByTwo – three times half of (float)Math.PI radians (270 degrees).

## ToSingle extension method

The Single() extension method for System.Double is now marked as obsolete. Your code will still work, but you will receive a warning during build.

The Single() extension method is now replaced with ToSingle() extension method. It does the same job – converts System.Double to System.Single.

The latest code is available in GitHub and the Nuget package is available here.

## CompositionProToolkit v0.5.0 Holiday Edition released!

After a long gap, I am back with another update to CompositionProToolkit. This time I have added a few helper classes for the Win2d project.

## CanvasPathBuilder extension methods

CanvasPathBuilder allows you to create a freeform path using lines, arcs, Quadratic Beziers and Cubic Beziers. You can then convert this path to a CanvasGeometry. Each path is composed of one or more figures. Each figure definition is encapsulated by the BeginFigure() and EndFigure() methods of CanvasPathBuilder.

If you want to add a circle(or ellipse) or a polygon figure to your path, you need to break the figure into curves or line segments and add them to the path one by one.

I have added the following extension methods to the CanvasPathBuilder to add a circle, ellipse or a polygon figure directly to your path

``````public static void AddCircleFigure (CanvasPathBuilder pathBuilder, Vector2 center, float radius);
public static void AddCircleFigure (CanvasPathBuilder pathBuilder, float x, float y, float radius);
public static void AddPolygonFigure(CanvasPathBuilder pathBuilder, int numSides, float x, float y, float radius);
``````

In the AddPolygonFigure, the radius parameter indicates the distance between the center of the polygon and its vertices.

Note: These methods add the required curves or line segments to your path internally. Since these methods add a figure to your path, you can invoke them only after closing the current figure in the path. They must not be called in between BeginFigure() and EndFigure() calls, otherwise an ArgumentException will be raised. These extension methods call the BeginFigure() and EndFigure() CanvasPathBuilder methods internally.

## CanvasGeometryParser

Last month, while working on my new UWP app, I was using Win2d extensively and found out that in Win2d there was no support for the Path Mini Langugage which is quite popular in WPF/Silverlight. It is a powerful and complex mini-language which you can use to specify path geometries more compactly using Extensible Application Markup Language (XAML). It is derived mainly from the SVG (Scalable Vector Graphics) Path language specification. Here is an example

``````    M8.64,223.948c0,0,143.468,3.431,185.777-181.808c2.673-11.702-1.23-20.154,1.316-33.146h16.287c0,0-3.14,17.248,1.095,30.848c21.392,68.692-4.179,242.343-204.227,196.59L8.64,223.948z
``````

So I added the CanvasGeometryParser class which parses the above string and converts it into appropriate CanvasPathBuilder commands. It contains the following static methods

``````public static CanvasGeometry Parse(ICanvasResourceCreator resourceCreator, System.String pathData, StringBuilder logger = null);
``````

The logger parameter in this method is an option argument of type StringBuilder which can be used to obtain the CanvasPathBuilder commands in text format. It is mainly intended for information/debugging purpose only.

Here is an example usage of the CanvasGeometryParser

``````private void OnCanvasDraw(CanvasControl sender, CanvasDrawEventArgs args)
{
string data = "M8.64,223.948c0,0,143.468,3.431,185.777-181.808c2.673-11.702-1.23-20.154," +
"1.316-33.146h16.287c0,0-3.14,17.248,1.095,30.848c21.392,68.692-4.179,242.343-204.227,196.59L8.64,223.948z";
var geometry = CanvasGeometryParser.Parse(sender, data);

args.DrawingSession.FillGeometry(geometry, Colors.Yellow);
args.DrawingSession.DrawGeometry(geometry, Colors.Black, 2f);
}
``````

Check out the Sample Gallery project in GitHub where you can interact with the CanvasGeometryParser by providing the SVG/XAML path data and converting it to CanvasGeometry. You can alter the StrokeThickness, StrokeColor and FillColor of the rendered geometry.

You can view the CanvasPathBuilder commands called to create the parsed geometry.

Based on the SVG (Scalable Vector Graphics) Path language specification, the following rules must be followed to create the path data

• All instructions are expressed as one character (e.g., a moveto is expressed as an M).
• Superfluous white space and separators such as commas can be eliminated (e.g., M 100 100 L 200 200 contains unnecessary spaces and could be expressed more compactly as M100 100L200 200).
• The command letter can be eliminated on subsequent commands if the same command is used multiple times in a row (e.g., you can drop the second “L” in M 100 200 L 200 100 L -100 -200 and use M 100 200 L 200 100 -100 -200 instead).
• Relative versions of all commands are available (uppercase means absolute coordinates, lowercase means relative coordinates).

In the table below, the following notation is used:

() indicates grouping of parameters.

+ indicates 1 or more of the given parameter(s) is required.

Command Command Letter Parameters Remarks
MoveTo M (x y)+ Starts a new sub-path at the given (x,y) coordinate. If a moveto is followed by multiple pairs of coordinates, the subsequent pairs are treated as implicit lineto commands.
ClosePath Z none Closes the current subpath by drawing a straight line from the current point to current subpath’s initial point.
LineTo L (x y)+ Draws a line from the current point to the given (x,y) coordinate which becomes the new current point.
HorizontalLineTo H (x)+ Draws a horizontal line from the current point (cpx, cpy) to (x, cpy).
VerticalLineTo V (y)+ Draws a vertical line from the current point (cpx, cpy) to (cpx, y).
CubicBezier C (x1 y1 x2 y2 x y)+ Draws a cubic Bézier curve from the current point to (x,y) using (x1,y1) as the control point at the beginning of the curve and (x2,y2) as the control point at the end of the curve.
SmoothCubicBezier S (x2 y2 x y)+ Draws a cubic Bézier curve from the current point to (x,y). The first control point is assumed to be the reflection of the second control point on the previous command relative to the current point. (If there is no previous command or if the previous command was not an C, c, S or s, assume the first control point is coincident with the current point.)
QuadraticBezier Q (x1 y1 x y)+ Draws a quadratic Bézier curve from the current point to (x,y) using (x1,y1) as the control point.
SmoothQuadraticBezier T (x y)+ Draws a quadratic Bézier curve from the current point to (x,y). The control point is assumed to be the reflection of the control point on the previous command relative to the current point. (If there is no previous command or if the previous command was not a Q, q, T or t, assume the control point is coincident with the current point.)
Arc A (radiusX radiusY angle isLargeFlag SweepDirection x y)+ Draws an elliptical arc from the current point to (x, y).
EllipseFigure O (radiusX radiusY x y)+ Adds an Ellipse Figure to the path. The current point remains unchanged.
PolygonFigure P (numSides radius x y)+ Adds an n-sided Polygon Figure to the path. The current point remains unchanged.

The latest code is available in GitHub and the Nuget package is available here.

Happy Holidays! 🙂

## CompositionProToolkit v0.4.6 released

Another update to CompositionProToolkit this week with couple of feature additions to ImageFrame and some bug fixes.

## ImageFrame

ImageFrame now provides a new dependency property called OptimizeShadow which allows multiple ImageFrame instances to share the same DropShadow instance. You can set this property to True when you are displaying several ImageFrame instances within a single container and each ImageFrame instance has shadow enabled. This will reduce the memory footprint.

Dependency Property Type Description Default Value
`OptimizeShadow` `Boolean` Indicates whether the ImageFrame should use a shared shadow object to display the shadow. False

### IDisposable

ImageFrame now implements the IDisposable interface and thus provides a Dispose method to free up resources. ImageFrame internally uses several Composition objects which must be disposed to optimize the memory usage within your app.

### Guidelines for effectively disposing ImageFrame

Consider a scenario where you are displaying several ImageFrame instances in a GridView within a page. When the app navigates away from the page, then you must dispose the ImageFrame instances like this

``````protected override void OnNavigatedFrom(NavigationEventArgs e)
{
foreach (var imgFrame in ItemGridView.GetDescendantsOfType())
{
imgFrame.Dispose();
}
VisualTreeHelper.DisconnectChildrenRecursive(ItemGridView);
ItemGridView.ItemsSource = null;
ItemGridView.Items?.Clear();

base.OnNavigatedFrom(e);
}
``````

## Frosted Glass Effect Brush

A new extension method CreateFrostedGlassBrush has been added to Compositor which, as the name suggests, allows you to create a custom shaped brush which gives a frosted glass effect. The main difference between this method and the CreateMaskedBackdropBrush is that when you apply the FrostedGlassBrush to a visual with a DropShadow, it will look better, whereas with the MaskedBackdropBrush, the shadow will darken the visual.

You can obtain the mask from the FrostedGlass effect brush, to apply to the DropShadow, in the following way

``````var roundRectGeometry = CanvasGeometry.CreateRoundedRectangle(_generator.Device,
0, 0, _width, _height, 25, 25);
roundRectGeometry);
Colors.AntiqueWhite, 30f, _backdropBrush);