Есть ли текстовое решение для UWP Composition API, отличное от Win2D?

Чтобы избежать вопроса XY, сначала Y: есть ли способ создать текст в SpriteVisual, который не требует Win2D?

Теперь X: проблема, которую я пытаюсь решить, заключается в том, что мне нужен текст в SpriteVisual (вместо TextBlock), чтобы применить к нему анимацию трехмерного выражения с поворотом в перспективе. Текст на SpriteVisual можно сделать с помощью Win2D. Вот фрагмент образца кода Microsoft:

using (var ds = CanvasComposition.CreateDrawingSession(_drawingSurface))
{
     ds.Clear(Colors.Transparent);
     var rect = new Rect(new Point(2, 2), (_drawingSurface.Size.ToVector2() - new Vector2(4, 4)).ToSize());
     ds.FillRoundedRectangle(rect, 15, 15, Colors.LightBlue);
     ds.DrawRoundedRectangle(rect, 15, 15, Colors.Gray, 2);
     ds.DrawText("This is a composition drawing surface", rect, Colors.Black, new CanvasTextFormat()
     {
          FontFamily = "Comic Sans MS",
          FontSize = 32,
          WordWrapping = CanvasWordWrapping.WholeWord,
          VerticalAlignment = CanvasVerticalAlignment.Center,
          HorizontalAlignment = CanvasHorizontalAlignment.Center
     }
);

_drawingBrush.Surface = _drawingSurface;

_drawingVisual = _compositor.CreateSpriteVisual();
_drawingVisual.Brush = _drawingBrush;

Для раскрашивания текста требуется Win2D ICanvasBrush. Но я хочу анимировать цвет в Expression Animation, поэтому мне нужен цвет текста из CompositionBrush. Теперь я мог создать CompositionMaskBrush с текстовой кистью в качестве маски и CompositionBrush в качестве источника. Но с CompositionMaskBrush я не могу добавить к нему дополнительную маску или какие-либо другие эффекты композиции, что для меня проблематично.

Есть ли альтернативный подход или, возможно, усовершенствование Composition API в инсайдерской сборке, с которым я не знаком?


person Sean O'Neil    schedule 19.01.2019    source источник


Ответы (1)


Y-ответ: Нет, вы можете рисовать текст только на CompositionDrawingSurface с помощью Win2d CanvasDrawingSession. Но вы можете получить Visual из XAML TextBlock с помощью ElementCompositionPreview.GetElementVisual(yourTextBlock) и анимировать его с помощью выражений Composition API + цветовые раскадровки XAML.

X-ответ: вы можете создать альфа-маску из своего текста CompositionDrawingSurface и применить ее к CompositionColorBrush:

    private void CreateColoredText(string text)
    {
        var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
        var graphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(compositor, CanvasDevice.GetSharedDevice());

        var spriteTextVisual = compositor.CreateSpriteVisual();
        spriteTextVisual.Size = new Vector2(512, 512);

        var maskDrawingSurface = graphicsDevice.CreateDrawingSurface(new Size(512, 512), DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied);

        using (var ds = CanvasComposition.CreateDrawingSession(maskDrawingSurface))
        {
            ds.Clear(Colors.Transparent);
            ds.DrawText(text, new Rect(0, 0, 512, 512), Colors.Lime, new CanvasTextFormat
            {
                FontSize = 32,
                FontWeight = FontWeights.Bold,
                VerticalAlignment = CanvasVerticalAlignment.Center,
                HorizontalAlignment = CanvasHorizontalAlignment.Center,
                LineSpacing = 32
            });
        }

        var maskSurfaceBrush = compositor.CreateSurfaceBrush(maskDrawingSurface);
        var surfaceTextBrush = compositor.CreateColorBrush(Colors.DeepPink);
        var maskBrush = compositor.CreateMaskBrush();
        maskBrush.Mask = maskSurfaceBrush;
        maskBrush.Source = surfaceTextBrush;

        var colorAnimation = compositor.CreateColorKeyFrameAnimation();
        colorAnimation.InsertKeyFrame(0.5f, Colors.DeepSkyBlue);
        colorAnimation.InsertKeyFrame(1, Colors.DeepPink);
        colorAnimation.Duration = TimeSpan.FromMilliseconds(1500);
        colorAnimation.IterationBehavior = AnimationIterationBehavior.Forever;

        surfaceTextBrush.StartAnimation("Color", colorAnimation);

        spriteTextVisual.Brush = maskBrush;

        ElementCompositionPreview.SetElementChildVisual(Grid, spriteTextVisual);
    }

Теперь вы можете анимировать цвет и перспективу для своих целей.

person Jet Chopper    schedule 21.01.2019
comment
Мне нужно поиграть с этим, но некоторые возможные проблемы не вызывают у меня головы. Разве TextBlock не нужно добавлять в визуальное дерево, чтобы его визуал даже работал? - person Sean O'Neil; 21.01.2019
comment
Можно ли добавить визуальный элемент к ContainerVisual, но я уверен, что это невозможно. Анимация PlaneProjection работает, применяя преобразование глубины к ContainerVisual и затем анимируя вращение дочернего элемента (вложенного контейнера или спрайта). Также выражения находятся в контейнерах, потому что есть визуальные элементы-близнецы, такие как фон текста. Новый RedirectVisual может помочь, но по нему нет документации. - person Sean O'Neil; 21.01.2019
comment
Также относительно CompositionMaskBrush я уже упоминал об этом, и это то, что я делаю сейчас, но как только вы это сделаете, вы не сможете вложить ее в другую маску или добавить к ней другие эффекты композиции (например, Saturate или Hue Rotate). - person Sean O'Neil; 21.01.2019
comment
Хорошо, я ошибался, компилятор действительно позволяет добавить элемент Visual в ContainerVisual, но я добавил его из TextBlock с текстом в нем, и он ничего не показывает. - person Sean O'Neil; 21.01.2019
comment
Я экспериментировал с этим. Решение TextBlock не сработает. RedirectVisual может работать, но сам TextBlock должен быть добавлен в визуальное дерево XAML, и он должен отрисовывать пиксели, несмотря ни на что. Сворачивание UIElement или установка непрозрачности 0 (или даже 0,01 непрозрачности) делает RedirectVisual пустым. Таким образом, даже если вы можете поместить Visual элемента в ContainerVisual, для всех практических целей он ничего не даст, а RedirectVisual не будет работать, если оригинал также не будет отображен на экране, что было бы очень необычным вариантом использования. - person Sean O'Neil; 21.01.2019