[UWP]用Win2D实现镂空文字

1. 前言

以前用PointLight作了一个番茄钟,效果还不错,具体可见这篇文章:html

[UWP]使用PointLight并实现动画效果git

后来试玩了Win2D,此次就用Win2D实现文字的镂空效果,配合PointLight作一个内敛不张扬的番茄钟。github

实现镂空文字的核心思想是使用CanvasGeometry.CreateText从TextLayout获取一个Geometry,而后使用DrawGeometry将它画到DrawingSurface。这篇文章介绍了具体的实现步骤。canvas

2. 参考例子

Win2D Gallery提供了大量Win2D的Sample,此次就参考了其中的文字镂空效果例子,地址和运行效果以下:windows

github.com/microsoft/W…api

3. 实现步骤

Sample的代码量虽多,其实核心并不复杂,下面讲讲须要用到的API:session

3.1 CanvasDevice.GetSharedDevice

由于要用到Win2D,因此首先要引用Win2D.uwp nuget包。由于个人目标不是输出到CanvasControl上,而是想要输出到一个SpriteVisual上,因此使用CanvasDeviceapp

var canvasDevice = CanvasDevice.GetSharedDevice();
复制代码

3.2 CanvasComposition.CreateCompositionGraphicsDevice

而后建立一个Compositor,并将这个Compositor和CanvasDevice关联起来,这里须要使用 CanvasComposition 建立 GraphicsDevice函数

var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
var graphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(compositor, canvasDevice);
复制代码

3.3 CompositionGraphicsDevice.CreateDrawingSurface

而后使用CompositionGraphicsDevice.CreateDrawingSurface建立一个CompositionDrawingSurface对象,它是用来绘画内容的表面:动画

var drawingSurface = graphicsDevice.CreateDrawingSurface(e.NewSize, DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied);
复制代码

3.4 Compositor.CreateSurfaceBrush

使用Compositor.CreateSurfaceBrush建立一个CompositionSurfaceBrush,它的做用是使用像素绘制SpriteVisual,简单来讲它就是一张位图,而后输出到SpriteVisual上:

var maskSurfaceBrush = compositor.CreateSurfaceBrush(drawingSurface);
spriteTextVisual.Brush = maskSurfaceBrush;
复制代码

3.5 CanvasComposition.CreateDrawingSession

有了CompositionDrawingSurface就能够随心所欲了,将这个DrawingSurface做为参数,调用CanvasComposition.CreateDrawingSession建立DrawingSession,DrawingSession提供了多个函数,能够自由地在DrawingSurface上画文字、形状、图片甚至SVG。

using (var session = CanvasComposition.CreateDrawingSession(drawingSurface))
{

}
复制代码

3.6 CanvasTextFormat和CanvasTextLayout

要再DrawingSurface上写字,须要CanvasTextLayout,而CanvasTextLayout中的文字大小、格式等则由CanvasTextFormat定义:

using (var textFormat = new CanvasTextFormat()
{
    FontSize = (float)FontSize,
    Direction = CanvasTextDirection.LeftToRightThenTopToBottom,
    VerticalAlignment = CanvasVerticalAlignment.Center,
    HorizontalAlignment = CanvasHorizontalAlignment.Center,

})
{
    using (var textLayout = new CanvasTextLayout(session, Text, textFormat, width, height))
    {
        Color fontColor = FontColor;
        session.DrawTextLayout(textLayout, 0, 0, fontColor);
    }
}
复制代码

3.7 CanvasGeometry.CreateText

由于个人目标是镂空的文字,因此不能直接使用DrawTextLayout。这里须要使用CanvasGeometry.CreateText从TextLayout获取一个Geometry,而后使用DrawGeometry将它画到DrawingSurface。CanvasStrokeStyle是可选的,它控制边框的虚线。

using (var textGeometry = CanvasGeometry.CreateText(textLayout))
{
    var dashedStroke = new CanvasStrokeStyle()
    {
        DashStyle = DashStyle
    };
    session.DrawGeometry(textGeometry, OutlineColor, (float)StrokeWidth, dashedStroke);
}
复制代码

4. 封装为控件

将上面的代码总结一下,封装为一个OutlineTextControl 控件,它提供了Text、OutlineColor、FontColor等属性,在控件SizeChanged时,或者各个属性改变时调用DrawText从新在CompositionDrawingSurface上绘制文字。代码大体以下:

public class OutlineTextControl : Control
{
    private CompositionDrawingSurface _drawingSurface;

    public OutlineTextControl() {
        var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
        var graphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(compositor, CanvasDevice.GetSharedDevice());
        var spriteTextVisual = compositor.CreateSpriteVisual();

        ElementCompositionPreview.SetElementChildVisual(this, spriteTextVisual);
        SizeChanged += (s, e) =>
        {
            _drawingSurface = graphicsDevice.CreateDrawingSurface(e.NewSize, DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied);
            DrawText();
            var maskSurfaceBrush = compositor.CreateSurfaceBrush(_drawingSurface);
            spriteTextVisual.Brush = maskSurfaceBrush;
            spriteTextVisual.Size = e.NewSize.ToVector2();
        };
        RegisterPropertyChangedCallback(FontSizeProperty, new DependencyPropertyChangedCallback((s, e) =>
        {
            DrawText();
        }));
    }


    private void DrawText() {
        if (ActualHeight == 0 || ActualWidth == 0 || string.IsNullOrWhiteSpace(Text) || _drawingSurface == null)
            return;

        var width = (float)ActualWidth;
        var height = (float)ActualHeight;
        using (var session = CanvasComposition.CreateDrawingSession(_drawingSurface))
        {
            session.Clear(Colors.Transparent);
            using (var textFormat = new CanvasTextFormat()
            {
                FontSize = (float)FontSize,
                Direction = CanvasTextDirection.LeftToRightThenTopToBottom,
                VerticalAlignment = CanvasVerticalAlignment.Center,
                HorizontalAlignment = CanvasHorizontalAlignment.Center,

            })
            {
                using (var textLayout = new CanvasTextLayout(session, Text, textFormat, width, height))
                {
                    if (ShowNonOutlineText)
                    {
                        session.DrawTextLayout(textLayout, 0, 0, FontColor);
                    }

                    using (var textGeometry = CanvasGeometry.CreateText(textLayout))
                    {
                        var dashedStroke = new CanvasStrokeStyle()
                        {
                            DashStyle = DashStyle
                        };
                        session.DrawGeometry(textGeometry, OutlineColor, (float)StrokeWidth, dashedStroke);
                    }
                }
            }
        }
    }

//SOME CODE AND PROPERTIES

}
复制代码

5. 结语

文章开头的那个番茄钟源码能够在这里查看:

OnePomodoro_OutlineTextView.xaml at master

也能够安装个人番茄钟应用试玩一下,安装地址:

一个番茄钟

6. 参考

CanvasComposition Class

CanvasDrawingSession Class

CanvasGeometry Class

CompositionGraphicsDevice Class (Windows.UI.Composition) - Windows UWP applications _ Microsoft Docs

CompositionDrawingSurface Class (Windows.UI.Composition) - Windows UWP applications _ Microsoft Docs

CompositionGraphicsDevice Class (Windows.UI.Composition) - Windows UWP applications _ Microsoft Docs

CompositionSurfaceBrush Class (Windows.UI.Composition) - Windows UWP applications _ Microsoft Docs

相关文章
相关标签/搜索