Example #1
0
 public Layer(List <IContentModel> shapes, LottieComposition composition, string layerName, long layerId, LayerType layerType, long parentId, string refId, List <Mask> masks, AnimatableTransform transform, int solidWidth, int solidHeight, Color solidColor, float timeStretch, float startFrame, int preCompWidth, int preCompHeight, AnimatableTextFrame text, AnimatableTextProperties textProperties, List <Keyframe <float?> > inOutKeyframes, MatteType matteType, AnimatableFloatValue timeRemapping, bool hidden)
 {
     _shapes        = shapes;
     _composition   = composition;
     Name           = layerName;
     Id             = layerId;
     _layerType     = layerType;
     ParentId       = parentId;
     RefId          = refId;
     Masks          = masks;
     Transform      = transform;
     SolidWidth     = solidWidth;
     SolidHeight    = solidHeight;
     SolidColor     = solidColor;
     TimeStretch    = timeStretch;
     StartFrame     = startFrame;
     PreCompWidth   = preCompWidth;
     PreCompHeight  = preCompHeight;
     Text           = text;
     TextProperties = textProperties;
     InOutKeyframes = inOutKeyframes;
     _matteType     = matteType;
     TimeRemapping  = timeRemapping;
     Hidden         = hidden;
 }
Example #2
0
        public static Layer Parse(JsonReader reader, LottieComposition composition)
        {
            string layerName = null;

            Layer.LayerType layerType   = Layer.LayerType.Unknown;
            string          refId       = null;
            long            layerId     = 0;
            int             solidWidth  = 0;
            int             solidHeight = 0;
            Color           solidColor;
            int             preCompWidth  = 0;
            int             preCompHeight = 0;
            long            parentId      = -1;
            float           timeStretch   = 1f;
            float           startFrame    = 0f;
            float           inFrame       = 0f;
            float           outFrame      = 0f;
            string          cl            = null;

            Layer.MatteType          matteType      = Layer.MatteType.None;
            AnimatableTransform      transform      = null;
            AnimatableTextFrame      text           = null;
            AnimatableTextProperties textProperties = null;
            AnimatableFloatValue     timeRemapping  = null;

            List <Mask>          masks  = new List <Mask>();
            List <IContentModel> shapes = new List <IContentModel>();

            reader.BeginObject();
            while (reader.HasNext())
            {
                switch (reader.NextName())
                {
                case "nm":
                    layerName = reader.NextString();
                    break;

                case "ind":
                    layerId = reader.NextInt();
                    break;

                case "refId":
                    refId = reader.NextString();
                    break;

                case "ty":
                    int layerTypeInt = reader.NextInt();
                    if (layerTypeInt < (int)Layer.LayerType.Unknown)
                    {
                        layerType = (Layer.LayerType)layerTypeInt;
                    }
                    else
                    {
                        layerType = Layer.LayerType.Unknown;
                    }
                    break;

                case "parent":
                    parentId = reader.NextInt();
                    break;

                case "sw":
                    solidWidth = (int)(reader.NextInt() * Utils.Utils.DpScale());
                    break;

                case "sh":
                    solidHeight = (int)(reader.NextInt() * Utils.Utils.DpScale());
                    break;

                case "sc":
                    solidColor = Utils.Utils.GetSolidColorBrush(reader.NextString());
                    break;

                case "ks":
                    transform = AnimatableTransformParser.Parse(reader, composition);
                    break;

                case "tt":
                    matteType = (Layer.MatteType)reader.NextInt();
                    break;

                case "masksProperties":
                    reader.BeginArray();
                    while (reader.HasNext())
                    {
                        masks.Add(MaskParser.Parse(reader, composition));
                    }
                    reader.EndArray();
                    break;

                case "shapes":
                    reader.BeginArray();
                    while (reader.HasNext())
                    {
                        var shape = ContentModelParser.Parse(reader, composition);
                        if (shape != null)
                        {
                            shapes.Add(shape);
                        }
                    }
                    reader.EndArray();
                    break;

                case "t":
                    reader.BeginObject();
                    while (reader.HasNext())
                    {
                        switch (reader.NextName())
                        {
                        case "d":
                            text = AnimatableValueParser.ParseDocumentData(reader, composition);
                            break;

                        case "a":
                            reader.BeginArray();
                            if (reader.HasNext())
                            {
                                textProperties = AnimatableTextPropertiesParser.Parse(reader, composition);
                            }
                            while (reader.HasNext())
                            {
                                reader.SkipValue();
                            }
                            reader.EndArray();
                            break;

                        default:
                            reader.SkipValue();
                            break;
                        }
                    }
                    reader.EndObject();
                    break;

                case "ef":
                    reader.BeginArray();
                    List <string> effectNames = new List <string>();
                    while (reader.HasNext())
                    {
                        reader.BeginObject();
                        while (reader.HasNext())
                        {
                            switch (reader.NextName())
                            {
                            case "nm":
                                effectNames.Add(reader.NextString());
                                break;

                            default:
                                reader.SkipValue();
                                break;
                            }
                        }
                        reader.EndObject();
                    }
                    reader.EndArray();
                    composition.AddWarning("Lottie doesn't support layer effects. If you are using them for " +
                                           " fills, strokes, trim paths etc. then try adding them directly as contents " +
                                           " in your shape. Found: " + effectNames);
                    break;

                case "sr":
                    timeStretch = reader.NextDouble();
                    break;

                case "st":
                    startFrame = reader.NextDouble();
                    break;

                case "w":
                    preCompWidth = (int)(reader.NextInt() * Utils.Utils.DpScale());
                    break;

                case "h":
                    preCompHeight = (int)(reader.NextInt() * Utils.Utils.DpScale());
                    break;

                case "ip":
                    inFrame = reader.NextDouble();
                    break;

                case "op":
                    outFrame = reader.NextDouble();
                    break;

                case "tm":
                    timeRemapping = AnimatableValueParser.ParseFloat(reader, composition, false);
                    break;

                case "cl":
                    cl = reader.NextString();
                    break;

                default:
                    reader.SkipValue();
                    break;
                }
            }
            reader.EndObject();

            // Bodymovin pre-scales the in frame and out frame by the time stretch. However, that will
            // cause the stretch to be double counted since the in out animation gets treated the same
            // as all other animations and will have stretch applied to it again.
            inFrame  /= timeStretch;
            outFrame /= timeStretch;

            List <Keyframe <float?> > inOutKeyframes = new List <Keyframe <float?> >();

            // Before the in frame
            if (inFrame > 0)
            {
                Keyframe <float?> preKeyframe = new Keyframe <float?>(composition, 0f, 0f, null, 0f, inFrame);
                inOutKeyframes.Add(preKeyframe);
            }

            // The + 1 is because the animation should be visible on the out frame itself.
            outFrame = (outFrame > 0 ? outFrame : composition.EndFrame) + 1;
            Keyframe <float?> visibleKeyframe = new Keyframe <float?>(composition, 1f, 1f, null, inFrame, outFrame);

            inOutKeyframes.Add(visibleKeyframe);

            Keyframe <float?> outKeyframe = new Keyframe <float?>(composition, 0f, 0f, null, outFrame, float.MaxValue);

            inOutKeyframes.Add(outKeyframe);

            if (layerName.EndsWith(".ai") || "ai".Equals(cl))
            {
                composition.AddWarning("Convert your Illustrator layers to shape layers.");
            }

            return(new Layer(shapes, composition, layerName, layerId, layerType, parentId, refId, masks, transform, solidWidth, solidHeight, solidColor, timeStretch, startFrame, preCompWidth, preCompHeight, text, textProperties, inOutKeyframes, matteType, timeRemapping));
        }
Example #3
0
            internal static Layer NewInstance(JsonObject json, LottieComposition composition)
            {
                var layerName = json.GetNamedString("nm");
                var refId     = json.GetNamedString("refId", string.Empty);

                if (layerName.EndsWith(".ai") || json.GetNamedString("cl", "").Equals("ai"))
                {
                    composition.AddWarning("Convert your Illustrator layers to shape layers.");
                }

                var       layerId     = (long)json.GetNamedNumber("ind");
                var       solidWidth  = 0;
                var       solidHeight = 0;
                Color     solidColor;
                var       preCompWidth  = 0;
                var       preCompHeight = 0;
                LayerType layerType;
                var       layerTypeInt = (int)json.GetNamedNumber("ty", -1);

                if (layerTypeInt < (int)LayerType.Unknown)
                {
                    layerType = (LayerType)layerTypeInt;
                }
                else
                {
                    layerType = LayerType.Unknown;
                }

                if (layerType == LayerType.Text && !Utils.Utils.IsAtLeastVersion(composition, 4, 8, 0))
                {
                    layerType = LayerType.Unknown;
                    composition.AddWarning("Text is only supported on bodymovin >= 4.8.0");
                }

                var parentId = (long)json.GetNamedNumber("parent", -1);

                if (layerType == LayerType.Solid)
                {
                    solidWidth  = (int)(json.GetNamedNumber("sw") * composition.DpScale);
                    solidHeight = (int)(json.GetNamedNumber("sh") * composition.DpScale);
                    solidColor  = Utils.Utils.GetSolidColorBrush(json.GetNamedString("sc"));
                    Debug.WriteLine("\tSolid=" + string.Format("{0:X}", solidColor) + " " + solidWidth + "x" + solidHeight + " " + composition.Bounds, Tag);
                }

                var transform      = AnimatableTransform.Factory.NewInstance(json.GetNamedObject("ks"), composition);
                var matteType      = (MatteType)(int)json.GetNamedNumber("tt", 0);
                var masks          = new List <Mask>();
                var inOutKeyframes = new List <IKeyframe <float?> >();
                var jsonMasks      = json.GetNamedArray("masksProperties", null);

                if (jsonMasks != null)
                {
                    for (var i = 0; i < jsonMasks.Count; i++)
                    {
                        var mask = Mask.Factory.NewMask(jsonMasks[i].GetObject(), composition);
                        masks.Add(mask);
                    }
                }

                var shapes     = new List <IContentModel>();
                var shapesJson = json.GetNamedArray("shapes", null);

                if (shapesJson != null)
                {
                    for (var i = 0; i < shapesJson.Count; i++)
                    {
                        var shape = ShapeGroup.ShapeItemWithJson(shapesJson[i].GetObject(), composition);
                        if (shape != null)
                        {
                            shapes.Add(shape);
                        }
                    }
                }

                AnimatableTextFrame      text           = null;
                AnimatableTextProperties textProperties = null;
                var textJson = json.GetNamedObject("t", null);

                if (textJson != null)
                {
                    text = AnimatableTextFrame.Factory.NewInstance(textJson.GetNamedObject("d", null), composition);
                    var namedArray     = textJson.GetNamedArray("a", null);
                    var propertiesJson = namedArray?.Count > 0 ? namedArray.GetObjectAt(0) : null;
                    textProperties = AnimatableTextProperties.Factory.NewInstance(propertiesJson, composition);
                }

                if (json.ContainsKey("ef"))
                {
                    composition.AddWarning("Lottie doesn't support layer effects. If you are using them for " +
                                           " fills, strokes, trim paths etc. then try adding them directly as contents " +
                                           " in your shape.");
                }

                var timeStretch   = (float)json.GetNamedNumber("sr", 1.0);
                var startFrame    = (float)json.GetNamedNumber("st");
                var frames        = composition.DurationFrames;
                var startProgress = startFrame / frames;

                if (layerType == LayerType.PreComp)
                {
                    preCompWidth  = (int)(json.GetNamedNumber("w") * composition.DpScale);
                    preCompHeight = (int)(json.GetNamedNumber("h") * composition.DpScale);
                }

                // Bodymovin pre-scales the in frame and out frame by the time stretch. However, that will
                // cause the stretch to be double counted since the in out animation gets treated the same
                // as all other animations and will have stretch applied to it again.
                var inFrame  = (float)json.GetNamedNumber("ip") / timeStretch;
                var outFrame = (float)json.GetNamedNumber("op") / timeStretch;

                // Before the in frame
                if (inFrame > 0)
                {
                    var preKeyframe = new Keyframe <float?>(composition, 0f, 0f, null, 0f, inFrame);
                    inOutKeyframes.Add(preKeyframe);
                }

                // The + 1 is because the animation should be visible on the out frame itself.
                outFrame = outFrame > 0 ? outFrame : composition.EndFrame + 1;
                var visibleKeyframe = new Keyframe <float?>(composition, 1f, 1f, null, inFrame, outFrame);

                inOutKeyframes.Add(visibleKeyframe);

                var outKeyframe = new Keyframe <float?>(composition, 0f, 0f, null, outFrame, float.MaxValue);

                inOutKeyframes.Add(outKeyframe);

                AnimatableFloatValue timeRemapping = null;

                if (json.ContainsKey("tm"))
                {
                    timeRemapping = AnimatableFloatValue.Factory.NewInstance(json.GetNamedObject("tm", null), composition, false);
                }

                return(new Layer(shapes, composition, layerName, layerId, layerType, parentId, refId, masks, transform, solidWidth, solidHeight, solidColor, timeStretch, startProgress, preCompWidth, preCompHeight, text, textProperties, inOutKeyframes, matteType, timeRemapping));
            }