CrazyIter 4 роки тому
батько
коміт
c3c6e67e41

+ 91 - 0
HTEXLib/Animations/AnimationTypes.cs

@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace HTEXLib.Animations
+{
+    internal class AnimationTypes
+    {
+        public const string FlyIn = "FlyIn";
+        public const string FlyOut = "FlyOut";
+        public const string Sling = "Sling";
+        public const string Appear = "Appear";
+        public const string Strips = "Strips";
+        public const string Blinds = "Blinds";
+        public const string Box = "Box";
+        public const string Glide = "Glide";
+        public const string Swivel = "Swivel";
+        public const string Ascend = "Ascend";
+        public const string Boomerang = "Boomerang";
+        public const string CenterRevolve = "CenterRevolve";
+        public const string Compress = "Compress";
+        public const string CrawlIn = "CrawlIn";
+        public const string CrawlOut = "CrawlOut";
+        public const string Descend = "Descend";
+        public const string EaseIn = "EaseIn";
+        public const string EaseOut = "EaseOut";
+        public const string Expand = "Expand";
+        public const string Contract = "Contract";
+        public const string FadedZoom = "FadedZoom";
+        public const string FlashOnce = "FlashOnce";
+        public const string Fold = "Fold";
+        public const string GrowTurn = "GrowTurn";
+        public const string Pinwheel = "Pinwheel";
+        public const string RiseUp = "RiseUp";
+        public const string SinkDown = "SinkDown";
+        public const string Spinner = "Spinner";
+        public const string Bounce = "Bounce";
+        public const string Credits = "Credits";
+        public const string CurveUp = "CurveUp";
+        public const string CurveDown = "CurveDown";
+        public const string Dissolve = "Dissolve";
+        public const string Float = "Float";
+        public const string LightSpeed = "LightSpeed";
+        public const string Magnify = "Magnify";
+        public const string SpiralIn = "SpiralIn";
+        public const string SpiralOut = "SpiralOut";
+        public const string Stretch = "Stretch";
+        public const string Thread = "Thread";
+        public const string Wheel = "Wheel";
+        public const string Zoom = "Zoom";
+        public const string Spin = "Spin";
+        public const string GrowShrink = "GrowShrink";
+        public const string Checkerboard = "Checkerboard";
+        public const string Circle = "Circle";
+        public const string Diamond = "Diamond";
+        public const string Fade = "Fade";
+        public const string Plus = "Plus";
+        public const string Wipe = "Wipe";
+        public const string PeekOut = "PeekOut";
+        public const string PeekIn = "PeekIn";
+        public const string Split = "Split";
+        public const string Push = "Push";
+        public const string FadeThroughBlack = "FadeThroughBlack";
+        public const string Cut = "Cut";
+        public const string CutThroughBlack = "CutThroughBlack";
+        public const string DissolveIn = "DissolveIn";
+        public const string Wedge = "Wedge";
+        public const string UnCover = "UnCover";
+        public const string Newsflash = "Newsflash";
+        public const string RandomBars = "RandomBars";
+        public const string MotionPath = "MotionPath";
+        public const string TypePath = "path";
+        public const string TypeEntrance = "entr";
+        public const string TypeExit = "exit";
+        public const string TypeEmphasis = "emph";
+        public const string ChangeFontColor = "ChangeFontColor";
+        public const string ColorWave = "ColorWave";
+        public const string ColorBlend = "ColorBlend";
+        public const string BrushOnColor = "BrushOnColor";
+        public const string Blast = "Blast";
+        public const string FlashBulb = "FlashBulb";
+        public const string Blink = "Blink";
+        public const string Transparency = "Transparency";
+        public const string VerticalHighlight = "VerticalHighlight";
+        public const string Flicker = "Flicker";
+        public const string Shimmer = "Shimmer";
+        public const string GrowwithColor = "GrowwithColor";
+        public const string Teeter = "Teeter";
+        public const string Wave = "Wave";
+    }
+}

+ 102 - 0
HTEXLib/Animations/EmphasisAnimation.cs

@@ -0,0 +1,102 @@
+using DocumentFormat.OpenXml.Presentation;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using DocumentFormat.OpenXml.Drawing;
+using DocumentFormat.OpenXml;
+using HTEXLib.Models;
+
+namespace HTEXLib.Animations
+{
+    public class EmphasisAnimation : SimpleAnimation
+    {
+        public EmphasisAnimation()
+        {
+
+        }
+
+        public EmphasisAnimation(SimpleAnimation fromBase)
+        {
+            this.AdditionalData = fromBase.AdditionalData;
+            this.InitialState = fromBase.InitialState;
+            this.InnerAnimations = fromBase.InnerAnimations;
+            this.Start = fromBase.Start;
+            this.Length = fromBase.Length;
+            this.ObjectId = fromBase.ObjectId;
+            this.Repetitions = fromBase.Repetitions;
+            this.timingType = fromBase.timingType;
+            this.Type = fromBase.Type;
+
+            this.RGBColor = "[0,0,0]";
+            this.Transparency = 0;
+            this.RotationDegrees = 0;
+            this.ScaleX = 0;
+            this.ScaleY = 0;
+            e1 = 1;
+            e2 = 0;
+        }
+
+        public String RGBColor { get; set; }
+        public double Transparency { get; set; }
+        public int ScaleX { get; set; }
+        public int ScaleY { get; set; }
+        public int RotationDegrees { get; set; }
+        public int e1 { get; set; }
+        public int e2 { get; set; }
+
+        public override string GetJsonString()
+        {
+            return "{objectId:" + GetObjectIdForJSON() + ",start:" + Start + ",length:" + Length + ",repeat:" + Repetitions + ",state:" + InitialState +
+                   ",name:'" + Type + "',c7:0,additionalData:" + RotationDegrees + ",additionalData2:" + RotationDegrees + ",scaleX:" + ScaleX + ",scaleY:" + ScaleY +
+                   ",color:" + RGBColor + ",transparency:" +
+
+                   Transparency.ToString("0.##", System.Globalization.CultureInfo.GetCultureInfo("en-US").NumberFormat) + ",v:0,e0:" + GetE0Value() + ",e1:" + e1 + ",e2:" + e2 + GetE3Value() + "}";
+        }
+
+        public void setRgbColor(CommonTimeNode commonTimeNode, PPTSlide Slide)
+        {
+            RGBColor = "[0,0,0]";
+            foreach (Object xmlEl in commonTimeNode.Descendants())
+            {
+                if (xmlEl.GetType().Equals(typeof(RgbColorModelHex)))
+                {
+                    RgbColorModelHex rgb = (RgbColorModelHex)xmlEl;
+                    RGBColor = convertHEXtoRGB(((RgbColorModelHex)rgb).Val);
+                }
+                else if (xmlEl.GetType().Equals(typeof(SchemeColor)))
+                {
+                    string schemeCol = ((SchemeColor)xmlEl).Val;
+                    DocumentFormat.OpenXml.Drawing.ColorScheme allSchemeCols =
+                        Slide.SlideLayoutPart.SlideMasterPart.ThemePart.Theme.ThemeElements.ColorScheme;
+                    foreach (OpenXmlCompositeElement desc in allSchemeCols.Descendants())
+                    {
+                        string currSchemeCol = desc.LocalName;
+                        if (schemeCol == currSchemeCol ||
+                            (schemeCol == "bg1" && currSchemeCol == "lt1") ||
+                            (schemeCol == "bg2" && currSchemeCol == "lt2") ||
+                            (schemeCol == "tx1" && currSchemeCol == "dk1") ||
+                            (schemeCol == "tx2" && currSchemeCol == "dk2"))
+                        {
+                            if (typeof(RgbColorModelHex) == desc.FirstChild.GetType())
+                            {
+                                RGBColor = convertHEXtoRGB(((RgbColorModelHex)desc.FirstChild).Val);
+                            }
+                            else if (typeof(SystemColor) == desc.FirstChild.GetType())
+                            {
+                                RGBColor = convertHEXtoRGB(((SystemColor)desc.FirstChild).LastColor);
+                            }
+                        }
+                    }
+                    break;
+                }
+            }
+        }
+
+        private string convertHEXtoRGB(string hex)
+        {
+            var colorHtml = System.Drawing.ColorTranslator.FromHtml("#" + hex);
+            string rgb = "[" + colorHtml.R + "," + colorHtml.G + "," + colorHtml.B + "]";
+            return rgb;
+        }
+    }
+}

+ 719 - 0
HTEXLib/Animations/JSONGenerator.cs

@@ -0,0 +1,719 @@
+using DocumentFormat.OpenXml.Presentation;
+using HTEXLib.Models;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+namespace HTEXLib.Animations
+{
+    public class JSONGenerator
+    {
+        public PPTSlide Slide { get; set; }
+
+        public JSONGenerator(PPTSlide slide)
+        {
+            this.Slide = slide;
+        }
+
+        public JSONGenerator(List<PPTSlide> slides)
+        {
+            this.Slide = slides.ElementAt(0); //TODO: add support for more than one slide
+        }
+
+        public string GetAnimaVariable()
+        {
+            return "var animations = " + GetAnimationsJSON() + ";";
+        }
+
+        /*
+         * Fix the timing for animations that need to start without a click. Make the tree simpler by removing nodes that are empty or nested.
+         * 
+         * When a node has a start type != ClickEffect , we add the Animations from this timenode to the animations list in the previous time node.
+         * If it is type After the previous one we need to set Delay = Length of the previous one. 
+         * 
+         * Removing nested nodes:
+         * Example 1: Node -> Node -> Node  - every node has a single child. In this case we can create one time node with the timing for both. 
+         * Example 2: We have only one node (one simple animation) and all the other are nested (inner animations) - we remove the parent time node and 
+         * add its timing to the timing of the nested animations.
+         * 
+         */
+
+        private List<IAnimation> fixAnimationTimings(List<IAnimation> animations)
+        {
+            animations = fixNestedAnimations(animations);
+
+
+            List<IAnimation> result = new List<IAnimation>();
+            if (animations == null || animations.Count == 0)
+                return result;
+            //If we have only one animation and all the others are nested  - add the delay to the inner animations and remove this one.
+            if (animations.Count == 1 && animations[0].InnerAnimations != null && animations[0].InnerAnimations.Count > 0)
+            {
+                foreach (IAnimation anim in animations[0].InnerAnimations)
+                    anim.Start += animations[0].Start;
+                return fixAnimationTimings(animations[0].InnerAnimations);
+            }
+            IAnimation previousAnimation = null;
+            foreach (IAnimation animation in animations)
+            {
+                SimpleAnimation sAnimation = (SimpleAnimation)animation;
+                if (previousAnimation == null)
+                {
+                    previousAnimation = sAnimation;
+                    continue;
+                }
+                //These are the cases where animation starts without a click. There migth be other cases which are not handled yet.
+                else if (sAnimation.timingType.HasValue && (
+                        TimeNodeValues.WithEffect.Equals(sAnimation.timingType.Value) ||
+                        TimeNodeValues.AfterEffect.Equals(sAnimation.timingType.Value) ||
+                        TimeNodeValues.WithGroup.Equals(sAnimation.timingType.Value) ||
+                        TimeNodeValues.AfterGroup.Equals(sAnimation.timingType.Value)))
+                {
+                    int newLenegth = 0;
+                    if (TimeNodeValues.AfterEffect.Equals(sAnimation.timingType.Value) ||
+                        TimeNodeValues.AfterGroup.Equals(sAnimation.timingType.Value))
+                    {
+                        /*If animation is a part of a group then it has delay according to the start of the parent time node (animation). 
+                         * In this case we use this delay because it is the proper way power point handles such animations. 
+                         * If by some reason there isn't such delay and the animation type is set to 'After' previous
+                         * we set the start point to right after the previous animation ends." */
+
+                        if (sAnimation.Start <= previousAnimation.Length + previousAnimation.Start)
+                            sAnimation.Start = previousAnimation.Length + previousAnimation.Start;
+                        if (sAnimation.InnerAnimations != null)
+                            foreach (IAnimation anim in sAnimation.InnerAnimations)
+                                anim.Start = anim.Start + sAnimation.Start;
+                        newLenegth = sAnimation.Length + sAnimation.Start;
+                    }
+                    else
+                    {
+                        newLenegth = (sAnimation.Length + sAnimation.Start >
+                                           previousAnimation.Length + previousAnimation.Start)
+                                              ? sAnimation.Length + sAnimation.Start
+                                              : previousAnimation.Length + previousAnimation.Start;
+                    }
+
+                    /*Joins the current animation and the previous one and recalculates the length*/
+                    if (previousAnimation.InnerAnimations != null && previousAnimation.InnerAnimations.Count > 0)
+                    {
+
+                        previousAnimation.Length = newLenegth;
+                        if (sAnimation.InnerAnimations == null || sAnimation.InnerAnimations.Count == 0)
+                            previousAnimation.InnerAnimations.Add(sAnimation);
+                        else
+                            previousAnimation.InnerAnimations.AddRange(sAnimation.InnerAnimations);
+                        continue;
+                    }
+                    else
+                    {
+                        SimpleAnimation tempAnimation = new SimpleAnimation();
+                        tempAnimation.Length = newLenegth;
+                        tempAnimation.timingType = ((SimpleAnimation)previousAnimation).timingType;
+                        tempAnimation.InnerAnimations = new List<IAnimation>();
+
+                        if (previousAnimation.InnerAnimations == null || previousAnimation.InnerAnimations.Count == 0)
+                            tempAnimation.InnerAnimations.Add(previousAnimation);
+                        else
+                            tempAnimation.InnerAnimations.AddRange(previousAnimation.InnerAnimations);
+
+                        if (sAnimation.InnerAnimations == null || sAnimation.InnerAnimations.Count == 0)
+                            tempAnimation.InnerAnimations.Add(sAnimation);
+                        else
+                            tempAnimation.InnerAnimations.AddRange(sAnimation.InnerAnimations);
+                        previousAnimation = tempAnimation;
+                        continue;
+                    }
+                }
+                result.Add(previousAnimation);
+                previousAnimation = sAnimation;
+            }
+            result.Add(previousAnimation);
+            return result;
+        }
+
+
+        /* 
+         * When the animation has only one inner animation then return the inner animation. Do this recursive until we get the real one.          
+         */
+        private IAnimation getAnimationFromNested(IAnimation sAnimation)
+        {
+            if (sAnimation.InnerAnimations != null && sAnimation.InnerAnimations.Count == 1)
+            {
+                sAnimation.InnerAnimations[0].Start += sAnimation.Start;
+                return getAnimationFromNested(sAnimation.InnerAnimations[0]);
+            }
+            if (((SimpleAnimation)sAnimation).timingType == null && sAnimation.InnerAnimations != null)
+                ((SimpleAnimation)sAnimation).timingType = ((SimpleAnimation)getAnimationFromNested(sAnimation.InnerAnimations[0])).timingType;
+            return sAnimation;
+        }
+
+
+        /*         
+         * Generating the JSON for the animations for one slide only. It has some support for nested animations but not everything works.                    
+         */
+
+        public string GetAnimationsJSON()
+        {
+            if (Slide == null)
+            {
+                return "{s1:{t:{i:1000,c:1,v:0,n:0},g:0,a:0,f:0,c:0}}";
+            }
+            String result = "";
+
+            int animations = 0;
+
+            List<IAnimation> fixedAnimations = fixAnimationTimings(Slide.Animations);
+            animations = fixedAnimations.Count;
+
+            if (Slide.Transition == null)
+            {
+                result = "{s1:{t:{i:0,c:1,v:0,n:0},g:0,a:0,f:0,c:##ANIMATIONS_PLACEHOLDER##}}";
+            }
+            else
+            {
+                result = "{s1:{t:{i:" + (Slide.Transition.Length + Slide.Transition.Start) +
+                         ",c:" + Slide.Transition.GetJsonString() + "},g:0,a:0,f:0,c:##ANIMATIONS_PLACEHOLDER##}}";
+            }
+            if (animations == 0)
+            {
+                result = result.Replace("##ANIMATIONS_PLACEHOLDER##", "0");
+                return result;
+            }
+
+
+            SimpleAnimation checkEffectFirstAnim = (SimpleAnimation)fixedAnimations[0];
+            if (checkEffectFirstAnim.timingType.HasValue && checkEffectFirstAnim.timingType.Value != TimeNodeValues.ClickEffect)
+            {
+                result = result.Replace("n:0", "n:1");
+                //If it is just one Animation we change this in the transition! - the transition is like the first Animation!
+            }
+
+
+            string animationsString = "{i:" + animations + getAnimationsString(fixedAnimations, true) + "}";
+
+
+
+
+            result = result.Replace("##ANIMATIONS_PLACEHOLDER##", animationsString);
+
+            return result;
+        }
+
+
+        /*
+         * Generate JSON for animation tree. Recursive going into the tree - there is some difference in the animation string 
+         * for the first level and the next levels.         
+         */
+
+        private string getAnimationsString(List<IAnimation> animations, bool firstLevel)
+        {
+            String animationList = "";
+            int index = 0;
+            foreach (IAnimation animation in animations)
+            {
+                if (animation.InnerAnimations == null || animation.InnerAnimations.Count == 0)
+                {
+                    if (!firstLevel)
+                        animationList = animationList + ",c" + index++ + ":" + animation.GetJsonString();
+                    else
+                        animationList = animationList + ",c" + index++ + ":{i:" + (((SimpleAnimation)animation).getCalculatedLength() + animation.Start) + ",c0:" + animation.GetJsonString() + "}";
+                }
+                else
+                // Nested animatons (several animations in one time node, or in different time nodes that start together!
+                {
+                    String innerAnimationsString = getAnimationsString(animation.InnerAnimations, false);
+
+                    animationList = animationList + ",c" + index++ + ":{i:" + (((SimpleAnimation)animation).getCalculatedLength() + animation.Start) +
+                                    innerAnimationsString + "}";
+                }
+            }
+            return animationList;
+        }
+
+        public static IAnimation GenerateTransitionAnimationObject(Transition trans)
+        {
+            if (trans == null || trans.FirstChild == null)
+                return null;
+            TransitionAnimation result = new TransitionAnimation();
+            if (trans.Speed != null && TransitionSpeedValues.Fast.Equals(trans.Speed.Value))
+                result.Length = 500;
+            else if (trans.Speed != null && TransitionSpeedValues.Slow.Equals(trans.Speed.Value))
+                result.Length = 2000;
+            else if (trans.Duration != null)
+                result.Length = int.Parse(trans.Duration.Value);
+            else
+                result.Length = 1000;
+
+            result.Start = 0;
+            result.InitialState = -1;
+            result.Repetitions = 1;
+            if (trans.AdvanceOnClick != null)
+                result.AdvanceOnClick = trans.AdvanceOnClick.Value;
+            else result.AdvanceOnClick = true;
+
+            if (typeof(StripsTransition) == trans.FirstChild.GetType())
+            {
+                StripsTransition transition = (StripsTransition)trans.FirstChild;
+                result.Type = AnimationTypes.Strips;
+                if (transition.Direction != null &&
+                    TransitionCornerDirectionValues.RightUp.Equals(transition.Direction.Value))
+                    result.AdditionalData = "7";
+                else if (transition.Direction != null &&
+                         TransitionCornerDirectionValues.LeftDown.Equals(transition.Direction.Value))
+                    result.AdditionalData = "9";
+                else if (transition.Direction != null &&
+                         TransitionCornerDirectionValues.RightDown.Equals(transition.Direction.Value))
+                    result.AdditionalData = "8";
+                else
+                    result.AdditionalData = "6";
+            }
+            else if (typeof(PushTransition) == trans.FirstChild.GetType())
+            {
+                PushTransition transition = (PushTransition)trans.FirstChild;
+                result.Type = AnimationTypes.Push;
+                if (transition.Direction != null &&
+                    TransitionSlideDirectionValues.Right.Equals(transition.Direction.Value))
+                    result.AdditionalData = "3";
+                else if (transition.Direction != null &&
+                         TransitionSlideDirectionValues.Up.Equals(transition.Direction.Value))
+                    result.AdditionalData = "4";
+                else if (transition.Direction != null &&
+                         TransitionSlideDirectionValues.Left.Equals(transition.Direction.Value))
+                    result.AdditionalData = "2";
+                else result.AdditionalData = "1";
+            }
+            else if (typeof(WipeTransition) == trans.FirstChild.GetType())
+            {
+                WipeTransition transition = (WipeTransition)trans.FirstChild;
+                result.Type = AnimationTypes.Wipe;
+                if (transition.Direction != null &&
+                    TransitionSlideDirectionValues.Right.Equals(transition.Direction.Value))
+                    result.AdditionalData = "4";
+                else if (transition.Direction != null &&
+                         TransitionSlideDirectionValues.Up.Equals(transition.Direction.Value))
+                    result.AdditionalData = "3";
+                else if (transition.Direction != null &&
+                         TransitionSlideDirectionValues.Left.Equals(transition.Direction.Value))
+                    result.AdditionalData = "2";
+                else result.AdditionalData = "1";
+            }
+            else if (typeof(FadeTransition) == trans.FirstChild.GetType())
+            {
+                FadeTransition transition = (FadeTransition)trans.FirstChild;
+                result.Type = AnimationTypes.Fade;
+                if (transition.ThroughBlack != null && transition.ThroughBlack.Value)
+                    result.Type = AnimationTypes.FadeThroughBlack;
+                result.AdditionalData = "1";
+            }
+            else if (typeof(CutTransition) == trans.FirstChild.GetType())
+            {
+                CutTransition transition = (CutTransition)trans.FirstChild;
+                result.Type = AnimationTypes.Cut;
+                result.AdditionalData = "2";
+                if (transition.ThroughBlack != null && transition.ThroughBlack.Value)
+                {
+                    result.Type = AnimationTypes.CutThroughBlack;
+                    result.AdditionalData = "3";
+                }
+            }
+            else if (typeof(DissolveTransition) == trans.FirstChild.GetType())
+            {
+                result.Type = AnimationTypes.DissolveIn;
+                result.AdditionalData = "1";
+            }
+            else if (typeof(WedgeTransition) == trans.FirstChild.GetType())
+            {
+                result.Type = AnimationTypes.Wedge;
+                result.AdditionalData = "1";
+            }
+            else if (typeof(PullTransition) == trans.FirstChild.GetType())
+            {
+                PullTransition transition = (PullTransition)trans.FirstChild;
+                result.Type = AnimationTypes.UnCover;
+                if (transition.Direction != null && "d".Equals(transition.Direction.Value.ToString()))
+                    result.AdditionalData = "9";
+                else if (transition.Direction != null && "r".Equals(transition.Direction.Value.ToString()))
+                    result.AdditionalData = "11";
+                else if (transition.Direction != null && "u".Equals(transition.Direction.Value.ToString()))
+                    result.AdditionalData = "12";
+                else if (transition.Direction != null && "ld".Equals(transition.Direction.Value.ToString()))
+                    result.AdditionalData = "13";
+                else if (transition.Direction != null && "lu".Equals(transition.Direction.Value.ToString()))
+                    result.AdditionalData = "14";
+                else if (transition.Direction != null && "rd".Equals(transition.Direction.Value.ToString()))
+                    result.AdditionalData = "15";
+                else if (transition.Direction != null && "ru".Equals(transition.Direction.Value.ToString()))
+                    result.AdditionalData = "16";
+                else result.AdditionalData = "10";
+            }
+            else if (typeof(ZoomTransition) == trans.FirstChild.GetType())
+            {
+                ZoomTransition transition = (ZoomTransition)trans.FirstChild;
+                result.Type = AnimationTypes.Box;
+                if (transition.Direction != null && TransitionInOutDirectionValues.In == transition.Direction.Value)
+                    result.AdditionalData = "19";
+                else result.AdditionalData = "20";
+            }
+            else if (typeof(ZoomTransition) == trans.FirstChild.GetType())
+            {
+                ZoomTransition transition = (ZoomTransition)trans.FirstChild;
+                result.Type = AnimationTypes.Box;
+                if (transition.Direction != null && TransitionInOutDirectionValues.In == transition.Direction.Value)
+                    result.AdditionalData = "19";
+                else result.AdditionalData = "20";
+            }
+            else if (typeof(WheelTransition) == trans.FirstChild.GetType())
+            {
+                WheelTransition transition = (WheelTransition)trans.FirstChild;
+                result.Type = AnimationTypes.Wheel;
+                if (transition.Spokes != null && transition.Spokes.Value == 1)
+                    result.AdditionalData = "1";
+                else if (transition.Spokes != null && transition.Spokes.Value == 2)
+                    result.AdditionalData = "2";
+                else if (transition.Spokes != null && transition.Spokes.Value == 3)
+                    result.AdditionalData = "3";
+                else if (transition.Spokes != null && transition.Spokes.Value == 8)
+                    result.AdditionalData = "8";
+                else result.AdditionalData = "4";
+            }
+            else if (typeof(SplitTransition) == trans.FirstChild.GetType())
+            {
+                SplitTransition transition = (SplitTransition)trans.FirstChild;
+                result.Type = AnimationTypes.Split;
+                if (transition.Direction != null && TransitionInOutDirectionValues.In == transition.Direction.Value)
+                {
+                    if (transition.Orientation != null && DirectionValues.Vertical.Equals(transition.Orientation.Value))
+                        result.AdditionalData = "25";
+                    else
+                        result.AdditionalData = "23";
+                }
+                else
+                {
+                    if (transition.Orientation != null && DirectionValues.Vertical.Equals(transition.Orientation.Value))
+                        result.AdditionalData = "26";
+                    else
+                        result.AdditionalData = "24";
+                }
+            }
+            else if (typeof(CircleTransition) == trans.FirstChild.GetType())
+            {
+                result.Type = AnimationTypes.Circle;
+                result.AdditionalData = "20";
+            }
+            else if (typeof(DiamondTransition) == trans.FirstChild.GetType())
+            {
+                result.Type = AnimationTypes.Diamond;
+                result.AdditionalData = "20";
+            }
+            else if (typeof(PlusTransition) == trans.FirstChild.GetType())
+            {
+                result.Type = AnimationTypes.Plus;
+                result.AdditionalData = "20";
+            }
+            else if (typeof(NewsflashTransition) == trans.FirstChild.GetType())
+            {
+                result.Type = AnimationTypes.Newsflash;
+                result.AdditionalData = "20";
+            }
+            return result;
+        }
+
+
+        public SimpleAnimation getSimpleAnimationFromCommonTimeNodePreset(CommonTimeNode commonTimeNode, SlideSize SlideSizes)
+        {
+            SimpleAnimation result = new SimpleAnimation();
+            if (AnimationTypes.TypePath.Equals(commonTimeNode.PresetClass))
+            {
+                return new MotionPathAnimation(commonTimeNode, Slide.slideIndex, SlideSizes);
+            }
+            else if (AnimationTypes.TypeEntrance.Equals(commonTimeNode.PresetClass))
+            {
+                result.InitialState = 1;
+            }
+            else if (AnimationTypes.TypeExit.Equals(commonTimeNode.PresetClass))
+            {
+                result.InitialState = 2;
+            }
+            else if (AnimationTypes.TypeEmphasis.Equals(commonTimeNode.PresetClass))
+            {
+                result.InitialState = 3;
+            }
+            else return null;
+            if (commonTimeNode.PresetId == null)
+                return null;
+            result.timingType = commonTimeNode.NodeType;
+
+            //Get the speed from one of the nodes common behavior. Hopefully all nodes have the same speed (since the animation is the same).
+            foreach (Object xmlEl in commonTimeNode.Descendants())
+                if (xmlEl.GetType().Equals(typeof(CommonBehavior)))
+                {
+                    CommonBehavior bhvr = ((CommonBehavior)xmlEl);
+
+                    if (bhvr.CommonTimeNode != null)
+                    {
+                        result.FixAnimationTimings(bhvr, Slide.slideIndex);
+                        if (result.Length <= 1)
+                            continue;
+                        if (result.Start == 0)
+                        {
+                            Condition condition = commonTimeNode.StartConditionList.FirstChild as Condition;
+                            if (!condition.Delay.Equals("indefinite"))
+                                result.Start = int.Parse(condition.Delay);
+                        }
+                        break;
+                    }
+                }
+            if (result.Length <= 1)
+                result.Length = 100;  //Default value??
+            if (AnimationTypes.TypeEmphasis.Equals(commonTimeNode.PresetClass))
+                result = handleEmphasisAnimation(commonTimeNode, result);
+            else
+                result = handleEntranceAnimation(commonTimeNode, result);
+
+
+            if (result.AdditionalData == null || result.AdditionalData == "0") //There are default values. Horizontal In = horizontal + in ;)
+                switch (commonTimeNode.PresetSubtype.Value)
+                {
+                    case 0: result.AdditionalData = "0"; break;
+                    case 4: result.AdditionalData = "3"; break;   //From bottom
+                    case 2: result.AdditionalData = "2"; break;   //From right
+                    case 1: result.AdditionalData = "1"; break;   //From top
+                    case 8: result.AdditionalData = "4"; break;   //From left
+                    case 6: result.AdditionalData = "8"; break;  //Bottom right
+                    case 3: result.AdditionalData = "7"; break;  //Top right
+                    case 9: result.AdditionalData = "6"; break;  //Top right
+                    case 12: result.AdditionalData = "9"; break;  //Bottom left
+                    case 10: result.AdditionalData = "16"; break;  //Horizontal
+                    case 5: result.AdditionalData = "17"; break;   //Vertical
+                    case 26: result.AdditionalData = "23"; break;   //Horizontal in
+                    case 42: result.AdditionalData = "24"; break;   //Horizontal out
+                    case 21: result.AdditionalData = "25"; break;   //Vertical in
+                    case 37: result.AdditionalData = "26"; break;   //Vertical out       
+                    case 16: result.AdditionalData = "19"; break;   //in    
+                    case 32: result.AdditionalData = "20"; break;   //out
+                }
+
+            checkIsText(result);
+            return result;
+        }
+
+        private void checkIsText(SimpleAnimation result)
+        {
+            int res;
+            bool isTextWithEffect = int.TryParse(result.ObjectId, out res) && HTEXLib.Models.Inner.PPTShape.effectShapes.Contains(Slide.slideIndex + "_" + res);
+
+            int tryParse = 0;
+            if (!int.TryParse(result.ObjectId, out tryParse) || isTextWithEffect)
+            {
+                return;//if it is like 123p -> return;
+            }
+
+            foreach (HTEXLib.Models.Inner.PPTShapeBase shape in Slide.ContainerShape.Elements)
+                if (typeof(HTEXLib.Models.Inner.PPTShape).Equals(shape.GetType()) && ((HTEXLib.Models.Inner.PPTShape)shape).IsText)
+                {
+                    string shapeId = shape.NonVisualShapeProp.Id;
+                    string shapeObjectId = "s1s" + result.ObjectId;
+                    if (shapeId.Equals(shapeObjectId))
+                    {
+                        result.ObjectId = result.ObjectId + "p0";// TODO check when multiple paragraphs
+                    }
+                }
+        }
+
+        private EmphasisAnimation handleEmphasisAnimation(CommonTimeNode commonTimeNode, SimpleAnimation simpleAnim)
+        {
+            EmphasisAnimation result = new EmphasisAnimation(simpleAnim);
+            result.setRgbColor(commonTimeNode, Slide);
+
+            switch (commonTimeNode.PresetId.Value)  //Presets for Entrance/Exit
+            {
+                case 3: result.Type = AnimationTypes.ChangeFontColor; break;
+                case 19: result.Type = AnimationTypes.ColorBlend; break;
+                case 14: result.Type = AnimationTypes.Blast; break;
+                case 26: result.Type = AnimationTypes.FlashBulb; break;
+                case 35: result.Type = AnimationTypes.Blink; break;
+                case 9:
+                    {
+                        result.Type = AnimationTypes.Transparency;
+                        result.Transparency = getTransparence(commonTimeNode);
+                    }
+                    break;
+                case 20:
+                    {
+                        result.Type = AnimationTypes.ColorWave;
+                        result.Length *= 2;
+                        result.e2 = result.Length / 10;
+                        result.e1 = 2;
+                    }
+                    break;
+                case 16:
+                    {
+                        result.Type = AnimationTypes.BrushOnColor;
+                        result.e2 = result.Length / 25;
+                        result.e1 = 2;
+                    }
+                    break;
+                case 33:
+                    {
+                        result.Type = AnimationTypes.VerticalHighlight;
+                        result.Length *= 2;
+                    }
+                    break;
+                case 27:
+                    {
+                        result.Type = AnimationTypes.Flicker;
+                        result.Length *= 2;
+                    }
+                    break;
+                case 36:
+                    {
+                        result.Type = AnimationTypes.Shimmer;
+                        result.e2 = result.Length / 5;
+                        result.Length *= 2;
+                        foreach (Object obj in commonTimeNode.Descendants())
+                            if (obj.GetType().Equals(typeof(AnimateScale)))
+                            {
+                                ((EmphasisAnimation)result).ScaleX = ((AnimateScale)obj).ToPosition.X.Value / 1000;
+                                ((EmphasisAnimation)result).ScaleY = ((AnimateScale)obj).ToPosition.Y.Value / 1000;
+                                break;
+                            }
+                    }
+                    break;
+                case 28:
+                    {
+                        result.Type = AnimationTypes.GrowwithColor;
+                        result.e2 = result.Length / 10;
+                        result.e1 = 2;
+                    }
+                    break;
+                case 32:
+                    {
+                        result.Type = AnimationTypes.Teeter;
+                        result.Length *= 2;
+                    }
+                    break;
+                case 34:
+                    {
+                        result.Type = AnimationTypes.Wave;
+                        result.e2 = result.Length / 5;
+                        result.Length *= 2;
+                    }
+                    break;
+                case 8:
+                    {
+                        result.Type = AnimationTypes.Spin;
+                        foreach (Object obj in commonTimeNode.Descendants())
+                            if (obj.GetType().Equals(typeof(AnimateRotation)))
+                            {
+                                ((EmphasisAnimation)result).RotationDegrees = ((AnimateRotation)obj).By / 60000;
+                                break;
+                            }
+                    }
+                    break;
+                case 6:
+                    {
+                        result.Type = AnimationTypes.GrowShrink;
+                        foreach (Object obj in commonTimeNode.Descendants())
+                            if (obj.GetType().Equals(typeof(AnimateScale)))
+                            {
+                                ((EmphasisAnimation)result).ScaleX = ((AnimateScale)obj).ByPosition.X.Value / 1000;
+                                ((EmphasisAnimation)result).ScaleY = ((AnimateScale)obj).ByPosition.Y.Value / 1000;
+                                break;
+                            }
+                    }
+                    break;
+                default: return null;
+            }
+
+            return result;
+        }
+
+        private SimpleAnimation handleEntranceAnimation(CommonTimeNode commonTimeNode, SimpleAnimation result)
+        {
+            switch (commonTimeNode.PresetId.Value)  //Presets for Entrance/Exit
+            {
+                case 1: result.Type = AnimationTypes.Appear; break;
+                case 54: result.Type = AnimationTypes.Glide; break;
+                case 19: result.Type = AnimationTypes.Swivel; break;
+                case 42: result.Type = AnimationTypes.Ascend; break;
+                case 3: result.Type = AnimationTypes.Blinds; break;
+                case 4: result.Type = AnimationTypes.Box; break;
+                case 25: result.Type = AnimationTypes.Boomerang; break;
+                case 43: result.Type = AnimationTypes.CenterRevolve; break;
+                case 5: result.Type = AnimationTypes.Checkerboard; break;
+                case 50: result.Type = AnimationTypes.Compress; break;
+                case 7: result.Type = AnimationTypes.TypeEntrance.Equals(commonTimeNode.PresetClass) ? AnimationTypes.CrawlIn : AnimationTypes.CrawlOut; break;
+                case 47: result.Type = AnimationTypes.Descend; break;
+                case 48: result.Type = AnimationTypes.Sling; break;
+                case 29: result.Type = AnimationTypes.TypeEntrance.Equals(commonTimeNode.PresetClass) ? AnimationTypes.EaseIn : AnimationTypes.EaseOut; break;
+                case 55: result.Type = AnimationTypes.TypeEntrance.Equals(commonTimeNode.PresetClass) ? AnimationTypes.Expand : AnimationTypes.Contract; break;
+                case 10: result.Type = AnimationTypes.Fade; break;
+                case 53: result.Type = AnimationTypes.FadedZoom; break;
+                case 11: result.Type = AnimationTypes.FlashOnce; break;
+                case 2: result.Type = AnimationTypes.TypeEntrance.Equals(commonTimeNode.PresetClass) ? AnimationTypes.FlyIn : AnimationTypes.FlyOut; break;
+                case 58: result.Type = AnimationTypes.Fold; break;
+                case 31: result.Type = AnimationTypes.GrowTurn; break;
+                case 12: result.Type = AnimationTypes.TypeEntrance.Equals(commonTimeNode.PresetClass) ? AnimationTypes.PeekIn : AnimationTypes.PeekOut; break;
+                case 16: result.Type = AnimationTypes.Split; break;
+                case 35: result.Type = AnimationTypes.Pinwheel; break;
+                case 14: result.Type = AnimationTypes.RandomBars; break;
+                case 37: result.Type = AnimationTypes.TypeEntrance.Equals(commonTimeNode.PresetClass) ? AnimationTypes.RiseUp : AnimationTypes.SinkDown; break;
+                case 49: result.Type = AnimationTypes.Spinner; break;
+                case 22: result.Type = AnimationTypes.Wipe; break;
+                case 18: result.Type = AnimationTypes.Strips; break;
+                case 26: result.Type = AnimationTypes.Bounce; result.Length = (int)((result.Length * 100) / 29); break;//time tunning
+                case 6: result.Type = AnimationTypes.Circle; break;
+                case 28: result.Type = AnimationTypes.Credits; break;
+                case 52: result.Type = AnimationTypes.TypeEntrance.Equals(commonTimeNode.PresetClass) ? AnimationTypes.CurveUp : AnimationTypes.CurveDown; break;
+                case 8: result.Type = AnimationTypes.Diamond; break;
+                case 9: result.Type = AnimationTypes.Dissolve; break;
+                case 30: result.Type = AnimationTypes.Float; break;
+                case 34: result.Type = AnimationTypes.LightSpeed; result.Length = (int)((result.Length * 5) / 3); break;//time tunning
+                case 51: result.Type = AnimationTypes.Magnify; result.Length = (int)((result.Length * 200) / 77); break;//time tunning
+                case 13: result.Type = AnimationTypes.Plus; break;
+                case 15: result.Type = AnimationTypes.TypeEntrance.Equals(commonTimeNode.PresetClass) ? AnimationTypes.SpiralIn : AnimationTypes.SpiralOut; break;
+                case 17: result.Type = AnimationTypes.Stretch; break;
+                case 39: result.Type = AnimationTypes.Thread; break;
+                case 20: result.Type = AnimationTypes.Wedge; break;
+                case 21: result.Type = AnimationTypes.Wheel; result.AdditionalData = "" + commonTimeNode.PresetSubtype.Value; break;
+                case 23: result.Type = AnimationTypes.Zoom; break;
+
+                default: return null;
+            }
+
+            return result;
+        }
+
+        private double getTransparence(CommonTimeNode commonTimeNode)
+        {
+            if (typeof(AnimateEffect) == commonTimeNode.LastChild.LastChild.GetType())
+            {
+                AnimateEffect animEffect = (AnimateEffect)commonTimeNode.LastChild.LastChild;
+                string value = animEffect.PropertyList.Value;
+                if (value != null && value.IndexOf("opacity:") != -1)
+                {
+                    string opacityStr = value.Substring(9);//we need 0.75 from "opacity: 0.75"
+                    double opacity = double.Parse(opacityStr, CultureInfo.GetCultureInfo("en-US").NumberFormat);
+                    return 1 - opacity;
+                }
+            }
+
+            return 0;
+        }
+
+        private List<IAnimation> fixNestedAnimations(List<IAnimation> animations)
+        {
+            if (animations == null || animations.Count == 0)
+                return null;
+            List<IAnimation> result = new List<IAnimation>();
+            foreach (IAnimation anim in animations)
+            {
+                IAnimation animation = getAnimationFromNested(anim);
+                animation.InnerAnimations = fixNestedAnimations(animation.InnerAnimations);
+                result.Add(animation);
+            }
+            return result;
+        }
+
+    }
+}

+ 195 - 0
HTEXLib/Animations/MotionPathAnimation.cs

@@ -0,0 +1,195 @@
+using DocumentFormat.OpenXml.Presentation;
+using HTEXLib.Models.Inner;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HTEXLib.Animations
+{
+    class MotionPathAnimation : SimpleAnimation
+    {
+        private List<PathPart> motionPath;
+        private SlideSize SlideSizes;
+        public int MultiplierX()
+        {
+            if (SlideSizes == null || SlideSizes.Cx == 0)
+            {
+                return 1;
+            }
+            else if (SlideSizes.Cx < Globals.LEAST_COMMON_MULTIPLE_100_254)
+            {
+                return Convert.ToInt32((double)(Globals.LEAST_COMMON_MULTIPLE_100_254) / SlideSizes.Cx);
+            }
+            else
+            {
+                return Convert.ToInt32(SlideSizes.Cx / (double)(Globals.LEAST_COMMON_MULTIPLE_100_254));
+            }
+        }
+
+        public int MultiplierY()
+        {
+            if (SlideSizes == null || SlideSizes.Cy == 0)
+            {
+                return 1;
+            }
+            else if (SlideSizes.Cy < Globals.LEAST_COMMON_MULTIPLE_100_254)
+            {
+                return Convert.ToInt32((double)(Globals.LEAST_COMMON_MULTIPLE_100_254) / SlideSizes.Cy);
+            }
+            else
+            {
+                return Convert.ToInt32(SlideSizes.Cy / (double)(Globals.LEAST_COMMON_MULTIPLE_100_254));
+            }
+        }
+        public MotionPathAnimation(CommonTimeNode commonTimeNode, int slideIndex, SlideSize SlideSizes)
+        {
+
+
+            this.SlideSizes = SlideSizes;
+            InitialState = 4;
+            timingType = commonTimeNode.NodeType;
+            Type = AnimationTypes.MotionPath;
+            AnimateMotion motion = null;
+            foreach (Object xmlEl in commonTimeNode.Descendants())
+                if (xmlEl.GetType().Equals(typeof(AnimateMotion)))
+                    motion = (AnimateMotion)xmlEl;
+            if (motion == null)
+                return;
+            String path = motion.Path.Value;
+            String[] parts = path.Split();
+            motionPath = new List<PathPart>();
+            int indexPart = -1;
+            bool isX = true;
+            foreach (string part in parts)
+            {
+                if ("".Equals(part) || "E".Equals(part))  //We add our End tag 
+                    continue;
+                Double coords = 0.0;
+                if (!Double.TryParse(part, NumberStyles.Float, CultureInfo.InvariantCulture, out coords))
+                {
+                    isX = true;
+                    if (indexPart >= 0)
+                    {  //FIX FOR POINTS WITH 3 COORDINATES UNTIL WE KNOW WHAT THEY ARE.
+                        List<PathPoint> previousPartPoints = motionPath[indexPart].points;
+                        if (previousPartPoints[previousPartPoints.Count - 1].Y.CompareTo(0) == 0)
+                            previousPartPoints.Remove(previousPartPoints[previousPartPoints.Count - 1]);
+                    }
+
+                    indexPart++;
+                    motionPath.Add(new PathPart());
+                    motionPath[indexPart].typeCharacter = part;
+                }
+                else if (isX)
+                {
+                    coords = coords * MultiplierX();
+                    PathPoint newPoint = new PathPoint();
+                    newPoint.X = coords;
+                    motionPath[indexPart].points.Add(newPoint);   // We have a new point
+                    isX = !isX;
+                }
+                else
+                {
+                    coords = coords * MultiplierY();
+                    motionPath[indexPart].points[motionPath[indexPart].points.Count - 1].Y = coords;  //Set Y for the last point
+                    isX = !isX;
+                }
+            }
+
+
+            FixAnimationTimings(motion.CommonBehavior, slideIndex);
+            generateAdditionDataString(motionPath);
+
+        }
+
+        private void generateAdditionDataString(List<PathPart> motionPath)
+        {
+            double wholeDistance = 0.0;
+            PathPoint lastPoint = null;
+            foreach (PathPart part in motionPath)
+            {
+                wholeDistance += part.Distance(lastPoint);
+                lastPoint = part.LastPoint();
+            }
+            PathPart previousPart = null;
+            String result = "";
+            foreach (PathPart part in motionPath)
+            {
+                result += "|" + part.typeCharacter + " ";
+                bool needsComma = false;
+                if (previousPart != null && previousPart.LastPoint() != null)
+                {
+                    needsComma = true;
+                    result += previousPart.LastPoint().X.ToString("0.##########", CultureInfo.CreateSpecificCulture("en-GB")) + "," +
+                                previousPart.LastPoint().Y.ToString("0.##########", CultureInfo.CreateSpecificCulture("en-GB"));
+                }
+                foreach (PathPoint point in part.points)
+                {
+                    result += (needsComma ? "," : "") +
+                                point.X.ToString("0.##########", CultureInfo.CreateSpecificCulture("en-GB")) + "," +
+                                point.Y.ToString("0.##########", CultureInfo.CreateSpecificCulture("en-GB"));
+                    needsComma = true;
+                }
+                if (previousPart != null) //First part doesn't have timing
+                {
+                    double timing = (part.Distance(previousPart.LastPoint()) / wholeDistance) * ((double)Length / (double)1000);
+                    result += "," + timing.ToString("0.##########", CultureInfo.CreateSpecificCulture("en-GB"));
+                }
+
+                previousPart = part;
+            }
+
+            result += "|E " + previousPart.LastPoint().X.ToString("0.##########", CultureInfo.CreateSpecificCulture("en-GB")) + "," +
+                                previousPart.LastPoint().Y.ToString("0.##########", CultureInfo.CreateSpecificCulture("en-GB"));
+            AdditionalData = "'" + result + "'";
+
+        }
+
+
+        private class PathPart
+        {
+            public string typeCharacter { get; set; }
+            public List<PathPoint> points { get; set; }
+            public PathPart()
+            {
+                points = new List<PathPoint>();
+            }
+            public PathPoint LastPoint()
+            {
+                if (points == null || points.Count == 0)
+                    return null;
+                return points[points.Count - 1];
+            }
+            public double Distance(PathPoint LastPoint)
+            {
+                double result = 0.0;
+                if (points.Count == 1 && LastPoint != null)
+                    return distanceBetweenPoints(points[0], LastPoint);
+                PathPoint previousPoint = null;
+                foreach (PathPoint point in points)
+                {
+                    if (previousPoint != null)
+                        result += distanceBetweenPoints(point, previousPoint);
+                    previousPoint = point;
+                }
+                return result;
+            }
+
+            private static double distanceBetweenPoints(PathPoint point1, PathPoint point2)
+            {
+                return System. Math.Sqrt(System.Math.Pow(point1.X - point2.X, 2) + System.Math.Pow(point1.Y - point2.Y, 2));
+            }
+        }
+
+
+        class PathPoint
+        {
+            public double X { get; set; }
+            public double Y { get; set; }
+        }
+
+    }
+}
+

+ 102 - 0
HTEXLib/Animations/SimpleAnimation.cs

@@ -0,0 +1,102 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using DocumentFormat.OpenXml.Presentation;
+using HTEXLib.Models.Inner;
+
+namespace HTEXLib.Animations
+{
+    public class SimpleAnimation : IAnimation
+    {
+        public SimpleAnimation()
+        {
+            AdditionalData = "0";
+            ObjectId = "0";
+        }
+        public int Start { get; set; }
+        public int Length { get; set; }
+        public string ObjectId { get; set; }
+        public int Repetitions { get; set; }
+        public int InitialState { get; set; }
+        public string Type { get; set; }
+        public string AdditionalData { get; set; }
+        public List<IAnimation> InnerAnimations { get; set; }
+        public DocumentFormat.OpenXml.EnumValue<DocumentFormat.OpenXml.Presentation.TimeNodeValues> timingType { get; set; }
+
+        public int getCalculatedLength()
+        {
+            if (InnerAnimations == null || InnerAnimations.Count == 0)
+                return Length;
+            int res = 0;
+            foreach (SimpleAnimation anim in InnerAnimations)
+                res = res < anim.getCalculatedLength() + anim.Start ? anim.getCalculatedLength() + anim.Start : res;
+            return res;
+        }
+
+        public bool IsItEntranceAnimation()
+        {
+            return InitialState == 1; //I am not sure if it is correct ;)
+        }
+
+        protected string GetObjectIdForJSON()
+        {
+            int res = 0;
+            string result = int.TryParse(ObjectId, out res) ? ObjectId : "'" + ObjectId + "'";
+            return result;
+        }
+        protected string GetE3Value()
+        {
+            int res = 0;
+            string result = int.TryParse(ObjectId, out res) ? "" : ",e3:['s1s" + ObjectId + "']";
+            return result;
+        }
+        public virtual string GetJsonString()
+        {
+
+            return "{objectId:" + GetObjectIdForJSON() + ",start:" + Start + ",length:" + Length + ",repeat:" + Repetitions + ",state:" + InitialState +
+                   ",name:'" + Type + "',additionalData:" + AdditionalData + ",v:0" + ",e0:" + GetE0Value() + ",e1:1,e2:0" + GetE3Value()
+                                                                                + "}";
+        }
+
+        protected string GetE0Value()//if image then 3 else 2
+        {
+            int res = 0;
+            return int.TryParse(ObjectId, out res) ? "3" : "2";
+        }
+
+        public void FixAnimationTimings(CommonBehavior behavior, int slideIndex)
+        {
+            String intValue = behavior.TargetElement.ShapeTarget.ShapeId.Value;
+            ObjectId = intValue == null ? "" + 0 : intValue;
+            int spd = behavior.CommonTimeNode.Speed == null ? 100 : behavior.CommonTimeNode.Speed.Value;
+            intValue = behavior.CommonTimeNode.Duration;
+            Length = intValue == null || intValue == "indefinite" ? 0 : int.Parse(intValue) * spd / 100;
+            int delay = 0;
+            if (behavior.CommonTimeNode.StartConditionList != null &&
+                behavior.CommonTimeNode.StartConditionList.Any())
+            {
+                foreach (Condition cond in behavior.CommonTimeNode.StartConditionList)
+                    if (cond.Delay != null && cond.Delay.HasValue)
+                        delay = delay + int.Parse(cond.Delay.Value);
+            }
+
+            if (behavior.TargetElement.ShapeTarget.TextElement != null && behavior.TargetElement.ShapeTarget.TextElement.ParagraphIndexRange != null)
+            {
+                int res = 0;
+                bool isTextWithEffect = int.TryParse(ObjectId, out res) && PPTShape.effectShapes.Contains(slideIndex + "_" + res);
+                if (!isTextWithEffect)
+                {
+                    ObjectId = ObjectId + "p" + behavior.TargetElement.ShapeTarget.TextElement.ParagraphIndexRange.Start;
+                }
+
+                //TODO: add support for paragraph start-end index range
+            }
+
+            intValue = behavior.CommonTimeNode.RepeatDuration;
+            Repetitions = intValue == null ? 1 : int.Parse(intValue);
+            InnerAnimations = new List<IAnimation>();
+            Start = delay;
+
+        }
+    }
+}

+ 18 - 0
HTEXLib/Animations/TransitionAnimation.cs

@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace HTEXLib.Animations
+{
+
+    internal class TransitionAnimation : SimpleAnimation
+    {
+        public bool AdvanceOnClick { get; set; }
+
+        public override string GetJsonString()
+        {
+            return "{objectId:" + GetObjectIdForJSON() + ",start:" + Start + ",length:" + Length + ",repeat:" + Repetitions + ",state:" + InitialState +
+                   ",name:'" + Type + "',additionalData:" + AdditionalData + "},v:0,n:" + (AdvanceOnClick ? "0" : "1");
+        }
+    }
+}

+ 1 - 26
HTEXLib/Builders/HtexBuilder.cs

@@ -220,30 +220,5 @@ namespace HTEXLib.Builders
             }
         }
     }
-    public static class PtOpenXmlExtensions
-    {
-        public static XDocument GetXDocument(this OpenXmlPart part)
-        {
-
-            XDocument partXDocument = part.Annotation<XDocument>();
-            if (partXDocument != null)
-                return partXDocument;
-            using (Stream partStream = part.GetStream())
-            using (XmlReader partXmlReader = XmlReader.Create(partStream))
-                partXDocument = XDocument.Load(partXmlReader);
-            part.AddAnnotation(partXDocument);
-            return partXDocument;
-        }
-
-        public static void PutXDocument(this OpenXmlPart part)
-        {
-            XDocument partXDocument = part.GetXDocument();
-            if (partXDocument != null)
-            {
-                using (Stream partStream = part.GetStream(FileMode.Create, FileAccess.Write))
-                using (XmlWriter partXmlWriter = XmlWriter.Create(partStream))
-                    partXDocument.Save(partXmlWriter);
-            }
-        }
-    }
+    
 }

+ 54 - 0
HTEXLib/Builders/HtexGenerator.cs

@@ -0,0 +1,54 @@
+using HTEXLib.Models;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace HTEXLib.Builders
+{
+    public   class HtexGenerator
+    {
+        private readonly int _numberOfSlides;
+        private readonly int _allSlidesCount;
+        private readonly int _slideIndex;
+        private readonly string _fileName;
+        private readonly string _baseFileName;
+        private readonly string _filePath;
+        private readonly StringBuilder _htmlPart;
+
+        private List<Item> items { get; set; }=new List<Item>();
+        private readonly PPTSlide _mSlide;
+      //  private const string JS_DIR_NAME = "temp"; 
+        public int SlideWidth { get; set; }
+        public int SlideHeight { get; set; }
+
+        public HtexGenerator(string filepath, string filename,
+                              PPTSlide aSlide, int slideCounter, int slidesNumber) {
+            _baseFileName = filename;
+            try
+            {
+                if (filename.Length != 0)
+                {
+                    if (slidesNumber != 1)
+                    {
+                        this._fileName = filename + "_" + slideCounter.ToString();
+                    }
+                    else
+                    {
+                        this._fileName = filename;
+                    }
+                }
+                this._mSlide = aSlide;
+                _numberOfSlides = 1;
+                _allSlidesCount = slidesNumber;
+                _slideIndex = slideCounter;
+                this._filePath = filepath;
+                this._htmlPart = new StringBuilder();
+            }
+            catch (ArgumentNullException ex)
+            {
+                Console.WriteLine("The passed value for filename:" + ex.Message);
+                return;
+            }
+        }
+    }
+}

+ 64 - 0
HTEXLib/Builders/PPTContainerShapeBuilder.cs

@@ -0,0 +1,64 @@
+using DocumentFormat.OpenXml;
+using DocumentFormat.OpenXml.Packaging;
+using DocumentFormat.OpenXml.Presentation;
+using HTEXLib.Models;
+using HTEXLib.Models.Inner;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HTEXLib.Builders
+{
+    internal class PPTContainerShapeBuilder
+    {
+        public PPTContainerShape GetPPTContainerShape(SlidePart slidePart, PPTSlide slide)
+        {
+            var pptContainerShape = new PPTContainerShape();
+            pptContainerShape.Elements = new List<PPTShapeBase>();
+            foreach (object obj in slidePart.Slide.Descendants())
+            {
+                if (typeof(Shape).Equals(obj.GetType()))
+                {
+                    pptContainerShape.Elements.Add(new PPTShape(slidePart, (DocumentFormat.OpenXml.Presentation.Shape)obj, slide));
+                }
+                else if (typeof(Picture).Equals(obj.GetType()))
+                {
+                    pptContainerShape.Elements.Add(new PPTImage(slidePart, (Picture)obj));
+                }
+                else if (typeof(GraphicFrame).Equals(obj.GetType()))
+                {
+                    pptContainerShape.Elements.Add(new PPTGraphicFrame(slidePart, (GraphicFrame)obj));
+                }
+                else if (typeof(GroupShape).Equals(obj.GetType()))
+                {
+                    pptContainerShape.Elements.Add(new PPTGroupShape(slidePart, (GroupShape)obj));
+                }
+                else if (typeof(ConnectionShape).Equals(obj.GetType()))
+                {
+                    pptContainerShape.Elements.Add(new PPTConnectionShape(slidePart, (ConnectionShape)obj));
+                }
+                else if (typeof(AlternateContent).Equals(obj.GetType())) {
+                    Console.WriteLine("mathdemo.pptx");
+
+                    AlternateContent alternateContent = (AlternateContent)obj;
+                    var  element = alternateContent.ChildElements.Where(x =>typeof(AlternateContentFallback).Equals(x.GetType())).FirstOrDefault();
+                    if (element != null) {
+                        AlternateContentFallback alternateContentFallback = (AlternateContentFallback)element;
+                        if (typeof(DocumentFormat.OpenXml.Presentation.Shape) .Equals(alternateContentFallback.ChildElements.First().GetType()))
+                        {
+                            pptContainerShape.Elements.Add(new PPTShape(slidePart, (DocumentFormat.OpenXml.Presentation.Shape)alternateContentFallback.First(), slide));
+                        }
+                        else if(typeof(Picture).Equals(alternateContentFallback.ChildElements.First().GetType()) ) {
+                            pptContainerShape.Elements.Add(new PPTImage(slidePart, (Picture)obj));
+                        }
+                    }
+                   // pptContainerShape.Elements.Add(new PPTAlternateContent(slidePart, (AlternateContent)obj, slide));
+                    ///  处理公式 方程等
+                }
+            }
+
+
+            return pptContainerShape;
+        }
+    }
+}

+ 37 - 0
HTEXLib/Builders/PtOpenXmlExtensions.cs

@@ -0,0 +1,37 @@
+using DocumentFormat.OpenXml.Packaging;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Xml;
+using System.Xml.Linq;
+
+namespace HTEXLib.Builders
+{
+    public static class PtOpenXmlExtensions
+    {
+        public static XDocument GetXDocument(this OpenXmlPart part)
+        {
+
+            XDocument partXDocument = part.Annotation<XDocument>();
+            if (partXDocument != null)
+                return partXDocument;
+            using (Stream partStream = part.GetStream())
+            using (XmlReader partXmlReader = XmlReader.Create(partStream))
+                partXDocument = XDocument.Load(partXmlReader);
+            part.AddAnnotation(partXDocument);
+            return partXDocument;
+        }
+
+        public static void PutXDocument(this OpenXmlPart part)
+        {
+            XDocument partXDocument = part.GetXDocument();
+            if (partXDocument != null)
+            {
+                using (Stream partStream = part.GetStream(FileMode.Create, FileAccess.Write))
+                using (XmlWriter partXmlWriter = XmlWriter.Create(partStream))
+                    partXDocument.Save(partXmlWriter);
+            }
+        }
+    }
+}

+ 5 - 0
HTEXLib/Models/Chart.cs

@@ -8,6 +8,11 @@ namespace HTEXLib
     {
         public  List<CommonChart> charts { get; set; }
         public List<Paragraph> title { get; set; }
+
+        public override Item DrawElement()
+        {
+            throw new NotImplementedException();
+        }
     }
 
     public abstract class CommonChart {

+ 5 - 1
HTEXLib/Models/Connector.cs

@@ -15,6 +15,10 @@ namespace HTEXLib
         //public string HeadEnd { get; set; }
         //public string TailEnd { get; set; }
         public Border border { get; set; }
-      
+
+        public override Item DrawElement()
+        {
+            throw new NotImplementedException();
+        }
     }
 }

+ 5 - 0
HTEXLib/Models/Diagram.cs

@@ -7,5 +7,10 @@ namespace HTEXLib
     public class Diagram :Item
     {
         public List<Item> shapes { get; set; }
+
+        public override Item DrawElement()
+        {
+            throw new NotImplementedException();
+        }
     }
 }

+ 5 - 0
HTEXLib/Models/Group.cs

@@ -7,5 +7,10 @@ namespace HTEXLib
     public  class Group : Item
     {
         public List<Item> shapes { get; set; }
+
+        public override Item DrawElement()
+        {
+            throw new NotImplementedException();
+        }
     }
 }

+ 44 - 0
HTEXLib/Models/Inner/PPTAlternateContent.cs

@@ -0,0 +1,44 @@
+using DocumentFormat.OpenXml;
+using DocumentFormat.OpenXml.Packaging;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace HTEXLib.Models.Inner
+{
+     public class PPTAlternateContent : PPTShapeBase
+    {
+        public PPTAlternateContent(SlidePart slidePart, AlternateContent alternateContent, PPTSlide slide)
+        {
+            
+            SetAlternateContentVisualProperties(slidePart, alternateContent);
+            SetAlternateContentNonVisualProperties(slidePart, alternateContent);
+
+        }
+
+        private void SetAlternateContentNonVisualProperties(SlidePart slidePart, AlternateContent alternateContent) { 
+        
+        }
+        private void SetAlternateContentVisualProperties(SlidePart slidePart, AlternateContent alternateContent)
+        {
+            //base.VisualShapeProp = new PPTVisualPPTShapeProp();
+            //base.SetSlideLayoutVisualShapeProperties(slidePart, alternateContent);
+            //if (shape.ShapeProperties.Transform2D != null)
+            //{
+            //    Int32Value rot = shape.ShapeProperties.Transform2D.Rotation;
+            //    if (rot != null)
+            //    {
+            //        double degrees = System.Math.Round(rot / RotationIndex);
+            //        if (degrees < 0)
+            //        {
+            //            degrees = 360 + degrees;
+            //        }
+            //        base.VisualShapeProp.Rotate = degrees;
+            //    }
+
+            //    base.VisualShapeProp.Extents = shape.ShapeProperties.Transform2D.Extents;
+            //    base.VisualShapeProp.Offset = shape.ShapeProperties.Transform2D.Offset;
+            //}
+        }
+    }
+}

+ 66 - 0
HTEXLib/Models/Inner/PPTConnectionShape.cs

@@ -0,0 +1,66 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using DocumentFormat.OpenXml.Packaging;
+using DocumentFormat.OpenXml.Presentation;
+namespace HTEXLib.Models.Inner
+{
+    public class PPTConnectionShape : PPTShapeBase
+    {
+        public PPTConnectionShape(SlidePart slidePart, ConnectionShape connectionShape)
+        {
+            SetConnectionShapeVisualProperties(slidePart, connectionShape);
+            SetConnectionShapeNonVisualProperties(slidePart, connectionShape);
+        }
+
+
+        private void SetConnectionShapeNonVisualProperties(SlidePart slidePart,
+                                                           ConnectionShape connectionShape)
+        {
+            if (connectionShape.NonVisualConnectionShapeProperties.NonVisualDrawingProperties.HyperlinkOnClick != null)
+                foreach (HyperlinkRelationship link in slidePart.HyperlinkRelationships)
+                    if (link.Id.Equals(connectionShape.NonVisualConnectionShapeProperties.NonVisualDrawingProperties.HyperlinkOnClick.Id))
+                        ClickLinkUrl = link.Uri.IsAbsoluteUri ? link.Uri.AbsoluteUri : link.Uri.OriginalString;
+
+            if (connectionShape.NonVisualConnectionShapeProperties.NonVisualDrawingProperties.HyperlinkOnHover != null)
+                foreach (HyperlinkRelationship link in slidePart.HyperlinkRelationships)
+                    if (link.Id.Equals(connectionShape.NonVisualConnectionShapeProperties.NonVisualDrawingProperties.HyperlinkOnHover.Id))
+                        HoverLinkUrl = link.Uri.IsAbsoluteUri ? link.Uri.AbsoluteUri : link.Uri.OriginalString;
+            var nonVisualShapeProp = new PPTNonVisualShapeProp
+            {
+                Id = "s1s" +  //HARD CODED: we split it into separate HTML files!
+                connectionShape.NonVisualConnectionShapeProperties.NonVisualDrawingProperties.Id,
+                Name = connectionShape.LocalName,
+                Type = "PPTConnectionShape"
+            };
+            base.NonVisualShapeProp = nonVisualShapeProp;
+        }
+
+        private void SetConnectionShapeVisualProperties(SlidePart slidePart,
+                                                        ConnectionShape connectionShape)
+        {
+            base.VisualShapeProp = new PPTVisualPPTShapeProp();
+            if (connectionShape.ShapeProperties.Transform2D != null)
+            {
+                base.VisualShapeProp.Extents = connectionShape.ShapeProperties.Transform2D.Extents;
+                base.VisualShapeProp.Offset = connectionShape.ShapeProperties.Transform2D.Offset;
+            }
+            else
+            {
+                ShapeTree shapeTree = slidePart.SlideLayoutPart.SlideLayout.CommonSlideData.ShapeTree;
+                ConnectionShape layoutShape;
+                if (shapeTree != null)
+                {
+                    layoutShape = shapeTree.GetFirstChild<ConnectionShape>();
+                    if (layoutShape.ShapeProperties.Transform2D != null)
+                    {
+                        base.VisualShapeProp.Extents = layoutShape.ShapeProperties.Transform2D.Extents;
+                        base.VisualShapeProp.Offset = layoutShape.ShapeProperties.Transform2D.Offset;
+                    }
+                }
+            }
+        }
+    }
+}

+ 76 - 0
HTEXLib/Models/Inner/PPTGraphicFrame.cs

@@ -0,0 +1,76 @@
+using DocumentFormat.OpenXml.Packaging;
+using DocumentFormat.OpenXml.Presentation;
+
+namespace HTEXLib.Models.Inner
+{
+    public class PPTGraphicFrame : PPTShapeBase
+    {
+        public PPTGraphicFrame(SlidePart slidePart, GraphicFrame gfarame)
+        {
+            SetGraphicFrameVisualProperties(slidePart, gfarame);
+            SetGraphicFrameNonVisualProperties(slidePart, gfarame);
+        }
+
+
+        private void SetGraphicFrameNonVisualProperties(SlidePart slidePart, GraphicFrame gfarame)
+        {
+
+            if (gfarame.NonVisualGraphicFrameProperties.NonVisualDrawingProperties.HyperlinkOnClick != null)
+                foreach (HyperlinkRelationship link in slidePart.HyperlinkRelationships)
+                    if (link.Id.Equals(gfarame.NonVisualGraphicFrameProperties.NonVisualDrawingProperties.HyperlinkOnClick.Id))
+                        ClickLinkUrl = link.Uri.IsAbsoluteUri ? link.Uri.AbsoluteUri : link.Uri.OriginalString;
+
+            if (gfarame.NonVisualGraphicFrameProperties.NonVisualDrawingProperties.HyperlinkOnHover != null)
+                foreach (HyperlinkRelationship link in slidePart.HyperlinkRelationships)
+                    if (link.Id.Equals(gfarame.NonVisualGraphicFrameProperties.NonVisualDrawingProperties.HyperlinkOnHover.Id))
+                        HoverLinkUrl = link.Uri.IsAbsoluteUri ? link.Uri.AbsoluteUri : link.Uri.OriginalString;
+
+            var nonVisualShapeProp = new PPTNonVisualShapeProp
+            {
+                Id = "s1s" + //HARD CODED: we split it into separate HTML files!
+                                                  gfarame.NonVisualGraphicFrameProperties.NonVisualDrawingProperties.Id,
+                Name = gfarame.LocalName,
+                Type = "PPTGraphicFrame"
+            };
+            base.NonVisualShapeProp = nonVisualShapeProp;
+        }
+
+        private void SetGraphicFrameVisualProperties(SlidePart slidePart,
+                                                     GraphicFrame gfarame)
+        {
+            base.VisualShapeProp = new PPTVisualPPTShapeProp();
+            if (gfarame.Transform != null)
+            {
+                base.VisualShapeProp.Extents = gfarame.Transform.Extents;
+                base.VisualShapeProp.Offset = gfarame.Transform.Offset;
+            }
+            else
+            {
+                //Petco change get properties from layout for GraphicFrame object.
+                DocumentFormat.OpenXml.Presentation.ShapeTree shapeTree =
+                   slidePart.SlideLayoutPart.SlideLayout.CommonSlideData.ShapeTree;
+                DocumentFormat.OpenXml.Presentation.GraphicFrame layoutShape;
+                if (shapeTree != null)
+                {
+                    layoutShape = shapeTree.GetFirstChild<DocumentFormat.OpenXml.Presentation.GraphicFrame>();
+                    if (layoutShape.Transform != null)
+                    {
+                        base.VisualShapeProp.Extents = layoutShape.Transform.Extents;
+                        base.VisualShapeProp.Offset = layoutShape.Transform.Offset;
+                    }
+                }
+            }
+        }
+
+        public void CreateImage(string targetDir)
+        {
+            /*
+            Image image = base.SourceImage;
+            Size size = new Size(base.shPr.PixelWidth, base.shPr.PixelHeight);
+
+            string path = Path.Combine(targetDir, base.nvSpPr.Id + defaultImageType );
+            //image.Save(Path.Combine(path));
+            */
+        }
+    }
+}

+ 67 - 0
HTEXLib/Models/Inner/PPTGroupShape.cs

@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using DocumentFormat.OpenXml.Packaging;
+
+namespace HTEXLib.Models.Inner
+{
+    public class PPTGroupShape : PPTShapeBase
+    {
+        public PPTGroupShape(SlidePart slidePart, DocumentFormat.OpenXml.Presentation.GroupShape groupShape)
+        {
+            SetGroupShapeVisualProperties(slidePart, groupShape);
+            SetGroupShapeNonVisualProperties(slidePart, groupShape);
+        }
+
+
+        private void SetGroupShapeNonVisualProperties(SlidePart slidePart, DocumentFormat.OpenXml.Presentation.GroupShape groupShape)
+        {
+            if (groupShape.NonVisualGroupShapeProperties.NonVisualDrawingProperties.HyperlinkOnClick != null)
+                foreach (HyperlinkRelationship link in slidePart.HyperlinkRelationships)
+                    if (link.Id.Equals(groupShape.NonVisualGroupShapeProperties.NonVisualDrawingProperties.HyperlinkOnClick.Id))
+                        ClickLinkUrl = link.Uri.IsAbsoluteUri ? link.Uri.AbsoluteUri : link.Uri.OriginalString;
+
+            if (groupShape.NonVisualGroupShapeProperties.NonVisualDrawingProperties.HyperlinkOnHover != null)
+                foreach (HyperlinkRelationship link in slidePart.HyperlinkRelationships)
+                    if (link.Id.Equals(groupShape.NonVisualGroupShapeProperties.NonVisualDrawingProperties.HyperlinkOnHover.Id))
+                        HoverLinkUrl = link.Uri.IsAbsoluteUri ? link.Uri.AbsoluteUri : link.Uri.OriginalString;
+
+            var nonVisualShapeProp = new PPTNonVisualShapeProp
+            {
+                Id = "s1s" +  //HARD CODED: we split it into separate HTML files!
+                groupShape.NonVisualGroupShapeProperties.NonVisualDrawingProperties.Id,
+                Name = groupShape.LocalName,
+                Type = "PPTGroupShape"
+            };
+            base.NonVisualShapeProp = nonVisualShapeProp;
+        }
+
+        private void SetGroupShapeVisualProperties(SlidePart slidePart, DocumentFormat.OpenXml.Presentation.GroupShape groupShape)
+        {
+            base.VisualShapeProp = new PPTVisualPPTShapeProp();
+            if (groupShape.GroupShapeProperties.TransformGroup != null)
+            {
+                base.VisualShapeProp.Extents = groupShape.GroupShapeProperties.TransformGroup.Extents;
+                base.VisualShapeProp.Offset = groupShape.GroupShapeProperties.TransformGroup.Offset;
+            }
+            else
+            {
+                DocumentFormat.OpenXml.Presentation.ShapeTree shapeTree =
+                    slidePart.SlideLayoutPart.SlideLayout.CommonSlideData.ShapeTree;
+                DocumentFormat.OpenXml.Presentation.GroupShape layoutShape;
+                if (shapeTree != null)
+                {
+                    layoutShape = shapeTree.GetFirstChild<DocumentFormat.OpenXml.Presentation.GroupShape>();
+                    if (layoutShape.GroupShapeProperties.TransformGroup != null)
+                    {
+                        base.VisualShapeProp.Extents = layoutShape.GroupShapeProperties.TransformGroup.Extents;
+                        base.VisualShapeProp.Offset = layoutShape.GroupShapeProperties.TransformGroup.Offset;
+                    }
+                }
+            }
+        }
+    }
+
+}

+ 31 - 1
HTEXLib/Models/Inner/PPTShape.cs

@@ -1,4 +1,4 @@
-using System;
+using System;
 using System.Collections.Generic;
 using System.Text;
 using DocumentFormat.OpenXml.Drawing;
@@ -101,6 +101,36 @@ namespace HTEXLib.Models.Inner
                 base.VisualShapeProp.Extents = shape.ShapeProperties.Transform2D.Extents;
                 base.VisualShapeProp.Offset = shape.ShapeProperties.Transform2D.Offset;
             }
+
+            foreach (var element in shape.ShapeProperties.ChildElements) {
+                if (typeof(DocumentFormat.OpenXml.Drawing.PresetGeometry).Equals(element.GetType())) {
+                    base.VisualShapeProp.PresetGeometry = (DocumentFormat.OpenXml.Drawing.PresetGeometry)element;
+                }
+                if (typeof(DocumentFormat.OpenXml.Drawing.BlipFill).Equals(element.GetType()))
+                {
+                    base.VisualShapeProp.BlipFill = (DocumentFormat.OpenXml.Drawing.BlipFill)element;
+                }
+                if (typeof(DocumentFormat.OpenXml.Drawing.NoFill).Equals(element.GetType()))
+                {
+                    base.VisualShapeProp.NoFill = (DocumentFormat.OpenXml.Drawing.NoFill)element;
+                }
+                if (typeof(DocumentFormat.OpenXml.Drawing.SolidFill).Equals(element.GetType()))
+                {
+                    base.VisualShapeProp.SolidFill = (DocumentFormat.OpenXml.Drawing.SolidFill)element;
+                }
+                if (typeof(DocumentFormat.OpenXml.Drawing.GradientFill).Equals(element.GetType()))
+                {
+                    base.VisualShapeProp.GradientFill = (DocumentFormat.OpenXml.Drawing.GradientFill)element;
+                }
+                if (typeof(DocumentFormat.OpenXml.Drawing.PatternFill).Equals(element.GetType()))
+                {
+                    base.VisualShapeProp.PatternFill = (DocumentFormat.OpenXml.Drawing.PatternFill)element;
+                }
+                if (typeof(DocumentFormat.OpenXml.Drawing.GroupFill).Equals(element.GetType()))
+                {
+                    base.VisualShapeProp.GroupFill = (DocumentFormat.OpenXml.Drawing.GroupFill)element;
+                }
+            }
         }
 
         private void SetSpecificProperties(SlidePart slidePart, DocumentFormat.OpenXml.Presentation.Shape shape)

+ 113 - 2
HTEXLib/Models/Inner/PPTSlide.cs

@@ -1,6 +1,8 @@
-using DocumentFormat.OpenXml.Packaging;
+using DocumentFormat.OpenXml;
+using DocumentFormat.OpenXml.Packaging;
 using DocumentFormat.OpenXml.Presentation;
 using HTEXLib.Animations;
+using HTEXLib.Builders;
 using HTEXLib.Models.Inner;
 using System;
 using System.Collections.Generic;
@@ -8,7 +10,7 @@ using System.Text;
 
 namespace HTEXLib.Models
 {
-   public class PPTSlide
+    public class PPTSlide:PPTShapeBase
     {
         public PPTSlide(SlidePart slidePart, int slideIndex, DefaultTextStyle defaultTextStyle, string fileName, SlideSize SlideSizes)
         {
@@ -68,5 +70,114 @@ namespace HTEXLib.Models
                 bshape.Animatable = true;
             }
         }
+        private void SetShapeNonVisualProperties(SlidePart slidePart)
+        {
+            var nonVisualShapeProp = new PPTNonVisualShapeProp
+            {
+                Id = "s1s1",
+                Name = slidePart.Slide.LocalName,
+                Type = "PPTSlide"
+            };
+            base.NonVisualShapeProp = nonVisualShapeProp;
+
+        }
+        private void SetSpecificProperties(SlidePart slidePart)
+        {
+            textStyles = slidePart.SlideLayoutPart.SlideMasterPart.SlideMaster.TextStyles;
+            var groupShapeBuilder = new PPTContainerShapeBuilder();
+            ContainerShape = groupShapeBuilder.GetPPTContainerShape(slidePart, this);
+
+        }
+        public void MakeShapeInvisible(String shapeId)
+        {
+            foreach (PPTShapeBase shape in ContainerShape.Elements)
+                if (shape.NonVisualShapeProp.Id.Equals(shapeId))
+                {
+                    shape.Invisible = true;
+                    return;
+                }
+                else if (typeof(PPTShape).Equals(shape.GetType()) && ((PPTShape)shape).IsText)
+                {
+                    foreach (PPTParagraph text in ((PPTShape)shape).Texts)
+                        if ((shape.NonVisualShapeProp.Id + "p" + text.Paragraph).Equals(shapeId))
+                        {
+                            text.Invisible = true;
+                            return;
+                        }
+                }
+
+        }
+        public void AddAnimations(OpenXmlCompositeElement element, List<IAnimation> resultList, SlideSize SlideSizes)
+        {
+            if (element == null)
+                return;
+
+            List<AnimateMotion> motions = new List<AnimateMotion>();
+            IAnimation animationForThisNode = null;
+            if (element.GetType().Equals(typeof(CommonTimeNode)))
+            {
+                CommonTimeNode node = (CommonTimeNode)element;
+                animationForThisNode = new JSONGenerator(this).getSimpleAnimationFromCommonTimeNodePreset(node, SlideSizes);
+
+                if (animationForThisNode != null)
+                {
+                    resultList.Add(animationForThisNode);
+                    //Check if object id is presented in animation list.
+                    CheckAndSetAnimatableProperty(animationForThisNode.ObjectId);
+
+                    if ((animationForThisNode.InnerAnimations == null ||
+                         animationForThisNode.InnerAnimations.Count == 0) &&
+                        animationForThisNode.IsItEntranceAnimation())
+
+                        MakeShapeInvisible("s1s" + animationForThisNode.ObjectId);
+                    else if (animationForThisNode.InnerAnimations != null)
+                        foreach (IAnimation anAnimation in animationForThisNode.InnerAnimations)
+                            if (anAnimation.IsItEntranceAnimation())
+                                MakeShapeInvisible("s1s" + animationForThisNode.ObjectId);
+                    return;
+                }
+                else
+                {
+                    /*
+                     * Sometimes there are common time nodes without animations in them. They are used for grouping animations.                      
+                     * Usually animations are grouped for timing purposes like adding delay to all, or start a group after another. 
+                     * It's a tree structure and here we try to follow it as much as possible. Later we will strip the unnecessary nodes 
+                     */
+
+                    animationForThisNode = new SimpleAnimation();
+                    if (node.NodeType != null)
+                        ((SimpleAnimation)animationForThisNode).timingType = node.NodeType;
+                    int delay = 0;
+                    if (node.StartConditionList != null)
+                        foreach (Condition cond in node.StartConditionList)
+                            if (cond.Delay != null && "indefinite" != cond.Delay.Value && cond.Delay.HasValue)
+                                delay = delay + int.Parse(cond.Delay.Value);
+                    if (delay > 0)
+                    {
+                        animationForThisNode.Start = delay;
+                    }
+                }
+
+                if (animationForThisNode != null)
+                {
+                    animationForThisNode.InnerAnimations = new List<IAnimation>();
+                    resultList.Add(animationForThisNode);
+                }
+
+            }
+
+            //Go recursive in the Open XML tree
+
+            foreach (OpenXmlElement obj in element.ChildElements)
+            {
+                if (obj.GetType().IsSubclassOf(typeof(OpenXmlCompositeElement)))
+                {
+                    if (animationForThisNode == null)
+                        AddAnimations((OpenXmlCompositeElement)obj, resultList, SlideSizes);
+                    else
+                        AddAnimations((OpenXmlCompositeElement)obj, animationForThisNode.InnerAnimations, SlideSizes);
+                }
+            }
+        }
     }
 }

+ 7 - 2
HTEXLib/Models/Inner/PPTVisualPPTShapeProp.cs

@@ -1,4 +1,4 @@
-using DocumentFormat.OpenXml.Drawing;
+using DocumentFormat.OpenXml.Drawing;
 using System;
 using System.Collections.Generic;
 using System.Text;
@@ -78,6 +78,11 @@ namespace HTEXLib.Models.Inner
 
 
         public SolidFill SolidFill { get; set; }
-
+        public NoFill NoFill { get; set; }
+        public GradientFill GradientFill { get; set; }
+        public BlipFill BlipFill { get; set; }
+        public PatternFill PatternFill { get; set; }
+        public GroupFill GroupFill { get; set; }
+        public PresetGeometry PresetGeometry { get; set; }
     }
 }

+ 3 - 0
HTEXLib/Models/Item.cs

@@ -73,5 +73,8 @@ namespace HTEXLib
         /// ¶¯»­¼¯ºÏ
         /// </summary>
        // public List<IAnimation> Animations { get; set; }
+
+        public abstract Item DrawElement();
+
     }
 }

+ 5 - 1
HTEXLib/Models/Math.cs

@@ -12,6 +12,10 @@ namespace HTEXLib
         public Fill fill { get; set; }
         
         public Border border { get; set; }
-      
+
+        public override Item DrawElement()
+        {
+            throw new NotImplementedException();
+        }
     }
 }

+ 4 - 1
HTEXLib/Models/Media.cs

@@ -16,7 +16,10 @@ namespace HTEXLib
         public Fill fill { get; set; }
       
         public Border border { get; set; }
-        
 
+        public override Item DrawElement()
+        {
+            throw new NotImplementedException();
+        }
     }
 }

+ 6 - 1
HTEXLib/Models/Shape.cs

@@ -10,7 +10,12 @@ namespace HTEXLib
         public List<Paragraph> paragraph { get; set; }
         public Fill fill { get; set; }
         public Border border { get; set; }
-       
+
+        public override Item DrawElement()
+        {
+            throw new NotImplementedException();
+        }
+
         //public List<ShapeGuide> ShapeGuides { get; set; }
         //public List<Path> Paths { get; set; }
         //public string BorderSha { get; set; }

+ 5 - 0
HTEXLib/Models/Table.cs

@@ -15,6 +15,11 @@ namespace HTEXLib
        // public Border Border { get; set; }
        // public Fill Fill { get; set; }
         public List<Tr> tr { get; set; }
+
+        public override Item DrawElement()
+        {
+            throw new NotImplementedException();
+        }
     }
 
     public class Tr {

+ 2 - 2
HTEXTest/Program.cs

@@ -1,4 +1,4 @@
-using HTEXLib.Builders;
+using HTEXLib.Builders;
 using HTEXLib.Models;
 using System;
 
@@ -8,7 +8,7 @@ namespace HTEXTest
     {
         static void Main(string[] args)
         {
-            string path = "F:\\PRD-20191015001.pptx";
+            string path = "F:\\mathdemo.pptx";
             var htexBuilder = new HtexBuilder();
             var pptSlides = htexBuilder.GetPPTSlides(path);
             int width = htexBuilder.getSlideWidth();