Parse After Effects blur effects from Lottie files. (#393)
* Parse After Effects blur effects from Lottie files. Blur is not yet supported in the translator.
This commit is contained in:
Родитель
e1ed8f24aa
Коммит
385187aba9
|
@ -1,6 +1,5 @@
|
|||
[comment]: # (deprecated)
|
||||
[comment]: # (name:LayerEffectsIsNotSupported)
|
||||
[comment]: # (text:{layer} has an unsupported layer effects, type = {type}.)
|
||||
[comment]: # (name:LayerEffectsIsNotSupported)
|
||||
[comment]: # (text:{layer} has an unsupported layer effect, type = {type}.)
|
||||
|
||||
# Lottie-Windows Warning LP0008
|
||||
|
||||
|
@ -8,7 +7,8 @@ The Lottie file contains Layer Effects. Not all Layer Effects are supported
|
|||
by Lottie-Windows.
|
||||
|
||||
## Remarks
|
||||
This issue does not apply to the latest version. Please upgrade to a newer version of Lottie-Windows.
|
||||
Lottie does not support Layer Effects on most platforms. It may be possible to
|
||||
work around this by modifying your After Effects project to avoid the use of Layer Effects.
|
||||
|
||||
## Resources
|
||||
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
||||
{
|
||||
/// <summary>
|
||||
/// The dimensions affected by a blur.
|
||||
/// </summary>
|
||||
#if PUBLIC_LottieData
|
||||
public
|
||||
#endif
|
||||
enum BlurDimension
|
||||
{
|
||||
Horizontal,
|
||||
Vertical,
|
||||
HorizontalAndVertical,
|
||||
}
|
||||
}
|
|
@ -2,6 +2,8 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -31,7 +33,27 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
|
||||
public enum EffectType
|
||||
{
|
||||
// Type = 25.
|
||||
DropShadow,
|
||||
|
||||
// Type = 29.
|
||||
GaussianBlur,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an effect that was not recognized by the parser.
|
||||
/// </summary>
|
||||
public sealed class Unknown : Effect
|
||||
{
|
||||
readonly double _type;
|
||||
|
||||
public Unknown(double type, string name, bool isEnabled)
|
||||
: base(name, isEnabled)
|
||||
{
|
||||
_type = type;
|
||||
}
|
||||
|
||||
public override EffectType Type => (EffectType)Math.Round(_type);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
||||
{
|
||||
/// <summary>
|
||||
/// Wraps an enum, but implemented as a struct so that
|
||||
/// it can implement <see cref="IEquatable{T}"/> as required by
|
||||
/// <see cref="Animatable{T}"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">An enum type.</typeparam>
|
||||
#if PUBLIC_LottieData
|
||||
public
|
||||
#endif
|
||||
readonly struct Enum<T> : IEquatable<Enum<T>>
|
||||
where T : struct, IComparable
|
||||
{
|
||||
readonly T _value;
|
||||
|
||||
Enum(T value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public T Value => _value;
|
||||
|
||||
public static implicit operator Enum<T>(T value) => new Enum<T>(value);
|
||||
|
||||
public static implicit operator T(Enum<T> value) => value;
|
||||
|
||||
public bool Equals(Enum<T> other) => other._value.CompareTo(_value) == 0;
|
||||
|
||||
public override string? ToString() => _value.ToString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
||||
{
|
||||
/// <summary>
|
||||
/// A Gaussian blur effect.
|
||||
/// </summary>
|
||||
#if PUBLIC_LottieData
|
||||
public
|
||||
#endif
|
||||
sealed class GaussianBlurEffect : Effect
|
||||
{
|
||||
public GaussianBlurEffect(
|
||||
string name,
|
||||
bool isEnabled,
|
||||
Animatable<double> blurriness,
|
||||
Animatable<Enum<BlurDimension>> blurDimensions,
|
||||
Animatable<bool> repeatEdgePixels)
|
||||
: base(
|
||||
name,
|
||||
isEnabled)
|
||||
{
|
||||
Blurriness = blurriness;
|
||||
BlurDimensions = blurDimensions;
|
||||
RepeatEdgePixels = repeatEdgePixels;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The intensity of the blur.
|
||||
/// </summary>
|
||||
public Animatable<double> Blurriness { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the blur is horizontal, vertical, or both.
|
||||
/// </summary>
|
||||
public Animatable<Enum<BlurDimension>> BlurDimensions { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the blur repeats the pixels at the edge.
|
||||
/// </summary>
|
||||
public Animatable<bool> RepeatEdgePixels { get; }
|
||||
|
||||
public override EffectType Type => EffectType.GaussianBlur;
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)AssetCollection.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)BezierSegment.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)BlendMode.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)BlurDimension.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Char.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Color.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ColorGradientStop.cs" />
|
||||
|
@ -24,9 +25,11 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)Effect.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Ellipse.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)EmbeddedImageAsset.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Enum.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ExtensionMethods.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ExternalImageAsset.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Font.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)GaussianBlurEffect.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)GradientStop.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)HoldEasing.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)IAnimatableValue.cs" />
|
||||
|
|
|
@ -344,10 +344,14 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
YamlObject FromEffect(Effect effect, YamlMap superclassContent)
|
||||
{
|
||||
superclassContent.Add(nameof(effect.Type), effect.Type.ToString());
|
||||
superclassContent.Add(nameof(effect.IsEnabled), effect.IsEnabled);
|
||||
return effect.Type switch
|
||||
{
|
||||
Effect.EffectType.DropShadow => FromDropShadowEffect((DropShadowEffect)effect, superclassContent),
|
||||
_ => throw Unreachable,
|
||||
Effect.EffectType.GaussianBlur => FromGaussianBlurEffect((GaussianBlurEffect)effect, superclassContent),
|
||||
|
||||
// Handle all unknown effect types.
|
||||
_ => superclassContent,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -363,6 +367,15 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
return result;
|
||||
}
|
||||
|
||||
YamlObject FromGaussianBlurEffect(GaussianBlurEffect effect, YamlMap superclassContent)
|
||||
{
|
||||
var result = superclassContent;
|
||||
result.Add(nameof(effect.BlurDimensions), FromAnimatable(effect.BlurDimensions));
|
||||
result.Add(nameof(effect.Blurriness), FromAnimatable(effect.Blurriness));
|
||||
result.Add(nameof(effect.RepeatEdgePixels), FromAnimatable(effect.RepeatEdgePixels));
|
||||
return result;
|
||||
}
|
||||
|
||||
YamlObject FromMask(Mask mask)
|
||||
=> new YamlMap
|
||||
{
|
||||
|
@ -468,6 +481,9 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
|
||||
YamlObject FromAnimatable(Animatable<double> animatable) => FromAnimatable(animatable, Scalar);
|
||||
|
||||
YamlObject FromAnimatable<T>(Animatable<Enum<T>> animatable)
|
||||
where T : struct, IComparable => FromAnimatable(animatable, Scalar);
|
||||
|
||||
YamlObject FromAnimatable(Animatable<Opacity> animatable) => FromAnimatable(animatable, Scalar);
|
||||
|
||||
YamlObject FromAnimatable(Animatable<Rotation> animatable) => FromAnimatable(animatable, Scalar);
|
||||
|
@ -676,6 +692,9 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
|
||||
YamlScalar Scalar(Enum type) => Scalar(type, type.ToString());
|
||||
|
||||
YamlObject Scalar<T>(Enum<T> value)
|
||||
where T : struct, IComparable => Scalar(value, value.ToString()!);
|
||||
|
||||
YamlScalar Scalar(Mask.MaskMode type) => Scalar(type, type.ToString());
|
||||
|
||||
YamlScalar Scalar(Opacity value) => Scalar(value, $"{value.Percent}%");
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
|
||||
|
@ -17,6 +16,9 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
static readonly Sequence<GradientStop> s_defaultGradientStops =
|
||||
new Sequence<GradientStop>(new ColorGradientStop(0, Color.Black));
|
||||
|
||||
static readonly Animatable<Enum<BlurDimension>> s_animatableBlurDimensionHorizontalAndVertical =
|
||||
CreateNonAnimatedAnimatable((Enum<BlurDimension>)BlurDimension.HorizontalAndVertical);
|
||||
|
||||
static readonly Animatable<Color> s_animatableColorBlack = CreateNonAnimatedAnimatable(Color.Black);
|
||||
static readonly Animatable<double> s_animatableDoubleZero = CreateNonAnimatedAnimatable(0.0);
|
||||
static readonly Animatable<bool> s_animatableFalse = CreateNonAnimatedAnimatable(false);
|
||||
|
@ -28,6 +30,15 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
static readonly AnimatableVector3 s_animatableVector3Zero = new AnimatableVector3(Vector3.Zero, null);
|
||||
static readonly AnimatableVector3 s_animatableVector3OneHundred = new AnimatableVector3(new Vector3(100, 100, 100), null);
|
||||
|
||||
static readonly AnimatableParser<Enum<BlurDimension>> s_animatableBlurDimensionParser =
|
||||
CreateAnimatableParser((in LottieJsonElement element) => element.AsInt32() switch
|
||||
{
|
||||
1 => (Enum<BlurDimension>)BlurDimension.HorizontalAndVertical,
|
||||
2 => (Enum<BlurDimension>)BlurDimension.Horizontal,
|
||||
3 => (Enum<BlurDimension>)BlurDimension.Vertical,
|
||||
_ => throw ReaderException("Unexpected blur dimension value."),
|
||||
});
|
||||
|
||||
// Parses boolean values as 0 or non-0 integers.
|
||||
static readonly AnimatableParser<bool> s_animatableBoolParser =
|
||||
CreateAnimatableParser((in LottieJsonElement element) => (element.AsInt32() ?? 0) != 0);
|
||||
|
@ -69,6 +80,11 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
? s_animatableFalse
|
||||
: ReadAnimatable(s_animatableBoolParser, obj.Value);
|
||||
|
||||
Animatable<Enum<BlurDimension>> ReadAnimatableBlurDimension(in LottieJsonObjectElement? obj)
|
||||
=> obj is null
|
||||
? s_animatableBlurDimensionHorizontalAndVertical
|
||||
: ReadAnimatable(s_animatableBlurDimensionParser, obj.Value);
|
||||
|
||||
Animatable<Color> ReadAnimatableColor(in LottieJsonObjectElement? obj)
|
||||
=> obj is null
|
||||
? s_animatableColorBlack
|
||||
|
|
|
@ -38,29 +38,32 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
|
||||
Effect? ReadEffect(in LottieJsonObjectElement obj, string layerName)
|
||||
{
|
||||
var effectType = obj.DoublePropertyOrNull("ty") ?? throw ReaderException("Invalid effect");
|
||||
var effectType = obj.DoublePropertyOrNull("ty") ?? throw ReaderException("Invalid effect.");
|
||||
var effectName = obj.StringPropertyOrNull("nm") ?? string.Empty;
|
||||
var isEnabled = obj.BoolPropertyOrNull("en") ?? true;
|
||||
|
||||
switch (effectType)
|
||||
{
|
||||
// DropShadows are type 25. This is the only type we currently support.
|
||||
case 25:
|
||||
return ReadDropShadowEffect(obj);
|
||||
return ReadDropShadowEffect(obj, effectName, isEnabled);
|
||||
|
||||
case 29:
|
||||
return ReadGaussianBlurEffect(obj, effectName, isEnabled);
|
||||
|
||||
default:
|
||||
obj.IgnorePropertyThatIsNotYetSupported(
|
||||
"nm", // name.
|
||||
"mn", // match name.
|
||||
"en", // enabled.
|
||||
"np", // unknown.
|
||||
"ix", // index.
|
||||
"ef"); // effect parameters.
|
||||
|
||||
_issues.LayerEffectsIsNotSupported(layerName, effectType.ToString());
|
||||
return null;
|
||||
return new Effect.Unknown(effectType, effectName, isEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
DropShadowEffect ReadDropShadowEffect(in LottieJsonObjectElement obj)
|
||||
// Layer effect type 29.
|
||||
GaussianBlurEffect ReadGaussianBlurEffect(in LottieJsonObjectElement obj, string effectName, bool isEnabled)
|
||||
{
|
||||
// Index.
|
||||
obj.IgnorePropertyIntentionally("ix");
|
||||
|
@ -71,9 +74,67 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
// Unknown.
|
||||
obj.IgnorePropertyIntentionally("np");
|
||||
|
||||
var effectName = obj.StringPropertyOrNull("nm") ?? string.Empty;
|
||||
var parameters = obj.ArrayPropertyOrNull("ef") ?? throw ParseFailure();
|
||||
|
||||
var isEnabled = obj.BoolPropertyOrNull("en") ?? true;
|
||||
Animatable<double>? blurriness = null;
|
||||
Animatable<Enum<BlurDimension>>? blurDimensions = null;
|
||||
Animatable<bool>? repeatEdgePixels = null;
|
||||
|
||||
for (var i = 0; i < parameters.Count; i++)
|
||||
{
|
||||
var p = parameters[i].AsObject() ?? throw ParseFailure();
|
||||
|
||||
var value = p.ObjectPropertyOrNull("v") ?? throw ParseFailure();
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
// Blurriness - float 0..50
|
||||
blurriness = ReadAnimatableFloat(value) ?? throw ParseFailure();
|
||||
break;
|
||||
|
||||
case 1:
|
||||
blurDimensions = ReadAnimatableBlurDimension(value) ?? throw ParseFailure();
|
||||
break;
|
||||
|
||||
case 2:
|
||||
repeatEdgePixels = ReadAnimatableBool(value) ?? throw ParseFailure();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw ParseFailure();
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure all parameter values were provided.
|
||||
if (blurriness is null ||
|
||||
blurDimensions is null ||
|
||||
repeatEdgePixels is null)
|
||||
{
|
||||
throw ParseFailure();
|
||||
}
|
||||
|
||||
return new GaussianBlurEffect(
|
||||
effectName,
|
||||
isEnabled,
|
||||
blurriness: blurriness,
|
||||
blurDimensions: blurDimensions,
|
||||
repeatEdgePixels: repeatEdgePixels);
|
||||
|
||||
static Exception ParseFailure() => ReaderException("Invalid Gaussian blur effect.");
|
||||
}
|
||||
|
||||
// Layer effect type 25.
|
||||
DropShadowEffect ReadDropShadowEffect(in LottieJsonObjectElement obj, string effectName, bool isEnabled)
|
||||
{
|
||||
// Index.
|
||||
obj.IgnorePropertyIntentionally("ix");
|
||||
|
||||
// Match name.
|
||||
obj.IgnorePropertyIntentionally("mn");
|
||||
|
||||
// Unknown.
|
||||
obj.IgnorePropertyIntentionally("np");
|
||||
|
||||
var parameters = obj.ArrayPropertyOrNull("ef") ?? throw ParseFailure();
|
||||
|
||||
|
@ -112,7 +173,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
break;
|
||||
|
||||
default:
|
||||
throw ReaderException("Invalid drop shadow effect");
|
||||
throw ParseFailure();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,7 +198,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
opacity: opacity,
|
||||
softness: softness);
|
||||
|
||||
static Exception ParseFailure() => ReaderException("Invalid drop shadow effect");
|
||||
static Exception ParseFailure() => ReaderException("Invalid drop shadow effect.");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -43,7 +43,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
|
||||
internal void IllustratorLayers() => Report("LP0007", "Illustrator layers.");
|
||||
|
||||
internal void LayerEffectsIsNotSupported(string layer, string type) => Report("LP0008", $"{layer} has an unsupported layer effects, type = {type}.");
|
||||
internal void LayerEffectsIsNotSupported(string layer, string type) => Report("LP0008", $"{layer} has an unsupported layer effect, type = {type}.");
|
||||
|
||||
// LP0009 has been deprecated.
|
||||
// Was: Mattes.
|
||||
|
|
Загрузка…
Ссылка в новой задаче