├── .gitignore
├── AnimationPreviewer.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── swiftpm
│ │ └── Package.resolved
└── xcshareddata
│ └── xcschemes
│ └── AnimationPreviewer.xcscheme
├── AnimationPreviewer.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── AnimationPreviewer
├── AnimationPreviewer-Bridging-Header.h
├── AnimationPreviewer.entitlements
├── AppDelegate.swift
├── Assets.xcassets
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── cat (1).png
│ │ ├── cat 1.png
│ │ ├── cat 2.png
│ │ ├── cat 3.png
│ │ ├── cat 4.png
│ │ ├── cat 5.png
│ │ ├── cat 6.png
│ │ ├── cat 7.png
│ │ ├── cat 8.png
│ │ └── cat 9.png
│ ├── Contents.json
│ ├── alpha_img.imageset
│ │ ├── Contents.json
│ │ ├── alpha_img@2x.png
│ │ └── alpha_img@3x.png
│ ├── bar_cat.imageset
│ │ ├── Contents.json
│ │ ├── bar_cat_black@1x.png
│ │ ├── bar_cat_black@2x.png
│ │ ├── bar_cat_while@1x.png
│ │ └── bar_cat_while@2x.png
│ ├── color_palette_icon.imageset
│ │ ├── Contents.json
│ │ ├── color_palette_icon@2x.png
│ │ └── color_palette_icon@3x.png
│ └── slider-oval.imageset
│ │ ├── Contents.json
│ │ ├── slider-oval@2x.png
│ │ └── slider-oval@3x.png
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── Data
│ ├── AnimationData.swift
│ ├── AnimationStore.swift
│ └── BgImageType.swift
├── Info.plist
├── MacChannel.swift
├── Neves
│ ├── Const
│ │ └── Function.swift
│ ├── Extension
│ │ ├── Bundle+.swift
│ │ ├── Data+.swift
│ │ ├── Literal+.swift
│ │ ├── UIColor+.swift
│ │ ├── UIImage+.swift
│ │ ├── UIScreen+.swift
│ │ ├── UIView+.swift
│ │ ├── URL+.swift
│ │ └── UserDefaults+.swift
│ ├── Protocol
│ │ ├── Bindable.swift
│ │ ├── Hookable.swift
│ │ └── JP.swift
│ ├── Tool
│ │ ├── Asyncs.swift
│ │ ├── Done.swift
│ │ ├── File.swift
│ │ ├── JPProgressHUD.swift
│ │ ├── LottieImage
│ │ │ ├── DecodeImageProvider.swift
│ │ │ ├── LottieImagePicker.swift
│ │ │ └── LottieImageStore.swift
│ │ ├── ScreenRotator.swift
│ │ ├── UserDefault.swift
│ │ └── VideoMaker
│ │ │ ├── VideoMaker+GIF.swift
│ │ │ ├── VideoMaker+Image.swift
│ │ │ ├── VideoMaker+ImageInfo.swift
│ │ │ ├── VideoMaker+ImageTest.swift
│ │ │ ├── VideoMaker+Layer.swift
│ │ │ ├── VideoMaker+Lottie.swift
│ │ │ ├── VideoMaker+SVGA.swift
│ │ │ └── VideoMaker.swift
│ └── Unit
│ │ ├── Buttons
│ │ └── Buttons.swift
│ │ ├── Gradient
│ │ ├── GradientView.swift
│ │ └── Gradientable.swift
│ │ └── ImagePicker
│ │ ├── ImagePicker.API.swift
│ │ ├── ImagePicker.swift
│ │ └── ImagePickerObject.swift
├── SVGAPlayer_Optimized
│ ├── SVGAExPlayer.swift
│ ├── SVGARePlayer.h
│ ├── SVGARePlayer.m
│ ├── SVGAVideoEntity+Extension.h
│ └── SVGAVideoEntity+Extension.m
├── SceneDelegate.swift
├── ThirdLib
│ ├── SVGAPlayer
│ │ ├── SVGA.h
│ │ ├── SVGA.m
│ │ ├── SVGAAudioEntity.h
│ │ ├── SVGAAudioEntity.m
│ │ ├── SVGAAudioLayer.h
│ │ ├── SVGAAudioLayer.m
│ │ ├── SVGABezierPath.h
│ │ ├── SVGABezierPath.m
│ │ ├── SVGABitmapLayer.h
│ │ ├── SVGABitmapLayer.m
│ │ ├── SVGAContentLayer.h
│ │ ├── SVGAContentLayer.m
│ │ ├── SVGAExporter.h
│ │ ├── SVGAExporter.m
│ │ ├── SVGAImageView.h
│ │ ├── SVGAImageView.m
│ │ ├── SVGAParser.h
│ │ ├── SVGAParser.m
│ │ ├── SVGAPlayer.h
│ │ ├── SVGAPlayer.m
│ │ ├── SVGAVectorLayer.h
│ │ ├── SVGAVectorLayer.m
│ │ ├── SVGAVideoEntity.h
│ │ ├── SVGAVideoEntity.m
│ │ ├── SVGAVideoSpriteEntity.h
│ │ ├── SVGAVideoSpriteEntity.m
│ │ ├── SVGAVideoSpriteFrameEntity.h
│ │ ├── SVGAVideoSpriteFrameEntity.m
│ │ └── pbobjc
│ │ │ ├── Svga.pbobjc.h
│ │ │ └── Svga.pbobjc.m
│ ├── SVProgressHUD
│ │ ├── SVIndefiniteAnimatedView.h
│ │ ├── SVIndefiniteAnimatedView.m
│ │ ├── SVProgressAnimatedView.h
│ │ ├── SVProgressAnimatedView.m
│ │ ├── SVProgressHUD.bundle
│ │ │ ├── angle-mask.png
│ │ │ ├── angle-mask@2x.png
│ │ │ ├── angle-mask@3x.png
│ │ │ ├── error.png
│ │ │ ├── error@2x.png
│ │ │ ├── error@3x.png
│ │ │ ├── info.png
│ │ │ ├── info@2x.png
│ │ │ ├── info@3x.png
│ │ │ ├── success.png
│ │ │ ├── success@2x.png
│ │ │ └── success@3x.png
│ │ ├── SVProgressHUD.h
│ │ ├── SVProgressHUD.m
│ │ ├── SVRadialGradientLayer.h
│ │ └── SVRadialGradientLayer.m
│ ├── lottie
│ │ ├── Private
│ │ │ ├── CoreAnimation
│ │ │ │ ├── Animations
│ │ │ │ │ ├── CAAnimation+TimingConfiguration.swift
│ │ │ │ │ ├── CALayer+addAnimation.swift
│ │ │ │ │ ├── CombinedShapeAnimation.swift
│ │ │ │ │ ├── CustomPathAnimation.swift
│ │ │ │ │ ├── EllipseAnimation.swift
│ │ │ │ │ ├── GradientAnimations.swift
│ │ │ │ │ ├── LayerProperty.swift
│ │ │ │ │ ├── OpacityAnimation.swift
│ │ │ │ │ ├── RectangleAnimation.swift
│ │ │ │ │ ├── ShapeAnimation.swift
│ │ │ │ │ ├── StarAnimation.swift
│ │ │ │ │ ├── StrokeAnimation.swift
│ │ │ │ │ ├── TransformAnimations.swift
│ │ │ │ │ └── VisibilityAnimation.swift
│ │ │ │ ├── CompatibilityTracker.swift
│ │ │ │ ├── CoreAnimationLayer.swift
│ │ │ │ ├── Extensions
│ │ │ │ │ ├── CALayer+fillBounds.swift
│ │ │ │ │ ├── KeyframeGroup+exactlyOneKeyframe.swift
│ │ │ │ │ └── Keyframes+combinedIfPossible.swift
│ │ │ │ ├── Layers
│ │ │ │ │ ├── AnimationLayer.swift
│ │ │ │ │ ├── BaseAnimationLayer.swift
│ │ │ │ │ ├── BaseCompositionLayer.swift
│ │ │ │ │ ├── CALayer+setupLayerHierarchy.swift
│ │ │ │ │ ├── GradientRenderLayer.swift
│ │ │ │ │ ├── ImageLayer.swift
│ │ │ │ │ ├── LayerModel+makeAnimationLayer.swift
│ │ │ │ │ ├── MaskCompositionLayer.swift
│ │ │ │ │ ├── PreCompLayer.swift
│ │ │ │ │ ├── RepeaterLayer.swift
│ │ │ │ │ ├── ShapeItemLayer.swift
│ │ │ │ │ ├── ShapeLayer.swift
│ │ │ │ │ ├── SolidLayer.swift
│ │ │ │ │ ├── TextLayer.swift
│ │ │ │ │ └── TransformLayer.swift
│ │ │ │ └── ValueProviderStore.swift
│ │ │ ├── MainThread
│ │ │ │ ├── LayerContainers
│ │ │ │ │ ├── CompLayers
│ │ │ │ │ │ ├── CompositionLayer.swift
│ │ │ │ │ │ ├── ImageCompositionLayer.swift
│ │ │ │ │ │ ├── MaskContainerLayer.swift
│ │ │ │ │ │ ├── NullCompositionLayer.swift
│ │ │ │ │ │ ├── PreCompositionLayer.swift
│ │ │ │ │ │ ├── ShapeCompositionLayer.swift
│ │ │ │ │ │ ├── SolidCompositionLayer.swift
│ │ │ │ │ │ └── TextCompositionLayer.swift
│ │ │ │ │ ├── MainThreadAnimationLayer.swift
│ │ │ │ │ └── Utility
│ │ │ │ │ │ ├── CachedImageProvider.swift
│ │ │ │ │ │ ├── CompositionLayersInitializer.swift
│ │ │ │ │ │ ├── CoreTextRenderLayer.swift
│ │ │ │ │ │ ├── InvertedMatteLayer.swift
│ │ │ │ │ │ ├── LayerFontProvider.swift
│ │ │ │ │ │ ├── LayerImageProvider.swift
│ │ │ │ │ │ ├── LayerTextProvider.swift
│ │ │ │ │ │ └── LayerTransformNode.swift
│ │ │ │ └── NodeRenderSystem
│ │ │ │ │ ├── Extensions
│ │ │ │ │ └── ItemsExtension.swift
│ │ │ │ │ ├── NodeProperties
│ │ │ │ │ ├── NodeProperty.swift
│ │ │ │ │ ├── Protocols
│ │ │ │ │ │ ├── AnyNodeProperty.swift
│ │ │ │ │ │ ├── AnyValueContainer.swift
│ │ │ │ │ │ ├── KeypathSearchable.swift
│ │ │ │ │ │ └── NodePropertyMap.swift
│ │ │ │ │ ├── ValueContainer.swift
│ │ │ │ │ └── ValueProviders
│ │ │ │ │ │ ├── GroupInterpolator.swift
│ │ │ │ │ │ └── SingleValueProvider.swift
│ │ │ │ │ ├── Nodes
│ │ │ │ │ ├── ModifierNodes
│ │ │ │ │ │ └── TrimPathNode.swift
│ │ │ │ │ ├── OutputNodes
│ │ │ │ │ │ ├── GroupOutputNode.swift
│ │ │ │ │ │ ├── PassThroughOutputNode.swift
│ │ │ │ │ │ ├── PathOutputNode.swift
│ │ │ │ │ │ └── Renderables
│ │ │ │ │ │ │ ├── FillRenderer.swift
│ │ │ │ │ │ │ ├── GradientFillRenderer.swift
│ │ │ │ │ │ │ ├── GradientStrokeRenderer.swift
│ │ │ │ │ │ │ ├── LegacyGradientFillRenderer.swift
│ │ │ │ │ │ │ └── StrokeRenderer.swift
│ │ │ │ │ ├── PathNodes
│ │ │ │ │ │ ├── EllipseNode.swift
│ │ │ │ │ │ ├── PolygonNode.swift
│ │ │ │ │ │ ├── RectNode.swift
│ │ │ │ │ │ ├── ShapeNode.swift
│ │ │ │ │ │ └── StarNode.swift
│ │ │ │ │ ├── RenderContainers
│ │ │ │ │ │ └── GroupNode.swift
│ │ │ │ │ ├── RenderNodes
│ │ │ │ │ │ ├── FillNode.swift
│ │ │ │ │ │ ├── GradientFillNode.swift
│ │ │ │ │ │ ├── GradientStrokeNode.swift
│ │ │ │ │ │ └── StrokeNode.swift
│ │ │ │ │ └── Text
│ │ │ │ │ │ └── TextAnimatorNode.swift
│ │ │ │ │ ├── Protocols
│ │ │ │ │ ├── AnimatorNode.swift
│ │ │ │ │ ├── PathNode.swift
│ │ │ │ │ └── RenderNode.swift
│ │ │ │ │ └── RenderLayers
│ │ │ │ │ ├── ShapeContainerLayer.swift
│ │ │ │ │ └── ShapeRenderLayer.swift
│ │ │ ├── Model
│ │ │ │ ├── Assets
│ │ │ │ │ ├── Asset.swift
│ │ │ │ │ ├── AssetLibrary.swift
│ │ │ │ │ ├── ImageAsset.swift
│ │ │ │ │ └── PrecompAsset.swift
│ │ │ │ ├── DictionaryInitializable.swift
│ │ │ │ ├── Extensions
│ │ │ │ │ ├── Bundle.swift
│ │ │ │ │ └── KeyedDecodingContainerExtensions.swift
│ │ │ │ ├── Keyframes
│ │ │ │ │ ├── KeyframeData.swift
│ │ │ │ │ └── KeyframeGroup.swift
│ │ │ │ ├── Layers
│ │ │ │ │ ├── ImageLayerModel.swift
│ │ │ │ │ ├── LayerModel.swift
│ │ │ │ │ ├── PreCompLayerModel.swift
│ │ │ │ │ ├── ShapeLayerModel.swift
│ │ │ │ │ ├── SolidLayerModel.swift
│ │ │ │ │ └── TextLayerModel.swift
│ │ │ │ ├── Objects
│ │ │ │ │ ├── DashPattern.swift
│ │ │ │ │ ├── Marker.swift
│ │ │ │ │ ├── Mask.swift
│ │ │ │ │ └── Transform.swift
│ │ │ │ ├── ShapeItems
│ │ │ │ │ ├── Ellipse.swift
│ │ │ │ │ ├── Fill.swift
│ │ │ │ │ ├── GradientFill.swift
│ │ │ │ │ ├── GradientStroke.swift
│ │ │ │ │ ├── Group.swift
│ │ │ │ │ ├── Merge.swift
│ │ │ │ │ ├── Rectangle.swift
│ │ │ │ │ ├── Repeater.swift
│ │ │ │ │ ├── Shape.swift
│ │ │ │ │ ├── ShapeItem.swift
│ │ │ │ │ ├── ShapeTransform.swift
│ │ │ │ │ ├── Star.swift
│ │ │ │ │ ├── Stroke.swift
│ │ │ │ │ └── Trim.swift
│ │ │ │ └── Text
│ │ │ │ │ ├── Font.swift
│ │ │ │ │ ├── Glyph.swift
│ │ │ │ │ ├── TextAnimator.swift
│ │ │ │ │ └── TextDocument.swift
│ │ │ ├── RootAnimationLayer.swift
│ │ │ └── Utility
│ │ │ │ ├── Debugging
│ │ │ │ ├── AnimatorNodeDebugging.swift
│ │ │ │ ├── LayerDebugging.swift
│ │ │ │ └── TestHelpers.swift
│ │ │ │ ├── Extensions
│ │ │ │ ├── AnimationKeypathExtension.swift
│ │ │ │ ├── BlendMode+Filter.swift
│ │ │ │ ├── CGColor+RGB.swift
│ │ │ │ ├── CGFloatExtensions.swift
│ │ │ │ ├── DataExtension.swift
│ │ │ │ ├── MathKit.swift
│ │ │ │ └── StringExtensions.swift
│ │ │ │ ├── Helpers
│ │ │ │ └── AnimationContext.swift
│ │ │ │ ├── Interpolatable
│ │ │ │ ├── InterpolatableExtensions.swift
│ │ │ │ ├── KeyframeExtensions.swift
│ │ │ │ ├── KeyframeGroup+Extensions.swift
│ │ │ │ └── KeyframeInterpolator.swift
│ │ │ │ └── Primitives
│ │ │ │ ├── BezierPath.swift
│ │ │ │ ├── CGPointExtension.swift
│ │ │ │ ├── ColorExtension.swift
│ │ │ │ ├── CompoundBezierPath.swift
│ │ │ │ ├── CurveVertex.swift
│ │ │ │ ├── PathElement.swift
│ │ │ │ ├── UnitBezier.swift
│ │ │ │ └── VectorsExtensions.swift
│ │ └── Public
│ │ │ ├── Animation
│ │ │ ├── LottieAnimation.swift
│ │ │ ├── LottieAnimationHelpers.swift
│ │ │ ├── LottieAnimationView.swift
│ │ │ └── LottieAnimationViewInitializers.swift
│ │ │ ├── AnimationCache
│ │ │ ├── AnimationCacheProvider.swift
│ │ │ └── LRUAnimationCache.swift
│ │ │ ├── DynamicProperties
│ │ │ ├── AnimationKeypath.swift
│ │ │ ├── AnyValueProvider.swift
│ │ │ └── ValueProviders
│ │ │ │ ├── ColorValueProvider.swift
│ │ │ │ ├── FloatValueProvider.swift
│ │ │ │ ├── GradientValueProvider.swift
│ │ │ │ ├── PointValueProvider.swift
│ │ │ │ └── SizeValueProvider.swift
│ │ │ ├── FontProvider
│ │ │ └── AnimationFontProvider.swift
│ │ │ ├── ImageProvider
│ │ │ └── AnimationImageProvider.swift
│ │ │ ├── Keyframes
│ │ │ ├── Interpolatable.swift
│ │ │ └── Keyframe.swift
│ │ │ ├── Logging
│ │ │ └── LottieLogger.swift
│ │ │ ├── LottieConfiguration.swift
│ │ │ ├── Primitives
│ │ │ ├── AnimationTime.swift
│ │ │ ├── LottieColor.swift
│ │ │ └── Vectors.swift
│ │ │ ├── TextProvider
│ │ │ └── AnimationTextProvider.swift
│ │ │ └── iOS
│ │ │ ├── AnimatedButton.swift
│ │ │ ├── AnimatedControl.swift
│ │ │ ├── AnimatedSwitch.swift
│ │ │ ├── AnimationSubview.swift
│ │ │ ├── BundleImageProvider.swift
│ │ │ ├── Compatibility
│ │ │ ├── CompatibleAnimationKeypath.swift
│ │ │ └── CompatibleAnimationView.swift
│ │ │ ├── FilepathImageProvider.swift
│ │ │ ├── LottieAnimationViewBase.swift
│ │ │ └── UIColorExtension.swift
│ └── 自定义取色板
│ │ ├── ColorPickerClasses
│ │ ├── ANImageBitmapRep
│ │ │ ├── ANImageBitmapRep.h
│ │ │ ├── ANImageBitmapRep.m
│ │ │ ├── BitmapContextRep.h
│ │ │ ├── BitmapContextRep.m
│ │ │ ├── Compatibility
│ │ │ │ ├── NSImage+ANImageBitmapRep.h
│ │ │ │ ├── NSImage+ANImageBitmapRep.m
│ │ │ │ ├── OSCommonImage.h
│ │ │ │ ├── OSCommonImage.m
│ │ │ │ ├── UIImage+ANImageBitmapRep.h
│ │ │ │ └── UIImage+ANImageBitmapRep.m
│ │ │ ├── CoreGraphics
│ │ │ │ ├── CGContextCreator.h
│ │ │ │ ├── CGContextCreator.m
│ │ │ │ ├── CGImageContainer.h
│ │ │ │ └── CGImageContainer.m
│ │ │ └── Manipulators
│ │ │ │ ├── BitmapContextManipulator.h
│ │ │ │ ├── BitmapContextManipulator.m
│ │ │ │ ├── BitmapCropManipulator.h
│ │ │ │ ├── BitmapCropManipulator.m
│ │ │ │ ├── BitmapDrawManipulator.h
│ │ │ │ ├── BitmapDrawManipulator.m
│ │ │ │ ├── BitmapRotationManipulator.h
│ │ │ │ ├── BitmapRotationManipulator.m
│ │ │ │ ├── BitmapScaleManipulator.h
│ │ │ │ └── BitmapScaleManipulator.m
│ │ ├── BGRSLoupeLayer.h
│ │ ├── BGRSLoupeLayer.m
│ │ ├── RSColorFunctions.h
│ │ ├── RSColorFunctions.m
│ │ ├── RSColorPickerState.h
│ │ ├── RSColorPickerState.m
│ │ ├── RSColorPickerView.h
│ │ ├── RSColorPickerView.m
│ │ ├── RSGenerateOperation.h
│ │ ├── RSGenerateOperation.m
│ │ ├── RSSelectionLayer.h
│ │ └── RSSelectionLayer.m
│ │ ├── DSDetailColorBoard.h
│ │ ├── DSDetailColorBoard.m
│ │ ├── DSRGBAColorLabel.h
│ │ ├── DSRGBAColorLabel.m
│ │ ├── DSSliderBoard.h
│ │ ├── DSSliderBoard.m
│ │ ├── RSBrightnessSlider.h
│ │ ├── RSBrightnessSlider.m
│ │ ├── RSOpacitySlider.h
│ │ ├── RSOpacitySlider.m
│ │ ├── SilderPlaceHolderView.h
│ │ └── SilderPlaceHolderView.m
├── View
│ ├── AnimationImageView.swift
│ └── AnimationPlayView.swift
├── ViewController
│ ├── ViewController+Drop.swift
│ └── ViewController.swift
├── background1.jpg
└── background2.jpg
├── MacPlugin
├── Channel.swift
├── MacPlugin-Bridging-Header.h
└── MacPlugin.swift
├── Podfile
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | # OS X
2 | .DS_Store
3 |
4 | # Xcode
5 | build/
6 | *.pbxuser
7 | !default.pbxuser
8 | *.mode1v3
9 | !default.mode1v3
10 | *.mode2v3
11 | !default.mode2v3
12 | *.perspectivev3
13 | !default.perspectivev3
14 | xcuserdata/
15 | *.xccheckout
16 | profile
17 | *.moved-aside
18 | DerivedData
19 | *.hmap
20 | *.ipa
21 |
22 | # Bundler
23 | .bundle
24 |
25 | Carthage
26 | # We recommend against adding the Pods directory to your .gitignore. However
27 | # you should judge for yourself, the pros and cons are mentioned at:
28 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
29 | #
30 | # Note: if you ignore the Pods directory, make sure to uncomment
31 | # `pod install` in .travis.yml
32 | #
33 | # Pods/
34 |
35 | #CocoaPods
36 | Pods
37 | Podfile.lock
38 | !Podfile
39 |
--------------------------------------------------------------------------------
/AnimationPreviewer.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/AnimationPreviewer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/AnimationPreviewer.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "pins" : [
3 | {
4 | "identity" : "snapkit",
5 | "kind" : "remoteSourceControl",
6 | "location" : "https://github.com/SnapKit/SnapKit.git",
7 | "state" : {
8 | "revision" : "f222cbdf325885926566172f6f5f06af95473158",
9 | "version" : "5.6.0"
10 | }
11 | }
12 | ],
13 | "version" : 2
14 | }
15 |
--------------------------------------------------------------------------------
/AnimationPreviewer.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/AnimationPreviewer.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/AnimationPreviewer/AnimationPreviewer-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Use this file to import your target's public headers that you would like to expose to Swift.
3 | //
4 |
5 | #import
6 | #import "SVProgressHUD.h"
7 | #import "SVGARePlayer.h"
8 | #import "SVGAParser.h"
9 | #import "DSDetailColorBoard.h"
10 |
--------------------------------------------------------------------------------
/AnimationPreviewer/AnimationPreviewer.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.downloads.read-write
8 |
9 | com.apple.security.files.user-selected.read-only
10 |
11 | com.apple.security.network.client
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "cat (1).png",
5 | "idiom" : "mac",
6 | "scale" : "1x",
7 | "size" : "16x16"
8 | },
9 | {
10 | "filename" : "cat 2.png",
11 | "idiom" : "mac",
12 | "scale" : "2x",
13 | "size" : "16x16"
14 | },
15 | {
16 | "filename" : "cat 3.png",
17 | "idiom" : "mac",
18 | "scale" : "1x",
19 | "size" : "32x32"
20 | },
21 | {
22 | "filename" : "cat 4.png",
23 | "idiom" : "mac",
24 | "scale" : "2x",
25 | "size" : "32x32"
26 | },
27 | {
28 | "filename" : "cat 5.png",
29 | "idiom" : "mac",
30 | "scale" : "1x",
31 | "size" : "128x128"
32 | },
33 | {
34 | "filename" : "cat 6.png",
35 | "idiom" : "mac",
36 | "scale" : "2x",
37 | "size" : "128x128"
38 | },
39 | {
40 | "filename" : "cat 7.png",
41 | "idiom" : "mac",
42 | "scale" : "1x",
43 | "size" : "256x256"
44 | },
45 | {
46 | "filename" : "cat 8.png",
47 | "idiom" : "mac",
48 | "scale" : "2x",
49 | "size" : "256x256"
50 | },
51 | {
52 | "filename" : "cat 9.png",
53 | "idiom" : "mac",
54 | "scale" : "1x",
55 | "size" : "512x512"
56 | },
57 | {
58 | "filename" : "cat 1.png",
59 | "idiom" : "mac",
60 | "scale" : "2x",
61 | "size" : "512x512"
62 | }
63 | ],
64 | "info" : {
65 | "author" : "xcode",
66 | "version" : 1
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/AppIcon.appiconset/cat (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/Assets.xcassets/AppIcon.appiconset/cat (1).png
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/AppIcon.appiconset/cat 1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/Assets.xcassets/AppIcon.appiconset/cat 1.png
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/AppIcon.appiconset/cat 2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/Assets.xcassets/AppIcon.appiconset/cat 2.png
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/AppIcon.appiconset/cat 3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/Assets.xcassets/AppIcon.appiconset/cat 3.png
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/AppIcon.appiconset/cat 4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/Assets.xcassets/AppIcon.appiconset/cat 4.png
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/AppIcon.appiconset/cat 5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/Assets.xcassets/AppIcon.appiconset/cat 5.png
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/AppIcon.appiconset/cat 6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/Assets.xcassets/AppIcon.appiconset/cat 6.png
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/AppIcon.appiconset/cat 7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/Assets.xcassets/AppIcon.appiconset/cat 7.png
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/AppIcon.appiconset/cat 8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/Assets.xcassets/AppIcon.appiconset/cat 8.png
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/AppIcon.appiconset/cat 9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/Assets.xcassets/AppIcon.appiconset/cat 9.png
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/alpha_img.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "alpha_img@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "alpha_img@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/alpha_img.imageset/alpha_img@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/Assets.xcassets/alpha_img.imageset/alpha_img@2x.png
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/alpha_img.imageset/alpha_img@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/Assets.xcassets/alpha_img.imageset/alpha_img@3x.png
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/bar_cat.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "bar_cat_black@1x.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "appearances" : [
10 | {
11 | "appearance" : "luminosity",
12 | "value" : "dark"
13 | }
14 | ],
15 | "filename" : "bar_cat_while@1x.png",
16 | "idiom" : "universal",
17 | "scale" : "1x"
18 | },
19 | {
20 | "filename" : "bar_cat_black@2x.png",
21 | "idiom" : "universal",
22 | "scale" : "2x"
23 | },
24 | {
25 | "appearances" : [
26 | {
27 | "appearance" : "luminosity",
28 | "value" : "dark"
29 | }
30 | ],
31 | "filename" : "bar_cat_while@2x.png",
32 | "idiom" : "universal",
33 | "scale" : "2x"
34 | },
35 | {
36 | "idiom" : "universal",
37 | "scale" : "3x"
38 | },
39 | {
40 | "appearances" : [
41 | {
42 | "appearance" : "luminosity",
43 | "value" : "dark"
44 | }
45 | ],
46 | "idiom" : "universal",
47 | "scale" : "3x"
48 | }
49 | ],
50 | "info" : {
51 | "author" : "xcode",
52 | "version" : 1
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/bar_cat.imageset/bar_cat_black@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/Assets.xcassets/bar_cat.imageset/bar_cat_black@1x.png
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/bar_cat.imageset/bar_cat_black@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/Assets.xcassets/bar_cat.imageset/bar_cat_black@2x.png
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/bar_cat.imageset/bar_cat_while@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/Assets.xcassets/bar_cat.imageset/bar_cat_while@1x.png
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/bar_cat.imageset/bar_cat_while@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/Assets.xcassets/bar_cat.imageset/bar_cat_while@2x.png
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/color_palette_icon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "color_palette_icon@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "color_palette_icon@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/color_palette_icon.imageset/color_palette_icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/Assets.xcassets/color_palette_icon.imageset/color_palette_icon@2x.png
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/color_palette_icon.imageset/color_palette_icon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/Assets.xcassets/color_palette_icon.imageset/color_palette_icon@3x.png
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/slider-oval.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "slider-oval@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "slider-oval@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/slider-oval.imageset/slider-oval@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/Assets.xcassets/slider-oval.imageset/slider-oval@2x.png
--------------------------------------------------------------------------------
/AnimationPreviewer/Assets.xcassets/slider-oval.imageset/slider-oval@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/Assets.xcassets/slider-oval.imageset/slider-oval@3x.png
--------------------------------------------------------------------------------
/AnimationPreviewer/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Data/AnimationData.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimationData.swift
3 | // AnimationPreviewer
4 | //
5 | // Created by aa on 2023/8/22.
6 | //
7 |
8 | import Foundation
9 | import UniformTypeIdentifiers
10 |
11 | class AnimationData: NSObject, NSItemProviderReading {
12 | static func object(withItemProviderData data: Data, typeIdentifier: String) throws -> Self {
13 | return try Self.init(itemProviderData: data, typeIdentifier: typeIdentifier)
14 | }
15 |
16 | static var readableTypeIdentifiersForItemProvider: [String] {
17 | return [UTType.zip.identifier, UTType.directory.identifier, UTType.data.identifier]
18 | }
19 |
20 | let rawData: Data
21 | init(rawData: Data) {
22 | self.rawData = rawData
23 | }
24 |
25 | required convenience init(itemProviderData data: Data, typeIdentifier: String) throws {
26 | guard let data = NSData(data: data) as Data? else {
27 | throw NSError(domain: "AnimationData", code: -1, userInfo: [NSLocalizedDescriptionKey: "数据错误"])
28 | }
29 | self.init(rawData: data)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Data/BgImageType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BgImageType.swift
3 | // AnimationPreviewer
4 | //
5 | // Created by aa on 2024/11/29.
6 | //
7 |
8 | import UIKit
9 |
10 | enum BgImageType: Int {
11 | case null = 0
12 | case builtIn1 = 1
13 | case builtIn2 = 2
14 | case custom = 3
15 |
16 | static var customBgImageDataPath: String { File.cacheFilePath("jp_bgImageData") }
17 |
18 | static func removeCustomBgImageData() {
19 | File.manager.deleteFile(customBgImageDataPath)
20 | }
21 |
22 | static func cacheCustomBgImageData(_ data: Data) -> Bool {
23 | do {
24 | try data.write(to: URL(fileURLWithPath: customBgImageDataPath))
25 | return true
26 | } catch {
27 | return false
28 | }
29 | }
30 |
31 | var bgImage: UIImage? {
32 | switch self {
33 | case .null:
34 | return nil
35 | case .builtIn1:
36 | return UIImage(contentsOfFile: Bundle.jp.resourcePath(withName: "background1", type: "jpg"))
37 | case .builtIn2:
38 | return UIImage(contentsOfFile: Bundle.jp.resourcePath(withName: "background2", type: "jpg"))
39 | case .custom:
40 | return UIImage(contentsOfFile: Self.customBgImageDataPath)
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | UIApplicationSceneManifest
6 |
7 | UIApplicationSupportsMultipleScenes
8 |
9 | UISceneConfigurations
10 |
11 | UIWindowSceneSessionRoleApplication
12 |
13 |
14 | UISceneConfigurationName
15 | Default Configuration
16 | UISceneDelegateClassName
17 | $(PRODUCT_MODULE_NAME).SceneDelegate
18 | UISceneStoryboardFile
19 | Main
20 |
21 |
22 |
23 |
24 | UISupportsDocumentBrowser
25 |
26 | LSSupportsOpeningDocumentsInPlace
27 |
28 | UIFileSharingEnabled
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/AnimationPreviewer/MacChannel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MacChannel.swift
3 | // AnimationPreviewer
4 | //
5 | // Created by 周健平 on 2023/5/9.
6 | //
7 |
8 | enum MacChannel {
9 | static var channel: Channel?
10 |
11 | static func shared() -> Channel {
12 | if let channel = channel {
13 | return channel
14 | }
15 |
16 | let bundleFileName = "MacPlugin.bundle"
17 | let bundleURL = Bundle.main.builtInPlugInsURL!.appendingPathComponent(bundleFileName)
18 |
19 | let bundle = Bundle(url: bundleURL)!
20 |
21 | let className = "MacPlugin.MacPlugin"
22 | let ChannelCls = bundle.classNamed(className) as! Channel.Type
23 | let channel = ChannelCls.init()
24 |
25 | self.channel = channel
26 | return channel
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Neves/Extension/Bundle+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Bundle.Extension.swift
3 | // Neves_Example
4 | //
5 | // Created by 周健平 on 2020/10/9.
6 | // Copyright © 2020 CocoaPods. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension Bundle {
12 | // 参考 Alamofire
13 | var executable: String {
14 | (infoDictionary?[kCFBundleExecutableKey as String] as? String) ??
15 | (ProcessInfo.processInfo.arguments.first?.split(separator: "/").last.map(String.init)) ??
16 | "Unknown"
17 | }
18 |
19 | var bundle: String { infoDictionary?[kCFBundleIdentifierKey as String] as? String ?? "Unknown" }
20 |
21 | var appVersion: String { infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown" }
22 |
23 | var appBuild: String { infoDictionary?[kCFBundleVersionKey as String] as? String ?? "Unknown" }
24 |
25 | var appName: String { infoDictionary?[kCFBundleNameKey as String] as? String ?? "Unknown" }
26 |
27 | var osNameVersion: String {
28 | let version = ProcessInfo.processInfo.operatingSystemVersion
29 | let versionString = "\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)"
30 | let osName: String = {
31 | #if os(iOS)
32 | return "iOS"
33 | #elseif os(watchOS)
34 | return "watchOS"
35 | #elseif os(tvOS)
36 | return "tvOS"
37 | #elseif os(macOS)
38 | return "macOS"
39 | #elseif os(Linux)
40 | return "Linux"
41 | #elseif os(Windows)
42 | return "Windows"
43 | #else
44 | return "Unknown"
45 | #endif
46 | }()
47 | return "\(osName) \(versionString)"
48 | }
49 | }
50 |
51 | extension Bundle: JPCompatible {}
52 | extension JP where Base: Bundle {
53 | static func executable() -> String {
54 | Base.main.executable
55 | }
56 |
57 | static func resourcePath(withName name: String, type: String? = nil) -> String {
58 | guard let path = Base.main.path(forResource: name, ofType: type) else { fatalError("路径不存在") }
59 | return path
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Neves/Extension/Data+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Data+.swift
3 | // AnimationPreviewer
4 | //
5 | // Created by aa on 2023/8/24.
6 | //
7 |
8 | import Foundation
9 |
10 | private let zipMagicNumber: [UInt8] = [0x50, 0x4B, 0x03, 0x04] // "PK\x03\x04"
11 | private let gifIdentifier = Data([0x47, 0x49, 0x46])
12 |
13 | extension Data: JPCompatible {}
14 | extension JP where Base == Data {
15 | var isZip: Bool {
16 | guard base.count >= zipMagicNumber.count else {
17 | return false
18 | }
19 | let magicNumberBytes = base.prefix(zipMagicNumber.count)
20 | return magicNumberBytes.elementsEqual(zipMagicNumber)
21 | }
22 |
23 | var isGIF: Bool {
24 | guard base.count >= gifIdentifier.count else {
25 | return false
26 | }
27 |
28 | let prefix = base.prefix(gifIdentifier.count)
29 | return prefix.elementsEqual(gifIdentifier)
30 | }
31 |
32 | var isJSON: Bool {
33 | do {
34 | _ = try JSONSerialization.jsonObject(with: base, options: [])
35 | return true
36 | } catch {
37 | return false
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Neves/Extension/UIImage+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+.swift
3 | // AnimationPreviewer
4 | //
5 | // Created by aa on 2025/4/12.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIImage {
11 | /// 透明格子图片
12 | static let transparentGrid: UIImage = {
13 | let size = CGSize(width: 20, height: 20)
14 | let gridWH = size.width * 0.5
15 |
16 | // UIGraphicsBeginImageContextWithOptions(size, false, 0)
17 | // // 获取绘图上下文
18 | // guard let context = UIGraphicsGetCurrentContext() else { return UIImage() }
19 | //
20 | // // 背景颜色
21 | // UIColor(white: 1, alpha: 0.9).setFill()
22 | // context.fill(CGRect(origin: .zero, size: size))
23 | //
24 | // // 小方块颜色
25 | // UIColor(white: 0.75, alpha: 0.9).setFill()
26 | // context.fill(CGRect(x: 0, y: 0, width: gridWH, height: gridWH))
27 | // context.fill(CGRect(x: gridWH, y: gridWH, width: gridWH, height: gridWH))
28 | //
29 | // let image = UIGraphicsGetImageFromCurrentImageContext()
30 | // UIGraphicsEndImageContext()
31 | //
32 | // return image ?? UIImage()
33 |
34 | /// ⚡️性能提升:
35 | /// 相对于`UIGraphicsBeginImageContextWithOptions`,`UIGraphicsImageRenderer`是更推荐的方式,
36 | /// 尤其是在需要高效生成图像时。
37 |
38 | let rendererFormat = UIGraphicsImageRendererFormat()
39 | rendererFormat.scale = UIScreen.main.scale
40 |
41 | // 使用 renderer 生成图像
42 | let renderer = UIGraphicsImageRenderer(size: size, format: rendererFormat)
43 | return renderer.image { context in
44 | // 获取绘图上下文
45 | let ctx = context.cgContext
46 |
47 | // 背景填充
48 | UIColor(white: 1, alpha: 0.9).setFill()
49 | ctx.fill(CGRect(origin: .zero, size: size))
50 |
51 | // 绘制小格子
52 | UIColor(white: 0.75, alpha: 0.9).setFill()
53 | ctx.fill(CGRect(x: 0, y: 0, width: gridWH, height: gridWH))
54 | ctx.fill(CGRect(x: gridWH, y: gridWH, width: gridWH, height: gridWH))
55 | }
56 | }()
57 | }
58 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Neves/Extension/UIScreen+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIScreen.Extension.swift
3 | // Neves_Example
4 | //
5 | // Created by 周健平 on 2020/10/9.
6 | // Copyright © 2020 CocoaPods. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIScreen {
12 | static var mainScale: CGFloat { main.scale }
13 | static var mainBounds: CGRect { main.bounds }
14 | static var mainSize: CGSize { main.bounds.size }
15 | static var mainWidth: CGFloat { main.bounds.width }
16 | static var mainHeight: CGFloat { main.bounds.height }
17 | }
18 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Neves/Extension/URL+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URL+.swift
3 | // AnimationPreviewer
4 | //
5 | // Created by aa on 2025/4/9.
6 | //
7 |
8 | import Foundation
9 |
10 | extension URL: JPCompatible {}
11 | extension JP where Base == URL {
12 | /// 安全获取路径,支持选择是否保留百分号编码(兼容旧版本)
13 | /// 🌰🌰🌰 `"file:///Users/zhoujianping/My%20Documents/file.txt"`
14 | /// `percentEncoded: false => /Users/zhoujianping/My Documents/file.txt`
15 | /// `percentEncoded: true => /Users/zhoujianping/My%20Documents/file.txt`
16 | func safePath(percentEncoded: Bool = true) -> String {
17 | if #available(iOS 16.0, macOS 13.0, *) {
18 | return base.path(percentEncoded: percentEncoded)
19 | }
20 |
21 | // iOS 15 及以下用 URLComponents 实现
22 | guard percentEncoded, let components = URLComponents(url: base, resolvingAgainstBaseURL: false) else {
23 | return base.path
24 | }
25 |
26 | return components.percentEncodedPath
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Neves/Extension/UserDefaults+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserDefault+.swift
3 | // AnimationPreviewer
4 | //
5 | // Created by aa on 2023/8/30.
6 | //
7 |
8 | import Foundation
9 |
10 | extension UserDefaults {
11 | /// 在这里注册`Key`
12 | enum Key: String, CaseIterable {
13 | case animationType
14 | case isSVGAMute
15 | case bgImageType
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Neves/Protocol/Bindable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Bindable.swift
3 | // Neves
4 | //
5 | // Created by aa on 2021/6/4.
6 | //
7 |
8 | infix operator ~~~
9 |
10 | protocol VBindable: UIView {
11 | associatedtype BindModel: MBindable
12 | var bindModel: BindModel? { set get }
13 | static func ~~~ (_ view: Self, _ model: BindModel?) -> Bool
14 | }
15 |
16 | protocol MBindable: AnyObject {
17 | associatedtype ModelID: Any
18 | associatedtype BindView: VBindable
19 | var identifier: ModelID { get }
20 | var bindView: BindView? { set get }
21 | static func ~~~ (_ model: Self, _ view: BindView?) -> Bool
22 | }
23 |
24 | extension VBindable {
25 | @discardableResult
26 | static func ~~~ (_ view: Self, _ model: BindModel?) -> Bool {
27 | model?.bindView?.bindModel = nil
28 | view.bindModel?.bindView = nil
29 |
30 | guard let bindModel = model,
31 | let bindView = view as? BindModel.BindView else
32 | {
33 | model?.bindView = nil
34 | view.bindModel = nil
35 | return false
36 | }
37 |
38 | bindModel.bindView = bindView
39 | view.bindModel = bindModel
40 | return true
41 | }
42 | }
43 |
44 | extension MBindable {
45 | @discardableResult
46 | static func ~~~ (_ model: Self, _ view: BindView?) -> Bool {
47 | model.bindView?.bindModel = nil
48 | view?.bindModel?.bindView = nil
49 |
50 | guard let bindView = view,
51 | let bindModel = model as? BindView.BindModel else
52 | {
53 | model.bindView = nil
54 | view?.bindModel = nil
55 | return false
56 | }
57 |
58 | model.bindView = bindView
59 | bindView.bindModel = bindModel
60 | return true
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Neves/Protocol/Hookable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Hookable.swift
3 | // Neves
4 | //
5 | // Created by aa on 2023/1/17.
6 | //
7 |
8 | protocol Hookable: NSObject {}
9 | extension Hookable {
10 | static func swizzlingInstanceMethods(_ originalSelector: Selector, _ swizzledSelector: Selector) {
11 | guard let originalMethod = class_getInstanceMethod(self, originalSelector),
12 | let swizzledMethod = class_getInstanceMethod(self, swizzledSelector) else {
13 | return
14 | }
15 | method_exchangeImplementations(originalMethod, swizzledMethod)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Neves/Protocol/JP.swift:
--------------------------------------------------------------------------------
1 | //
2 | // JP.swift
3 | // Neves_Example
4 | //
5 | // Created by 周健平 on 2020/10/9.
6 | // Copyright © 2020 CocoaPods. All rights reserved.
7 | //
8 |
9 | struct JP {
10 | let base: Base
11 | init(_ base: Base) {
12 | self.base = base
13 | }
14 | }
15 |
16 | protocol JPCompatible {}
17 | extension JPCompatible {
18 | static var jp: JP.Type {
19 | set {}
20 | get { JP.self }
21 | }
22 | var jp: JP {
23 | set {}
24 | get { JP(self) }
25 | }
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Neves/Tool/Done.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Done.swift
3 | // Neves
4 | //
5 | // Created by aa on 2021/2/4.
6 | //
7 |
8 | struct Done {
9 | typealias Map = (O) -> T
10 | typealias Complete = (Result) -> ()
11 |
12 | struct Fail {
13 | var error: Error?
14 | var msg: String
15 | var errorMsg: String { error.map { $0.localizedDescription } ?? "" }
16 | /// 错误信息的优先级:高 msg -> localizedDescription -> defaultMsg 低
17 | init(_ error: Error?, msg: String? = nil, _ defaultMsg: @autoclosure () -> String?) {
18 | self.error = error
19 | self.msg = msg ?? error.map { $0.localizedDescription } ?? defaultMsg() ?? ""
20 | }
21 | }
22 |
23 | enum Result {
24 | case success(_ data: T)
25 | case failed(_ fail: Fail?)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Neves/Tool/LottieImage/DecodeImageProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DecodeImageProvider.swift
3 | // Neves
4 | //
5 | // Created by aa on 2021/10/22.
6 | //
7 |
8 | class DecodeImageProvider: AnimationImageProvider {
9 | let images: [String: CGImage]
10 | let replacement: [String: CGImage]?
11 |
12 | init?(imageDirPath: String, imageReplacement: [String: CGImage]? = nil) {
13 | guard File.manager.fileExists(imageDirPath) else {
14 | JPrint("不存在图片文件夹!")
15 | return nil
16 | }
17 |
18 | guard let fileNames = try? FileManager.default.subpathsOfDirectory(atPath: imageDirPath) else {
19 | JPrint("不存在图片!")
20 | return nil
21 | }
22 |
23 | var images: [String: CGImage] = [:]
24 | for fileName in fileNames {
25 | let imagePath = imageDirPath + "/\(fileName)"
26 | guard let image = UIImage(contentsOfFile: imagePath),
27 | let cgImg = image.cgImage else { return nil }
28 | images[fileName] = DecodeImage(cgImg) ?? cgImg
29 | }
30 |
31 | self.images = images
32 | self.replacement = imageReplacement
33 | }
34 |
35 | func imageForAsset(asset: ImageAsset) -> CGImage? {
36 | replacement.map { $0[asset.name] } ?? images[asset.name]
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Neves/Tool/UserDefault.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserDefault.swift
3 | // Neves
4 | //
5 | // Created by aa on 2022/4/21.
6 | // Copyright © 2022 CocoaPods. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | @propertyWrapper
12 | struct UserDefault {
13 | let key: UserDefaults.Key
14 | let id: Int?
15 | let suiteName: String?
16 | let defaultValue: T
17 |
18 | private var userDefaults: UserDefaults {
19 | if let suiteName, let uds = UserDefaults(suiteName: suiteName) {
20 | return uds
21 | }
22 | return UserDefaults.standard
23 | }
24 |
25 | var keyValue: String {
26 | if let id {
27 | return key.rawValue + "_\(id)"
28 | }
29 | return key.rawValue
30 | }
31 |
32 | var wrappedValue: T {
33 | get { userDefaults.object(forKey: keyValue) as? T ?? defaultValue }
34 | set {
35 | userDefaults.set(newValue, forKey: keyValue)
36 | userDefaults.synchronize()
37 | }
38 | }
39 |
40 | /// 该属性能让外部可以用`$外部属性名`的方式访问该属性值
41 | var projectedValue: T? {
42 | userDefaults.object(forKey: keyValue) as? T
43 | }
44 |
45 | init(wrappedValue: T, _ key: UserDefaults.Key, id: Int? = nil, suiteName: String? = nil) {
46 | self.key = key
47 | self.id = id
48 | self.suiteName = suiteName
49 | self.defaultValue = wrappedValue
50 | }
51 | }
52 |
53 |
54 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Neves/Unit/Buttons/Buttons.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Buttons.swift
3 | // Neves
4 | //
5 | // Created by aa on 2022/3/28.
6 | //
7 |
8 | class CustomLayoutButton: UIButton {
9 | var layoutSubviewsHandler: ((CustomLayoutButton) -> ())?
10 | override func layoutSubviews() {
11 | super.layoutSubviews()
12 | layoutSubviewsHandler?(self)
13 | }
14 | }
15 |
16 | class NoHighlightButton: CustomLayoutButton {
17 | override var isHighlighted: Bool {
18 | get { super.isHighlighted }
19 | set {}
20 | }
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/AnimationPreviewer/Neves/Unit/Gradient/GradientView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GradientView.swift
3 | // Neves_Example
4 | //
5 | // Created by aa on 2020/10/14.
6 | // Copyright © 2020 CocoaPods. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class GradientView: UIView {
12 | // MARK: - 重写的父类函数
13 | override class var layerClass: AnyClass {
14 | CAGradientLayer.self
15 | }
16 | }
17 |
18 | // MARK: - Gradientable
19 | extension GradientView: Gradientable {
20 | convenience init(frame: CGRect = .zero,
21 | startPoint: CGPoint = .zero,
22 | endPoint: CGPoint = .zero,
23 | locations: [NSNumber]? = nil,
24 | colors: [UIColor]? = nil) {
25 | self.init(frame: frame)
26 |
27 | self.startPoint(startPoint)
28 | .endPoint(endPoint)
29 | .locations(locations)
30 | .colors(colors)
31 | }
32 |
33 | public var gLayer: CAGradientLayer { layer as! CAGradientLayer }
34 | }
35 |
--------------------------------------------------------------------------------
/AnimationPreviewer/SVGAPlayer_Optimized/SVGAVideoEntity+Extension.h:
--------------------------------------------------------------------------------
1 | //
2 | // SVGAVideoEntity+Extension.h
3 | // SVGAPlayer_OptimizedDemo
4 | //
5 | // Created by aa on 2023/11/20.
6 | //
7 |
8 | #import "SVGAVideoEntity.h"
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | typedef NS_ENUM(NSUInteger, SVGAVideoEntityError) {
13 | /// 木有问题
14 | SVGAVideoEntityError_None = 0,
15 | /// 画面没有尺寸
16 | SVGAVideoEntityError_ZeroVideoSize = 1,
17 | /// FPS为0
18 | SVGAVideoEntityError_ZeroFPS = 2,
19 | /// 帧数为0
20 | SVGAVideoEntityError_ZeroFrames = 3,
21 | };
22 |
23 | @interface SVGAVideoEntity (Extension)
24 |
25 | /// 最小帧数(0)
26 | @property (readonly) NSInteger minFrame;
27 |
28 | /// 最大帧数
29 | @property (readonly) NSInteger maxFrame;
30 |
31 | /// 总时长
32 | @property (readonly) NSTimeInterval duration;
33 |
34 | /// 资源错误
35 | @property (readonly) SVGAVideoEntityError entityError;
36 |
37 | /// 是否带有音频
38 | @property (readonly) BOOL isHasAudio;
39 |
40 | @end
41 |
42 | NS_ASSUME_NONNULL_END
43 |
--------------------------------------------------------------------------------
/AnimationPreviewer/SVGAPlayer_Optimized/SVGAVideoEntity+Extension.m:
--------------------------------------------------------------------------------
1 | //
2 | // SVGAVideoEntity+Extension.m
3 | // SVGAPlayer_OptimizedDemo
4 | //
5 | // Created by aa on 2023/11/20.
6 | //
7 |
8 | #import "SVGAVideoEntity+Extension.h"
9 |
10 | @implementation SVGAVideoEntity (Extension)
11 |
12 | - (NSInteger)minFrame {
13 | return 0;
14 | }
15 |
16 | - (NSInteger)maxFrame {
17 | int frames = self.frames;
18 | return frames > 1 ? (frames - 1) : 0;
19 | }
20 |
21 | - (NSTimeInterval)duration {
22 | int frames = self.frames;
23 | int fps = self.FPS;
24 | if (frames > 0 && fps > 0) {
25 | return (NSTimeInterval)frames / (NSTimeInterval)fps;
26 | }
27 | return 0;
28 | }
29 |
30 | - (SVGAVideoEntityError)entityError {
31 | if (self.videoSize.width <= 0 || self.videoSize.height <= 0) {
32 | return SVGAVideoEntityError_ZeroVideoSize;
33 | }
34 | else if (self.FPS == 0) {
35 | return SVGAVideoEntityError_ZeroFPS;
36 | }
37 | else if (self.frames == 0) {
38 | return SVGAVideoEntityError_ZeroFrames;
39 | }
40 | return SVGAVideoEntityError_None;
41 | }
42 |
43 | - (BOOL)isHasAudio {
44 | return self.audiosData.count > 0 && self.audios.count > 0;
45 | }
46 |
47 | @end
48 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVGAPlayer/SVGA.h:
--------------------------------------------------------------------------------
1 | //
2 | // SVGA.h
3 | // SVGAPlayer
4 | //
5 | // Created by 崔明辉 on 16/6/17.
6 | // Copyright © 2016年 UED Center. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "SVGAParser.h"
11 | #import "SVGAPlayer.h"
12 | #import "SVGAImageView.h"
13 | #import "SVGAVideoEntity.h"
14 | #import "SVGAExporter.h"
15 |
16 | @interface SVGA : NSObject
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVGAPlayer/SVGA.m:
--------------------------------------------------------------------------------
1 | //
2 | // SVGA.m
3 | // SVGAPlayer
4 | //
5 | // Created by 崔明辉 on 16/6/17.
6 | // Copyright © 2016年 UED Center. All rights reserved.
7 | //
8 |
9 | #import "SVGA.h"
10 |
11 | @implementation SVGA
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVGAPlayer/SVGAAudioEntity.h:
--------------------------------------------------------------------------------
1 | //
2 | // SVGAAudioEntity.h
3 | // SVGAPlayer
4 | //
5 | // Created by PonyCui on 2018/10/18.
6 | // Copyright © 2018年 UED Center. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class SVGAProtoAudioEntity;
12 |
13 | @interface SVGAAudioEntity : NSObject
14 |
15 | @property (nonatomic, readonly) NSString *audioKey;
16 | @property (nonatomic, readonly) NSInteger startFrame;
17 | @property (nonatomic, readonly) NSInteger endFrame;
18 | @property (nonatomic, readonly) NSInteger startTime;
19 |
20 | - (instancetype)initWithProtoObject:(SVGAProtoAudioEntity *)protoObject;
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVGAPlayer/SVGAAudioEntity.m:
--------------------------------------------------------------------------------
1 | //
2 | // SVGAAudioEntity.m
3 | // SVGAPlayer
4 | //
5 | // Created by PonyCui on 2018/10/18.
6 | // Copyright © 2018年 UED Center. All rights reserved.
7 | //
8 |
9 | #import "SVGAAudioEntity.h"
10 | #import "Svga.pbobjc.h"
11 |
12 | @interface SVGAAudioEntity ()
13 |
14 | @property (nonatomic, readwrite) NSString *audioKey;
15 | @property (nonatomic, readwrite) NSInteger startFrame;
16 | @property (nonatomic, readwrite) NSInteger endFrame;
17 | @property (nonatomic, readwrite) NSInteger startTime;
18 |
19 | @end
20 |
21 | @implementation SVGAAudioEntity
22 |
23 | - (instancetype)initWithProtoObject:(SVGAProtoAudioEntity *)protoObject {
24 | self = [super init];
25 | if (self) {
26 | _audioKey = protoObject.audioKey;
27 | _startFrame = protoObject.startFrame;
28 | _endFrame = protoObject.endFrame;
29 | _startTime = protoObject.startTime;
30 | }
31 | return self;
32 | }
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVGAPlayer/SVGAAudioLayer.h:
--------------------------------------------------------------------------------
1 | //
2 | // SVGAAudioLayer.h
3 | // SVGAPlayer
4 | //
5 | // Created by PonyCui on 2018/10/18.
6 | // Copyright © 2018年 UED Center. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @class SVGAAudioEntity, SVGAVideoEntity;
13 |
14 | @interface SVGAAudioLayer : NSObject
15 |
16 | @property (nonatomic, readonly) AVAudioPlayer *audioPlayer;
17 | @property (nonatomic, readonly) SVGAAudioEntity *audioItem;
18 | @property (nonatomic, assign) BOOL audioPlaying;
19 |
20 |
21 | - (instancetype)initWithAudioItem:(SVGAAudioEntity *)audioItem videoItem:(SVGAVideoEntity *)videoItem;
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVGAPlayer/SVGAAudioLayer.m:
--------------------------------------------------------------------------------
1 | //
2 | // SVGAAudioLayer.m
3 | // SVGAPlayer
4 | //
5 | // Created by PonyCui on 2018/10/18.
6 | // Copyright © 2018年 UED Center. All rights reserved.
7 | //
8 |
9 | #import "SVGAAudioLayer.h"
10 | #import "SVGAAudioEntity.h"
11 | #import "SVGAVideoEntity.h"
12 |
13 | @interface SVGAAudioLayer ()
14 |
15 | @property (nonatomic, readwrite) AVAudioPlayer *audioPlayer;
16 | @property (nonatomic, readwrite) SVGAAudioEntity *audioItem;
17 |
18 | @end
19 |
20 | @implementation SVGAAudioLayer
21 |
22 | - (instancetype)initWithAudioItem:(SVGAAudioEntity *)audioItem videoItem:(SVGAVideoEntity *)videoItem
23 | {
24 | self = [super init];
25 | if (self) {
26 | _audioItem = audioItem;
27 | if (audioItem.audioKey != nil && videoItem.audiosData[audioItem.audioKey] != nil) {
28 | _audioPlayer = [[AVAudioPlayer alloc] initWithData:videoItem.audiosData[audioItem.audioKey]
29 | fileTypeHint:@"mp3"
30 | error:NULL];
31 | [_audioPlayer prepareToPlay];
32 | }
33 | }
34 | return self;
35 | }
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVGAPlayer/SVGABezierPath.h:
--------------------------------------------------------------------------------
1 | //
2 | // SVGABezierPath.h
3 | // SVGAPlayer
4 | //
5 | // Created by 崔明辉 on 16/6/28.
6 | // Copyright © 2016年 UED Center. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface SVGABezierPath : UIBezierPath
13 |
14 | - (void)setValues:(nonnull NSString *)values;
15 |
16 | - (nonnull CAShapeLayer *)createLayer;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVGAPlayer/SVGABitmapLayer.h:
--------------------------------------------------------------------------------
1 | //
2 | // SVGABitmapLayer.h
3 | // SVGAPlayer
4 | //
5 | // Created by 崔明辉 on 2017/2/20.
6 | // Copyright © 2017年 UED Center. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class SVGAVideoSpriteFrameEntity;
12 |
13 | @interface SVGABitmapLayer : CALayer
14 |
15 | - (instancetype)initWithFrames:(NSArray *)frames;
16 |
17 | - (void)stepToFrame:(NSInteger)frame;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVGAPlayer/SVGABitmapLayer.m:
--------------------------------------------------------------------------------
1 | //
2 | // SVGABitmapLayer.m
3 | // SVGAPlayer
4 | //
5 | // Created by 崔明辉 on 2017/2/20.
6 | // Copyright © 2017年 UED Center. All rights reserved.
7 | //
8 |
9 | #import "SVGABitmapLayer.h"
10 | #import "SVGABezierPath.h"
11 | #import "SVGAVideoSpriteFrameEntity.h"
12 |
13 | @interface SVGABitmapLayer ()
14 |
15 | @property (nonatomic, strong) NSArray *frames;
16 | @property (nonatomic, assign) NSInteger drawedFrame;
17 |
18 | @end
19 |
20 | @implementation SVGABitmapLayer
21 |
22 | - (instancetype)initWithFrames:(NSArray *)frames {
23 | self = [super init];
24 | if (self) {
25 | self.backgroundColor = [UIColor clearColor].CGColor;
26 | self.masksToBounds = NO;
27 | self.contentsGravity = kCAGravityResizeAspect;
28 | _frames = frames;
29 | [self stepToFrame:0];
30 | }
31 | return self;
32 | }
33 |
34 | - (void)stepToFrame:(NSInteger)frame {
35 | }
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVGAPlayer/SVGAContentLayer.h:
--------------------------------------------------------------------------------
1 | //
2 | // SVGAContentLayer.h
3 | // SVGAPlayer
4 | //
5 | // Created by 崔明辉 on 2017/2/22.
6 | // Copyright © 2017年 UED Center. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "SVGAPlayer.h"
11 |
12 | @class SVGABitmapLayer, SVGAVectorLayer, SVGAVideoSpriteFrameEntity;
13 |
14 | @interface SVGAContentLayer : CALayer
15 |
16 | @property (nonatomic, strong) NSString *imageKey;
17 | @property (nonatomic, assign) BOOL dynamicHidden;
18 | @property (nonatomic, copy) SVGAPlayerDynamicDrawingBlock dynamicDrawingBlock;
19 | @property (nonatomic, strong) SVGABitmapLayer *bitmapLayer;
20 | @property (nonatomic, strong) SVGAVectorLayer *vectorLayer;
21 | @property (nonatomic, strong) CATextLayer *textLayer;
22 |
23 | - (instancetype)initWithFrames:(NSArray *)frames;
24 |
25 | - (void)stepToFrame:(NSInteger)frame;
26 | - (void)resetTextLayerProperties:(NSAttributedString *)attributedString;
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVGAPlayer/SVGAExporter.h:
--------------------------------------------------------------------------------
1 | //
2 | // SVGAExporter.h
3 | // SVGAPlayer
4 | //
5 | // Created by 崔明辉 on 2017/3/7.
6 | // Copyright © 2017年 UED Center. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class SVGAVideoEntity;
12 |
13 | @interface SVGAExporter : NSObject
14 |
15 | @property (nonatomic, strong) SVGAVideoEntity *videoItem;
16 |
17 | - (NSArray *)toImages;
18 |
19 | - (void)saveImages:(NSString *)toPath filePrefix:(NSString *)filePrefix;
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVGAPlayer/SVGAImageView.h:
--------------------------------------------------------------------------------
1 | //
2 | // SVGAImageView.h
3 | // SVGAPlayer
4 | //
5 | // Created by 崔明辉 on 2017/10/17.
6 | // Copyright © 2017年 UED Center. All rights reserved.
7 | //
8 |
9 | #import "SVGAPlayer.h"
10 |
11 | @interface SVGAImageView : SVGAPlayer
12 |
13 | @property (nonatomic, assign) IBInspectable BOOL autoPlay;
14 | @property (nonatomic, strong) IBInspectable NSString *imageName;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVGAPlayer/SVGAImageView.m:
--------------------------------------------------------------------------------
1 | //
2 | // SVGAImageView.m
3 | // SVGAPlayer
4 | //
5 | // Created by 崔明辉 on 2017/10/17.
6 | // Copyright © 2017年 UED Center. All rights reserved.
7 | //
8 |
9 | #import "SVGAImageView.h"
10 | #import "SVGAParser.h"
11 |
12 | static SVGAParser *sharedParser;
13 |
14 | @implementation SVGAImageView
15 |
16 | + (void)load {
17 | sharedParser = [SVGAParser new];
18 | }
19 |
20 | - (instancetype)initWithCoder:(NSCoder *)coder
21 | {
22 | self = [super initWithCoder:coder];
23 | if (self) {
24 | _autoPlay = YES;
25 | }
26 | return self;
27 | }
28 |
29 | - (void)setImageName:(NSString *)imageName {
30 | _imageName = imageName;
31 | if ([imageName hasPrefix:@"http://"] || [imageName hasPrefix:@"https://"]) {
32 | [sharedParser parseWithURL:[NSURL URLWithString:imageName] completionBlock:^(SVGAVideoEntity * _Nullable videoItem) {
33 | [self setVideoItem:videoItem];
34 | if (self.autoPlay) {
35 | [self startAnimation];
36 | }
37 | } failureBlock:nil];
38 | }
39 | else {
40 | [sharedParser parseWithNamed:imageName inBundle:nil completionBlock:^(SVGAVideoEntity * _Nonnull videoItem) {
41 | [self setVideoItem:videoItem];
42 | if (self.autoPlay) {
43 | [self startAnimation];
44 | }
45 | } failureBlock:nil];
46 | }
47 | }
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVGAPlayer/SVGAParser.h:
--------------------------------------------------------------------------------
1 | //
2 | // SVGAParser.h
3 | // SVGAPlayer
4 | //
5 | // Created by 崔明辉 on 16/6/17.
6 | // Copyright © 2016年 UED Center. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class SVGAVideoEntity;
12 |
13 | @interface SVGAParser : NSObject
14 |
15 | @property (nonatomic, assign) BOOL enabledMemoryCache;
16 |
17 | - (void)parseWithURL:(nonnull NSURL *)URL
18 | completionBlock:(void ( ^ _Nonnull )(SVGAVideoEntity * _Nullable videoItem))completionBlock
19 | failureBlock:(void ( ^ _Nullable)(NSError * _Nullable error))failureBlock;
20 |
21 | - (void)parseWithURLRequest:(nonnull NSURLRequest *)URLRequest
22 | completionBlock:(void ( ^ _Nonnull )(SVGAVideoEntity * _Nullable videoItem))completionBlock
23 | failureBlock:(void ( ^ _Nullable)(NSError * _Nullable error))failureBlock;
24 |
25 | - (void)parseWithData:(nonnull NSData *)data
26 | cacheKey:(nonnull NSString *)cacheKey
27 | completionBlock:(void ( ^ _Nullable)(SVGAVideoEntity * _Nonnull videoItem))completionBlock
28 | failureBlock:(void ( ^ _Nullable)(NSError * _Nonnull error))failureBlock;
29 |
30 | - (void)parseWithNamed:(nonnull NSString *)named
31 | inBundle:(nullable NSBundle *)inBundle
32 | completionBlock:(void ( ^ _Nullable)(SVGAVideoEntity * _Nonnull videoItem))completionBlock
33 | failureBlock:(void ( ^ _Nullable)(NSError * _Nonnull error))failureBlock;
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVGAPlayer/SVGAVectorLayer.h:
--------------------------------------------------------------------------------
1 | //
2 | // SVGAVectorLayer.h
3 | // SVGAPlayer
4 | //
5 | // Created by 崔明辉 on 2017/2/20.
6 | // Copyright © 2017年 UED Center. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class SVGAVideoSpriteFrameEntity;
12 |
13 | @interface SVGAVectorLayer : CALayer
14 |
15 | - (instancetype)initWithFrames:(NSArray *)frames;
16 |
17 | - (void)stepToFrame:(NSInteger)frame;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVGAPlayer/SVGAVideoEntity.h:
--------------------------------------------------------------------------------
1 | //
2 | // SVGAVideoEntity.h
3 | // SVGAPlayer
4 | //
5 | // Created by 崔明辉 on 16/6/17.
6 | // Copyright © 2016年 UED Center. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import "SVGAAudioEntity.h"
12 |
13 | @class SVGAVideoEntity, SVGAVideoSpriteEntity, SVGAVideoSpriteFrameEntity, SVGABitmapLayer, SVGAVectorLayer;
14 | @class SVGAProtoMovieEntity;
15 |
16 | @interface SVGAVideoEntity : NSObject
17 |
18 | @property (nonatomic, readonly) CGSize videoSize;
19 | @property (nonatomic, readonly) int FPS;
20 | @property (nonatomic, readonly) int frames;
21 | @property (nonatomic, readonly) NSDictionary *images;
22 | @property (nonatomic, readonly) NSDictionary *audiosData;
23 | @property (nonatomic, readonly) NSArray *sprites;
24 | @property (nonatomic, readonly) NSArray *audios;
25 |
26 | - (instancetype)initWithJSONObject:(NSDictionary *)JSONObject cacheDir:(NSString *)cacheDir;
27 | - (void)resetImagesWithJSONObject:(NSDictionary *)JSONObject;
28 | - (void)resetSpritesWithJSONObject:(NSDictionary *)JSONObject;
29 |
30 | - (instancetype)initWithProtoObject:(SVGAProtoMovieEntity *)protoObject cacheDir:(NSString *)cacheDir;
31 | - (void)resetImagesWithProtoObject:(SVGAProtoMovieEntity *)protoObject;
32 | - (void)resetSpritesWithProtoObject:(SVGAProtoMovieEntity *)protoObject;
33 | - (void)resetAudiosWithProtoObject:(SVGAProtoMovieEntity *)protoObject;
34 |
35 | + (SVGAVideoEntity *)readCache:(NSString *)cacheKey;
36 | // NSCache缓存
37 | - (void)saveCache:(NSString *)cacheKey;
38 | // NSMapTable弱缓存
39 | - (void)saveWeakCache:(NSString *)cacheKey;
40 | @end
41 |
42 |
43 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVGAPlayer/SVGAVideoSpriteEntity.h:
--------------------------------------------------------------------------------
1 | //
2 | // SVGAVideoSpriteEntity.h
3 | // SVGAPlayer
4 | //
5 | // Created by 崔明辉 on 2017/2/20.
6 | // Copyright © 2017年 UED Center. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @class SVGAVideoSpriteFrameEntity, SVGAContentLayer;
13 | @class SVGAProtoSpriteEntity;
14 |
15 | @interface SVGAVideoSpriteEntity : NSObject
16 |
17 | @property (nonatomic, readonly) NSString *imageKey;
18 | @property (nonatomic, readonly) NSArray *frames;
19 | @property (nonatomic, readonly) NSString *matteKey;
20 |
21 | - (instancetype)initWithJSONObject:(NSDictionary *)JSONObject;
22 | - (instancetype)initWithProtoObject:(SVGAProtoSpriteEntity *)protoObject;
23 |
24 | - (SVGAContentLayer *)requestLayerWithBitmap:(UIImage *)bitmap;
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVGAPlayer/SVGAVideoSpriteFrameEntity.h:
--------------------------------------------------------------------------------
1 | //
2 | // SVGAVideoSpriteFrameEntity.h
3 | // SVGAPlayer
4 | //
5 | // Created by 崔明辉 on 2017/2/20.
6 | // Copyright © 2017年 UED Center. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @class SVGAVectorLayer;
13 | @class SVGAProtoFrameEntity;
14 |
15 | @interface SVGAVideoSpriteFrameEntity : NSObject
16 |
17 | @property (nonatomic, readonly) CGFloat alpha;
18 | @property (nonatomic, readonly) CGAffineTransform transform;
19 | @property (nonatomic, readonly) CGRect layout;
20 | @property (nonatomic, readonly) CGFloat nx;
21 | @property (nonatomic, readonly) CGFloat ny;
22 | @property (nonatomic, readonly) CALayer *maskLayer;
23 | @property (nonatomic, readonly) NSArray *shapes;
24 |
25 | - (instancetype)initWithJSONObject:(NSDictionary *)JSONObject;
26 | - (instancetype)initWithProtoObject:(SVGAProtoFrameEntity *)protoObject;
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVProgressHUD/SVIndefiniteAnimatedView.h:
--------------------------------------------------------------------------------
1 | //
2 | // SVIndefiniteAnimatedView.h
3 | // SVProgressHUD, https://github.com/SVProgressHUD/SVProgressHUD
4 | //
5 | // Copyright (c) 2014-2018 Guillaume Campagna. All rights reserved.
6 | //
7 |
8 | #import
9 |
10 | @interface SVIndefiniteAnimatedView : UIView
11 |
12 | @property (nonatomic, assign) CGFloat strokeThickness;
13 | @property (nonatomic, assign) CGFloat radius;
14 | @property (nonatomic, strong) UIColor *strokeColor;
15 |
16 | @end
17 |
18 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressAnimatedView.h:
--------------------------------------------------------------------------------
1 | //
2 | // SVProgressAnimatedView.h
3 | // SVProgressHUD, https://github.com/SVProgressHUD/SVProgressHUD
4 | //
5 | // Copyright (c) 2017-2018 Tobias Tiemerding. All rights reserved.
6 | //
7 |
8 | #import
9 |
10 | @interface SVProgressAnimatedView : UIView
11 |
12 | @property (nonatomic, assign) CGFloat radius;
13 | @property (nonatomic, assign) CGFloat strokeThickness;
14 | @property (nonatomic, strong) UIColor *strokeColor;
15 | @property (nonatomic, assign) CGFloat strokeEnd;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressHUD.bundle/angle-mask.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressHUD.bundle/angle-mask.png
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressHUD.bundle/angle-mask@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressHUD.bundle/angle-mask@2x.png
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressHUD.bundle/angle-mask@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressHUD.bundle/angle-mask@3x.png
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressHUD.bundle/error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressHUD.bundle/error.png
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressHUD.bundle/error@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressHUD.bundle/error@2x.png
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressHUD.bundle/error@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressHUD.bundle/error@3x.png
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressHUD.bundle/info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressHUD.bundle/info.png
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressHUD.bundle/info@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressHUD.bundle/info@2x.png
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressHUD.bundle/info@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressHUD.bundle/info@3x.png
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressHUD.bundle/success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressHUD.bundle/success.png
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressHUD.bundle/success@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressHUD.bundle/success@2x.png
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressHUD.bundle/success@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/ThirdLib/SVProgressHUD/SVProgressHUD.bundle/success@3x.png
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVProgressHUD/SVRadialGradientLayer.h:
--------------------------------------------------------------------------------
1 | //
2 | // SVRadialGradientLayer.h
3 | // SVProgressHUD, https://github.com/SVProgressHUD/SVProgressHUD
4 | //
5 | // Copyright (c) 2014-2018 Tobias Tiemerding. All rights reserved.
6 | //
7 |
8 | #import
9 |
10 | @interface SVRadialGradientLayer : CALayer
11 |
12 | @property (nonatomic) CGPoint gradientCenter;
13 |
14 | @end
15 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/SVProgressHUD/SVRadialGradientLayer.m:
--------------------------------------------------------------------------------
1 | //
2 | // SVRadialGradientLayer.m
3 | // SVProgressHUD, https://github.com/SVProgressHUD/SVProgressHUD
4 | //
5 | // Copyright (c) 2014-2018 Tobias Tiemerding. All rights reserved.
6 | //
7 |
8 | #import "SVRadialGradientLayer.h"
9 |
10 | @implementation SVRadialGradientLayer
11 |
12 | - (void)drawInContext:(CGContextRef)context {
13 | size_t locationsCount = 2;
14 | CGFloat locations[2] = {0.0f, 1.0f};
15 | CGFloat colors[8] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.75f};
16 | CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
17 | CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, colors, locations, locationsCount);
18 | CGColorSpaceRelease(colorSpace);
19 |
20 | float radius = MIN(self.bounds.size.width , self.bounds.size.height);
21 | CGContextDrawRadialGradient (context, gradient, self.gradientCenter, 0, self.gradientCenter, radius, kCGGradientDrawsAfterEndLocation);
22 | CGGradientRelease(gradient);
23 | }
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/CoreAnimation/Animations/CustomPathAnimation.swift:
--------------------------------------------------------------------------------
1 | // Created by Cal Stephens on 12/21/21.
2 | // Copyright © 2021 Airbnb Inc. All rights reserved.
3 |
4 | import QuartzCore
5 |
6 | extension CAShapeLayer {
7 | /// Adds animations for the given `BezierPath` keyframes to this `CALayer`
8 | @nonobjc
9 | func addAnimations(
10 | for customPath: KeyframeGroup,
11 | context: LayerAnimationContext,
12 | pathMultiplier: PathMultiplier = 1,
13 | transformPath: (CGPath) -> CGPath = { $0 })
14 | throws
15 | {
16 | try addAnimation(
17 | for: .path,
18 | keyframes: customPath.keyframes,
19 | value: { pathKeyframe in
20 | transformPath(pathKeyframe.cgPath().duplicated(times: pathMultiplier))
21 | },
22 | context: context)
23 | }
24 | }
25 |
26 | extension CGPath {
27 | /// Duplicates this `CGPath` so that it is repeated the given number of times
28 | func duplicated(times: Int) -> CGPath {
29 | if times <= 1 {
30 | return self
31 | }
32 |
33 | let cgPath = CGMutablePath()
34 |
35 | for _ in 0.. KeyframeGroup {
39 | let combinedKeyframes = Keyframes.combinedIfPossible(
40 | size, position,
41 | makeCombinedResult: Ellipse.Keyframe.init)
42 |
43 | if let combinedKeyframes = combinedKeyframes {
44 | return combinedKeyframes
45 | } else {
46 | // If we weren't able to combine all of the keyframes, we have to take the timing values
47 | // from one property and use a fixed value for the other properties.
48 | return try size.map { sizeValue in
49 | Keyframe(
50 | size: sizeValue,
51 | position: try position.exactlyOneKeyframe(context: context, description: "ellipse position"))
52 | }
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/CoreAnimation/Animations/OpacityAnimation.swift:
--------------------------------------------------------------------------------
1 | // Created by Cal Stephens on 5/17/22.
2 | // Copyright © 2022 Airbnb Inc. All rights reserved.
3 |
4 | import QuartzCore
5 |
6 | // MARK: - OpacityAnimationModel
7 |
8 | protocol OpacityAnimationModel {
9 | /// The opacity animation to apply to a `CALayer`
10 | var opacity: KeyframeGroup { get }
11 | }
12 |
13 | // MARK: - Transform + OpacityAnimationModel
14 |
15 | extension Transform: OpacityAnimationModel { }
16 |
17 | // MARK: - ShapeTransform + OpacityAnimationModel
18 |
19 | extension ShapeTransform: OpacityAnimationModel { }
20 |
21 | // MARK: - Fill + OpacityAnimationModel
22 |
23 | extension Fill: OpacityAnimationModel { }
24 |
25 | // MARK: - GradientFill + OpacityAnimationModel
26 |
27 | extension GradientFill: OpacityAnimationModel { }
28 |
29 | // MARK: - Stroke + OpacityAnimationModel
30 |
31 | extension Stroke: OpacityAnimationModel { }
32 |
33 | // MARK: - GradientStroke + OpacityAnimationModel
34 |
35 | extension GradientStroke: OpacityAnimationModel { }
36 |
37 | extension CALayer {
38 | /// Adds the opacity animation from the given `OpacityAnimationModel` to this layer
39 | @nonobjc
40 | func addOpacityAnimation(for opacity: OpacityAnimationModel, context: LayerAnimationContext) throws {
41 | try addAnimation(
42 | for: .opacity,
43 | keyframes: opacity.opacity.keyframes,
44 | value: {
45 | // Lottie animation files express opacity as a numerical percentage value
46 | // (e.g. 0%, 50%, 100%) so we divide by 100 to get the decimal values
47 | // expected by Core Animation (e.g. 0.0, 0.5, 1.0).
48 | $0.cgFloatValue / 100
49 | },
50 | context: context)
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/CoreAnimation/Animations/VisibilityAnimation.swift:
--------------------------------------------------------------------------------
1 | // Created by Cal Stephens on 12/21/21.
2 | // Copyright © 2021 Airbnb Inc. All rights reserved.
3 |
4 | import QuartzCore
5 |
6 | extension CALayer {
7 | /// Adds an animation for the given `inTime` and `outTime` to this `CALayer`
8 | @nonobjc
9 | func addVisibilityAnimation(
10 | inFrame: AnimationFrameTime,
11 | outFrame: AnimationFrameTime,
12 | context: LayerAnimationContext)
13 | {
14 | let animation = CAKeyframeAnimation(keyPath: #keyPath(isHidden))
15 | animation.calculationMode = .discrete
16 |
17 | animation.values = [
18 | true, // hidden, before `inFrame`
19 | false, // visible
20 | true, // hidden, after `outFrame`
21 | ]
22 |
23 | // From the documentation of `keyTimes`:
24 | // - If the calculationMode is set to discrete, the first value in the array
25 | // must be 0.0 and the last value must be 1.0. The array should have one more
26 | // entry than appears in the values array. For example, if there are two values,
27 | // there should be three key times.
28 | animation.keyTimes = [
29 | NSNumber(value: 0.0),
30 | NSNumber(value: max(Double(context.progressTime(for: inFrame)), 0)),
31 | NSNumber(value: min(Double(context.progressTime(for: outFrame)), 1)),
32 | NSNumber(value: 1.0),
33 | ]
34 |
35 | add(animation, timedWith: context)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/CoreAnimation/Extensions/CALayer+fillBounds.swift:
--------------------------------------------------------------------------------
1 | // Created by Cal Stephens on 12/15/21.
2 | // Copyright © 2021 Airbnb Inc. All rights reserved.
3 |
4 | import QuartzCore
5 |
6 | // MARK: - CALayer + fillBoundsOfSuperlayer
7 |
8 | extension CALayer {
9 | /// Updates the `bounds` of this layer to fill the bounds of its `superlayer`
10 | /// without setting `frame` (which is not permitted if the layer can rotate)
11 | @nonobjc
12 | func fillBoundsOfSuperlayer() {
13 | guard let superlayer = superlayer else { return }
14 |
15 | if let customLayerLayer = self as? CustomLayoutLayer {
16 | customLayerLayer.layout(superlayerBounds: superlayer.bounds)
17 | }
18 |
19 | else {
20 | // By default the `anchorPoint` of a layer is `CGPoint(x: 0.5, y: 0.5)`.
21 | // Setting it to `.zero` makes the layer have the same coordinate space
22 | // as its superlayer, which lets use use `superlayer.bounds` directly.
23 | anchorPoint = .zero
24 |
25 | bounds = superlayer.bounds
26 | }
27 | }
28 | }
29 |
30 | // MARK: - CustomLayoutLayer
31 |
32 | /// A `CALayer` that sets a custom `bounds` and `anchorPoint` relative to its superlayer
33 | protocol CustomLayoutLayer: CALayer {
34 | func layout(superlayerBounds: CGRect)
35 | }
36 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/CoreAnimation/Extensions/KeyframeGroup+exactlyOneKeyframe.swift:
--------------------------------------------------------------------------------
1 | // Created by Cal Stephens on 1/11/22.
2 | // Copyright © 2022 Airbnb Inc. All rights reserved.
3 |
4 | // MARK: - KeyframeGroup + exactlyOneKeyframe
5 |
6 | extension KeyframeGroup {
7 | /// Retrieves the first `Keyframe` from this group,
8 | /// and asserts that there are not any extra keyframes that would be ignored
9 | ///
10 | /// - There are several places in Lottie animation definitions where multiple
11 | /// sets of keyframe timings can be provided for properties that have to
12 | /// be applied to a single `CALayer` property (for example, the definition for a
13 | /// `Rectangle` technically lets you animate `size`, `position`, and `cornerRadius`
14 | /// separately, but these all have to be combined into a single `CAKeyframeAnimation`
15 | /// on the `CAShapeLayer.path` property.
16 | ///
17 | /// - In those sorts of cases, we currently choose one one `KeyframeGroup` to provide the
18 | /// timing information, and disallow simultaneous animations on the other properties.
19 | ///
20 | func exactlyOneKeyframe(
21 | context: CompatibilityTrackerProviding,
22 | description: String,
23 | fileID _: StaticString = #fileID,
24 | line _: UInt = #line)
25 | throws
26 | -> T
27 | {
28 | try context.compatibilityAssert(
29 | keyframes.count == 1,
30 | """
31 | The Core Animation rendering engine does not support animating multiple keyframes
32 | for \(description) values (due to limitations of Core Animation `CAKeyframeAnimation`s).
33 | """)
34 |
35 | return keyframes[0].value
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/CoreAnimation/Layers/BaseAnimationLayer.swift:
--------------------------------------------------------------------------------
1 | // Created by Cal Stephens on 1/27/22.
2 | // Copyright © 2022 Airbnb Inc. All rights reserved.
3 |
4 | import QuartzCore
5 |
6 | /// A base `CALayer` that manages the frame and animations
7 | /// of its `sublayers` and `mask`
8 | class BaseAnimationLayer: CALayer, AnimationLayer {
9 |
10 | // MARK: Internal
11 |
12 | override func layoutSublayers() {
13 | super.layoutSublayers()
14 |
15 | for sublayer in managedSublayers {
16 | sublayer.fillBoundsOfSuperlayer()
17 | }
18 | }
19 |
20 | func setupAnimations(context: LayerAnimationContext) throws {
21 | for childAnimationLayer in managedSublayers {
22 | try (childAnimationLayer as? AnimationLayer)?.setupAnimations(context: context)
23 | }
24 | }
25 |
26 | // MARK: Private
27 |
28 | /// All of the sublayers managed by this container
29 | private var managedSublayers: [CALayer] {
30 | (sublayers ?? []) + [mask].compactMap { $0 }
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/CoreAnimation/Layers/LayerModel+makeAnimationLayer.swift:
--------------------------------------------------------------------------------
1 | // Created by Cal Stephens on 12/20/21.
2 | // Copyright © 2021 Airbnb Inc. All rights reserved.
3 |
4 | import QuartzCore
5 |
6 | // MARK: - LayerContext
7 |
8 | /// Context available when constructing an `AnimationLayer`
9 | struct LayerContext {
10 | let animation: LottieAnimation
11 | let imageProvider: AnimationImageProvider
12 | let textProvider: AnimationTextProvider
13 | let fontProvider: AnimationFontProvider
14 | let compatibilityTracker: CompatibilityTracker
15 | var layerName: String
16 |
17 | func forLayer(_ layer: LayerModel) -> LayerContext {
18 | var context = self
19 | context.layerName = layer.name
20 | return context
21 | }
22 | }
23 |
24 | // MARK: - LayerModel + makeAnimationLayer
25 |
26 | extension LayerModel {
27 | /// Constructs an `AnimationLayer` / `CALayer` that represents this `LayerModel`
28 | func makeAnimationLayer(context: LayerContext) throws -> BaseCompositionLayer? {
29 | let context = context.forLayer(self)
30 |
31 | if hidden {
32 | return TransformLayer(layerModel: self)
33 | }
34 |
35 | switch (type, self) {
36 | case (.precomp, let preCompLayerModel as PreCompLayerModel):
37 | let preCompLayer = PreCompLayer(preCompLayer: preCompLayerModel)
38 | try preCompLayer.setup(context: context)
39 | return preCompLayer
40 |
41 | case (.solid, let solidLayerModel as SolidLayerModel):
42 | return SolidLayer(solidLayerModel)
43 |
44 | case (.shape, let shapeLayerModel as ShapeLayerModel):
45 | return try ShapeLayer(shapeLayer: shapeLayerModel, context: context)
46 |
47 | case (.image, let imageLayerModel as ImageLayerModel):
48 | return ImageLayer(imageLayer: imageLayerModel, context: context)
49 |
50 | case (.text, let textLayerModel as TextLayerModel):
51 | return try TextLayer(textLayerModel: textLayerModel, context: context)
52 |
53 | case (.null, _):
54 | return TransformLayer(layerModel: self)
55 |
56 | default:
57 | try context.logCompatibilityIssue("""
58 | Unexpected layer type combination ("\(type)" and "\(Swift.type(of: self))")
59 | """)
60 |
61 | return nil
62 | }
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/CoreAnimation/Layers/SolidLayer.swift:
--------------------------------------------------------------------------------
1 | // Created by Cal Stephens on 12/13/21.
2 | // Copyright © 2021 Airbnb Inc. All rights reserved.
3 |
4 | import QuartzCore
5 |
6 | // MARK: - SolidLayer
7 |
8 | final class SolidLayer: BaseCompositionLayer {
9 |
10 | // MARK: Lifecycle
11 |
12 | init(_ solidLayer: SolidLayerModel) {
13 | self.solidLayer = solidLayer
14 | super.init(layerModel: solidLayer)
15 | setupContentLayer()
16 | }
17 |
18 | required init?(coder _: NSCoder) {
19 | fatalError("init(coder:) has not been implemented")
20 | }
21 |
22 | /// Called by CoreAnimation to create a shadow copy of this layer
23 | /// More details: https://developer.apple.com/documentation/quartzcore/calayer/1410842-init
24 | override init(layer: Any) {
25 | guard let typedLayer = layer as? Self else {
26 | fatalError("\(Self.self).init(layer:) incorrectly called with \(type(of: layer))")
27 | }
28 |
29 | solidLayer = typedLayer.solidLayer
30 | super.init(layer: typedLayer)
31 | }
32 |
33 | // MARK: Private
34 |
35 | private let solidLayer: SolidLayerModel
36 |
37 | private func setupContentLayer() {
38 | // Render the fill color in a child `CAShapeLayer`
39 | // - Using a `CAShapeLayer` specifically, instead of a `CALayer` with a `backgroundColor`,
40 | // allows the size of the fill shape to be different from `contentsLayer.size`.
41 | let shapeLayer = CAShapeLayer()
42 | shapeLayer.fillColor = solidLayer.colorHex.cgColor
43 | shapeLayer.path = CGPath(rect: .init(x: 0, y: 0, width: solidLayer.width, height: solidLayer.height), transform: nil)
44 | addSublayer(shapeLayer)
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/CoreAnimation/Layers/TransformLayer.swift:
--------------------------------------------------------------------------------
1 | // Created by Cal Stephens on 12/21/21.
2 | // Copyright © 2021 Airbnb Inc. All rights reserved.
3 |
4 | /// The CALayer type responsible for only rendering the `transform` of a `LayerModel`
5 | final class TransformLayer: BaseCompositionLayer {
6 |
7 | /// `TransformLayer`s don't render any visible content,
8 | /// they just `transform` their sublayers
9 | override var renderLayerContents: Bool { false }
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/LayerContainers/CompLayers/ImageCompositionLayer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageCompositionLayer.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/25/19.
6 | //
7 |
8 | import CoreGraphics
9 | import Foundation
10 | import QuartzCore
11 |
12 | final class ImageCompositionLayer: CompositionLayer {
13 |
14 | // MARK: Lifecycle
15 |
16 | init(imageLayer: ImageLayerModel, size: CGSize) {
17 | imageReferenceID = imageLayer.referenceID
18 | super.init(layer: imageLayer, size: size)
19 | contentsLayer.masksToBounds = true
20 | contentsLayer.contentsGravity = CALayerContentsGravity.resize
21 | }
22 |
23 | override init(layer: Any) {
24 | /// Used for creating shadow model layers. Read More here: https://developer.apple.com/documentation/quartzcore/calayer/1410842-init
25 | guard let layer = layer as? ImageCompositionLayer else {
26 | fatalError("init(layer:) Wrong Layer Class")
27 | }
28 | imageReferenceID = layer.imageReferenceID
29 | image = nil
30 | super.init(layer: layer)
31 | }
32 |
33 | required init?(coder _: NSCoder) {
34 | fatalError("init(coder:) has not been implemented")
35 | }
36 |
37 | // MARK: Internal
38 |
39 | let imageReferenceID: String
40 |
41 | var image: CGImage? = nil {
42 | didSet {
43 | if let image = image {
44 | contentsLayer.contents = image
45 | } else {
46 | contentsLayer.contents = nil
47 | }
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/LayerContainers/CompLayers/NullCompositionLayer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NullCompositionLayer.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/25/19.
6 | //
7 |
8 | import Foundation
9 |
10 | final class NullCompositionLayer: CompositionLayer {
11 |
12 | init(layer: LayerModel) {
13 | super.init(layer: layer, size: .zero)
14 | }
15 |
16 | required init?(coder _: NSCoder) {
17 | fatalError("init(coder:) has not been implemented")
18 | }
19 |
20 | override init(layer: Any) {
21 | /// Used for creating shadow model layers. Read More here: https://developer.apple.com/documentation/quartzcore/calayer/1410842-init
22 | guard let layer = layer as? NullCompositionLayer else {
23 | fatalError("init(layer:) Wrong Layer Class")
24 | }
25 | super.init(layer: layer)
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/LayerContainers/CompLayers/ShapeCompositionLayer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ShapeLayerContainer.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/22/19.
6 | //
7 |
8 | import CoreGraphics
9 | import Foundation
10 |
11 | /// A CompositionLayer responsible for initializing and rendering shapes
12 | final class ShapeCompositionLayer: CompositionLayer {
13 |
14 | // MARK: Lifecycle
15 |
16 | init(shapeLayer: ShapeLayerModel) {
17 | let results = shapeLayer.items.initializeNodeTree()
18 | let renderContainer = ShapeContainerLayer()
19 | self.renderContainer = renderContainer
20 | rootNode = results.rootNode
21 | super.init(layer: shapeLayer, size: .zero)
22 | contentsLayer.addSublayer(renderContainer)
23 | for container in results.renderContainers {
24 | renderContainer.insertRenderLayer(container)
25 | }
26 | rootNode?.updateTree(0, forceUpdates: true)
27 | childKeypaths.append(contentsOf: results.childrenNodes)
28 | }
29 |
30 | override init(layer: Any) {
31 | guard let layer = layer as? ShapeCompositionLayer else {
32 | fatalError("init(layer:) wrong class.")
33 | }
34 | rootNode = nil
35 | renderContainer = nil
36 | super.init(layer: layer)
37 | }
38 |
39 | required init?(coder _: NSCoder) {
40 | fatalError("init(coder:) has not been implemented")
41 | }
42 |
43 | // MARK: Internal
44 |
45 | let rootNode: AnimatorNode?
46 | let renderContainer: ShapeContainerLayer?
47 |
48 | override func displayContentsWithFrame(frame: CGFloat, forceUpdates: Bool) {
49 | rootNode?.updateTree(frame, forceUpdates: forceUpdates)
50 | renderContainer?.markRenderUpdates(forFrame: frame)
51 | }
52 |
53 | override func updateRenderScale() {
54 | super.updateRenderScale()
55 | renderContainer?.renderScale = renderScale
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/LayerContainers/CompLayers/SolidCompositionLayer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SolidCompositionLayer.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/25/19.
6 | //
7 |
8 | import Foundation
9 | import QuartzCore
10 |
11 | final class SolidCompositionLayer: CompositionLayer {
12 |
13 | // MARK: Lifecycle
14 |
15 | init(solid: SolidLayerModel) {
16 | let components = solid.colorHex.hexColorComponents()
17 | colorProperty =
18 | NodeProperty(provider: SingleValueProvider(LottieColor(
19 | r: Double(components.red),
20 | g: Double(components.green),
21 | b: Double(components.blue),
22 | a: 1)))
23 |
24 | super.init(layer: solid, size: .zero)
25 | solidShape.path = CGPath(rect: CGRect(x: 0, y: 0, width: solid.width, height: solid.height), transform: nil)
26 | contentsLayer.addSublayer(solidShape)
27 | }
28 |
29 | override init(layer: Any) {
30 | /// Used for creating shadow model layers. Read More here: https://developer.apple.com/documentation/quartzcore/calayer/1410842-init
31 | guard let layer = layer as? SolidCompositionLayer else {
32 | fatalError("init(layer:) Wrong Layer Class")
33 | }
34 | colorProperty = layer.colorProperty
35 | super.init(layer: layer)
36 | }
37 |
38 | required init?(coder _: NSCoder) {
39 | fatalError("init(coder:) has not been implemented")
40 | }
41 |
42 | // MARK: Internal
43 |
44 | let colorProperty: NodeProperty?
45 | let solidShape = CAShapeLayer()
46 |
47 | override var keypathProperties: [String: AnyNodeProperty] {
48 | guard let colorProperty = colorProperty else { return super.keypathProperties }
49 | return [PropertyName.color.rawValue : colorProperty]
50 | }
51 |
52 | override func displayContentsWithFrame(frame: CGFloat, forceUpdates _: Bool) {
53 | guard let colorProperty = colorProperty else { return }
54 | colorProperty.update(frame: frame)
55 | solidShape.fillColor = colorProperty.value.cgColorValue
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/LayerContainers/Utility/CachedImageProvider.swift:
--------------------------------------------------------------------------------
1 | // Created by Jianjun Wu on 2022/5/12.
2 | // Copyright © 2022 Airbnb Inc. All rights reserved.
3 |
4 | import CoreGraphics
5 | import Foundation
6 |
7 | // MARK: - CachedImageProvider
8 |
9 | private final class CachedImageProvider: AnimationImageProvider {
10 |
11 | // MARK: Lifecycle
12 |
13 | /// Initializes an image provider with an image provider
14 | ///
15 | /// - Parameter imageProvider: The provider to load image from asset
16 | ///
17 | public init(imageProvider: AnimationImageProvider) {
18 | self.imageProvider = imageProvider
19 | }
20 |
21 | // MARK: Public
22 |
23 | public func imageForAsset(asset: ImageAsset) -> CGImage? {
24 | if let image = imageCache.object(forKey: asset.id as NSString) {
25 | return image
26 | }
27 | if let image = imageProvider.imageForAsset(asset: asset) {
28 | imageCache.setObject(image, forKey: asset.id as NSString)
29 | return image
30 | }
31 | return nil
32 | }
33 |
34 | // MARK: Internal
35 |
36 | let imageCache: NSCache = .init()
37 | let imageProvider: AnimationImageProvider
38 | }
39 |
40 | extension AnimationImageProvider {
41 | /// Create a cache enabled image provider which will reuse the asset image with the same asset id
42 | /// It wraps the current provider as image loader, and uses `NSCache` to cache the images for resue.
43 | /// The cache will be reset when the `animation` is reset.
44 | var cachedImageProvider: AnimationImageProvider {
45 | CachedImageProvider(imageProvider: self)
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/LayerContainers/Utility/InvertedMatteLayer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // InvertedMatteLayer.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/28/19.
6 | //
7 |
8 | import Foundation
9 | import QuartzCore
10 |
11 | /// A layer that inverses the alpha output of its input layer.
12 | ///
13 | /// WARNING: This is experimental and probably not very performant.
14 | final class InvertedMatteLayer: CALayer, CompositionLayerDelegate {
15 |
16 | // MARK: Lifecycle
17 |
18 | init(inputMatte: CompositionLayer) {
19 | self.inputMatte = inputMatte
20 | super.init()
21 | inputMatte.layerDelegate = self
22 | anchorPoint = .zero
23 | bounds = inputMatte.bounds
24 | setNeedsDisplay()
25 | }
26 |
27 | override init(layer: Any) {
28 | guard let layer = layer as? InvertedMatteLayer else {
29 | fatalError("init(layer:) wrong class.")
30 | }
31 | inputMatte = nil
32 | super.init(layer: layer)
33 | }
34 |
35 | required init?(coder _: NSCoder) {
36 | fatalError("init(coder:) has not been implemented")
37 | }
38 |
39 | // MARK: Internal
40 |
41 | let inputMatte: CompositionLayer?
42 | let wrapperLayer = CALayer()
43 |
44 | func frameUpdated(frame _: CGFloat) {
45 | setNeedsDisplay()
46 | displayIfNeeded()
47 | }
48 |
49 | override func draw(in ctx: CGContext) {
50 | guard let inputMatte = inputMatte else { return }
51 | guard let fillColor = CGColor(colorSpace: CGColorSpaceCreateDeviceRGB(), components: [0, 0, 0, 1])
52 | else { return }
53 | ctx.setFillColor(fillColor)
54 | ctx.fill(bounds)
55 | ctx.setBlendMode(.destinationOut)
56 | inputMatte.render(in: ctx)
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/LayerContainers/Utility/LayerFontProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LayerFontProvider.swift
3 | // Lottie
4 | //
5 | // Created by Brandon Withrow on 8/5/20.
6 | // Copyright © 2020 YurtvilleProds. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /// Connects a LottieFontProvider to a group of text layers
12 | final class LayerFontProvider {
13 |
14 | // MARK: Lifecycle
15 |
16 | init(fontProvider: AnimationFontProvider) {
17 | self.fontProvider = fontProvider
18 | textLayers = []
19 | reloadTexts()
20 | }
21 |
22 | // MARK: Internal
23 |
24 | private(set) var textLayers: [TextCompositionLayer]
25 |
26 | var fontProvider: AnimationFontProvider {
27 | didSet {
28 | reloadTexts()
29 | }
30 | }
31 |
32 | func addTextLayers(_ layers: [TextCompositionLayer]) {
33 | textLayers += layers
34 | }
35 |
36 | func reloadTexts() {
37 | textLayers.forEach {
38 | $0.fontProvider = fontProvider
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/LayerContainers/Utility/LayerImageProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LayerImageProvider.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/25/19.
6 | //
7 |
8 | import Foundation
9 |
10 | /// Connects a LottieImageProvider to a group of image layers
11 | final class LayerImageProvider {
12 |
13 | // MARK: Lifecycle
14 |
15 | init(imageProvider: AnimationImageProvider, assets: [String: ImageAsset]?) {
16 | self.imageProvider = imageProvider
17 | imageLayers = [ImageCompositionLayer]()
18 | if let assets = assets {
19 | imageAssets = assets
20 | } else {
21 | imageAssets = [:]
22 | }
23 | reloadImages()
24 | }
25 |
26 | // MARK: Internal
27 |
28 | private(set) var imageLayers: [ImageCompositionLayer]
29 | let imageAssets: [String: ImageAsset]
30 |
31 | var imageProvider: AnimationImageProvider {
32 | didSet {
33 | reloadImages()
34 | }
35 | }
36 |
37 | func addImageLayers(_ layers: [ImageCompositionLayer]) {
38 | for layer in layers {
39 | if imageAssets[layer.imageReferenceID] != nil {
40 | /// Found a linking asset in our asset library. Add layer
41 | imageLayers.append(layer)
42 | }
43 | }
44 | }
45 |
46 | func reloadImages() {
47 | for imageLayer in imageLayers {
48 | if let asset = imageAssets[imageLayer.imageReferenceID] {
49 | imageLayer.image = imageProvider.imageForAsset(asset: asset)
50 | }
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/LayerContainers/Utility/LayerTextProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LayerTextProvider.swift
3 | // lottie-ios-iOS
4 | //
5 | // Created by Alexandr Goncharov on 07/06/2019.
6 | //
7 |
8 | import Foundation
9 |
10 | /// Connects a LottieTextProvider to a group of text layers
11 | final class LayerTextProvider {
12 |
13 | // MARK: Lifecycle
14 |
15 | init(textProvider: AnimationTextProvider) {
16 | self.textProvider = textProvider
17 | textLayers = []
18 | reloadTexts()
19 | }
20 |
21 | // MARK: Internal
22 |
23 | private(set) var textLayers: [TextCompositionLayer]
24 |
25 | var textProvider: AnimationTextProvider {
26 | didSet {
27 | reloadTexts()
28 | }
29 | }
30 |
31 | func addTextLayers(_ layers: [TextCompositionLayer]) {
32 | textLayers += layers
33 | }
34 |
35 | func reloadTexts() {
36 | textLayers.forEach {
37 | $0.textProvider = textProvider
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/NodeRenderSystem/NodeProperties/NodeProperty.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NodeProperty.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/30/19.
6 | //
7 |
8 | import CoreGraphics
9 | import Foundation
10 |
11 | /// A node property that holds a reference to a T ValueProvider and a T ValueContainer.
12 | class NodeProperty: AnyNodeProperty {
13 |
14 | // MARK: Lifecycle
15 |
16 | init(provider: AnyValueProvider) {
17 | valueProvider = provider
18 | originalValueProvider = valueProvider
19 | typedContainer = ValueContainer(provider.value(frame: 0) as! T)
20 | typedContainer.setNeedsUpdate()
21 | }
22 |
23 | // MARK: Internal
24 |
25 | var valueProvider: AnyValueProvider
26 | var originalValueProvider: AnyValueProvider
27 |
28 | var valueType: Any.Type { T.self }
29 |
30 | var value: T {
31 | typedContainer.outputValue
32 | }
33 |
34 | var valueContainer: AnyValueContainer {
35 | typedContainer
36 | }
37 |
38 | func needsUpdate(frame: CGFloat) -> Bool {
39 | valueContainer.needsUpdate || valueProvider.hasUpdate(frame: frame)
40 | }
41 |
42 | func setProvider(provider: AnyValueProvider) {
43 | guard provider.valueType == valueType else { return }
44 | valueProvider = provider
45 | valueContainer.setNeedsUpdate()
46 | }
47 |
48 | func update(frame: CGFloat) {
49 | typedContainer.setValue(valueProvider.value(frame: frame), forFrame: frame)
50 | }
51 |
52 | // MARK: Fileprivate
53 |
54 | fileprivate var typedContainer: ValueContainer
55 | }
56 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/NodeRenderSystem/NodeProperties/Protocols/AnyNodeProperty.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnyNodeProperty.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/30/19.
6 | //
7 |
8 | import CoreGraphics
9 | import Foundation
10 |
11 | // MARK: - AnyNodeProperty
12 |
13 | /// A property of a node. The node property holds a provider and a container
14 | protocol AnyNodeProperty {
15 |
16 | /// Returns true if the property needs to recompute its stored value
17 | func needsUpdate(frame: CGFloat) -> Bool
18 |
19 | /// Updates the property for the frame
20 | func update(frame: CGFloat)
21 |
22 | /// The stored value container for the property
23 | var valueContainer: AnyValueContainer { get }
24 |
25 | /// The value provider for the property
26 | var valueProvider: AnyValueProvider { get }
27 |
28 | /// The original value provider for the property
29 | var originalValueProvider: AnyValueProvider { get }
30 |
31 | /// The Type of the value provider
32 | var valueType: Any.Type { get }
33 |
34 | /// Sets the value provider for the property.
35 | func setProvider(provider: AnyValueProvider)
36 | }
37 |
38 | extension AnyNodeProperty {
39 |
40 | /// Returns the most recently computed value for the keypath, returns nil if property wasn't found
41 | func getValueOfType() -> T? {
42 | valueContainer.value as? T
43 | }
44 |
45 | /// Returns the most recently computed value for the keypath, returns nil if property wasn't found
46 | func getValue() -> Any? {
47 | valueContainer.value
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/NodeRenderSystem/NodeProperties/Protocols/AnyValueContainer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnyValueContainer.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/30/19.
6 | //
7 |
8 | import CoreGraphics
9 | import Foundation
10 |
11 | /// The container for the value of a property.
12 | protocol AnyValueContainer: AnyObject {
13 |
14 | /// The stored value of the container
15 | var value: Any { get }
16 |
17 | /// Notifies the provider that it should update its container
18 | func setNeedsUpdate()
19 |
20 | /// When true the container needs to have its value updated by its provider
21 | var needsUpdate: Bool { get }
22 |
23 | /// The frame time of the last provided update
24 | var lastUpdateFrame: CGFloat { get }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/NodeRenderSystem/NodeProperties/Protocols/KeypathSearchable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // KeypathSettable.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 2/4/19.
6 | //
7 |
8 | import Foundation
9 | import QuartzCore
10 |
11 | /// Protocol that provides keypath search functionality. Returns all node properties associated with a keypath.
12 | protocol KeypathSearchable {
13 |
14 | /// The name of the Keypath
15 | var keypathName: String { get }
16 |
17 | /// A list of properties belonging to the keypath.
18 | var keypathProperties: [String: AnyNodeProperty] { get }
19 |
20 | /// Children Keypaths
21 | var childKeypaths: [KeypathSearchable] { get }
22 |
23 | var keypathLayer: CALayer? { get }
24 | }
25 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/NodeRenderSystem/NodeProperties/Protocols/NodePropertyMap.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NodePropertyMap.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/21/19.
6 | //
7 |
8 | import Foundation
9 | import QuartzCore
10 |
11 | // MARK: - NodePropertyMap
12 |
13 | protocol NodePropertyMap {
14 | var properties: [AnyNodeProperty] { get }
15 | }
16 |
17 | extension NodePropertyMap {
18 |
19 | var childKeypaths: [KeypathSearchable] {
20 | []
21 | }
22 |
23 | var keypathLayer: CALayer? {
24 | nil
25 | }
26 |
27 | /// Checks if the node's local contents need to be rebuilt.
28 | func needsLocalUpdate(frame: CGFloat) -> Bool {
29 | for property in properties {
30 | if property.needsUpdate(frame: frame) {
31 | return true
32 | }
33 | }
34 | return false
35 | }
36 |
37 | /// Rebuilds only the local nodes that have an update for the frame
38 | func updateNodeProperties(frame: CGFloat) {
39 | properties.forEach { property in
40 | property.update(frame: frame)
41 | }
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/NodeRenderSystem/NodeProperties/ValueContainer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ValueContainer.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/30/19.
6 | //
7 |
8 | import CoreGraphics
9 | import Foundation
10 |
11 | /// A container for a node value that is Typed to T.
12 | class ValueContainer: AnyValueContainer {
13 |
14 | // MARK: Lifecycle
15 |
16 | init(_ value: T) {
17 | outputValue = value
18 | }
19 |
20 | // MARK: Internal
21 |
22 | private(set) var lastUpdateFrame = CGFloat.infinity
23 |
24 | fileprivate(set) var needsUpdate = true
25 |
26 | var value: Any {
27 | outputValue as Any
28 | }
29 |
30 | var outputValue: T {
31 | didSet {
32 | needsUpdate = false
33 | }
34 | }
35 |
36 | func setValue(_ value: Any, forFrame: CGFloat) {
37 | if let typedValue = value as? T {
38 | needsUpdate = false
39 | lastUpdateFrame = forFrame
40 | outputValue = typedValue
41 | }
42 | }
43 |
44 | func setNeedsUpdate() {
45 | needsUpdate = true
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/NodeRenderSystem/NodeProperties/ValueProviders/GroupInterpolator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // KeyframeGroupInterpolator.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/22/19.
6 | //
7 |
8 | import CoreGraphics
9 | import Foundation
10 |
11 | /// A value provider that produces an array of values from an array of Keyframe Interpolators
12 | final class GroupInterpolator: ValueProvider where ValueType: Interpolatable {
13 |
14 | // MARK: Lifecycle
15 |
16 | /// Initialize with an array of array of keyframes.
17 | init(keyframeGroups: ContiguousArray>>) {
18 | keyframeInterpolators = ContiguousArray(keyframeGroups.map({ KeyframeInterpolator(keyframes: $0) }))
19 | }
20 |
21 | // MARK: Internal
22 |
23 | let keyframeInterpolators: ContiguousArray>
24 |
25 | var valueType: Any.Type {
26 | [ValueType].self
27 | }
28 |
29 | var storage: ValueProviderStorage<[ValueType]> {
30 | .closure { frame in
31 | self.keyframeInterpolators.map({ $0.value(frame: frame) as! ValueType })
32 | }
33 | }
34 |
35 | func hasUpdate(frame: CGFloat) -> Bool {
36 | let updated = keyframeInterpolators.first(where: { $0.hasUpdate(frame: frame) })
37 | return updated != nil
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/NodeRenderSystem/NodeProperties/ValueProviders/SingleValueProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SingleValueProvider.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/30/19.
6 | //
7 |
8 | import Foundation
9 | import QuartzCore
10 |
11 | /// Returns a value for every frame.
12 | final class SingleValueProvider: ValueProvider {
13 |
14 | // MARK: Lifecycle
15 |
16 | init(_ value: ValueType) {
17 | self.value = value
18 | }
19 |
20 | // MARK: Internal
21 |
22 | var value: ValueType {
23 | didSet {
24 | hasUpdate = true
25 | }
26 | }
27 |
28 | var storage: ValueProviderStorage {
29 | .singleValue(value)
30 | }
31 |
32 | var valueType: Any.Type {
33 | ValueType.self
34 | }
35 |
36 | func hasUpdate(frame _: CGFloat) -> Bool {
37 | hasUpdate
38 | }
39 |
40 | // MARK: Private
41 |
42 | private var hasUpdate = true
43 | }
44 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/GroupOutputNode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TransformNodeOutput.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/30/19.
6 | //
7 |
8 | import CoreGraphics
9 | import Foundation
10 | import QuartzCore
11 |
12 | class GroupOutputNode: NodeOutput {
13 |
14 | // MARK: Lifecycle
15 |
16 | init(parent: NodeOutput?, rootNode: NodeOutput?) {
17 | self.parent = parent
18 | self.rootNode = rootNode
19 | }
20 |
21 | // MARK: Internal
22 |
23 | let parent: NodeOutput?
24 | let rootNode: NodeOutput?
25 | var isEnabled = true
26 |
27 | private(set) var outputPath: CGPath? = nil
28 | private(set) var transform: CATransform3D = CATransform3DIdentity
29 |
30 | func setTransform(_ xform: CATransform3D, forFrame _: CGFloat) {
31 | transform = xform
32 | outputPath = nil
33 | }
34 |
35 | func hasOutputUpdates(_ forFrame: CGFloat) -> Bool {
36 | guard isEnabled else {
37 | let upstreamUpdates = parent?.hasOutputUpdates(forFrame) ?? false
38 | outputPath = parent?.outputPath
39 | return upstreamUpdates
40 | }
41 |
42 | let upstreamUpdates = parent?.hasOutputUpdates(forFrame) ?? false
43 | if upstreamUpdates {
44 | outputPath = nil
45 | }
46 | let rootUpdates = rootNode?.hasOutputUpdates(forFrame) ?? false
47 | if rootUpdates {
48 | outputPath = nil
49 | }
50 |
51 | var localUpdates = false
52 | if outputPath == nil {
53 | localUpdates = true
54 |
55 | let newPath = CGMutablePath()
56 | if let parentNode = parent, let parentPath = parentNode.outputPath {
57 | /// First add parent path.
58 | newPath.addPath(parentPath)
59 | }
60 | var xform = CATransform3DGetAffineTransform(transform)
61 | if
62 | let rootNode = rootNode,
63 | let rootPath = rootNode.outputPath,
64 | let xformedPath = rootPath.copy(using: &xform)
65 | {
66 | /// Now add root path. Note root path is transformed.
67 | newPath.addPath(xformedPath)
68 | }
69 |
70 | outputPath = newPath
71 | }
72 |
73 | return upstreamUpdates || localUpdates
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/PassThroughOutputNode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PassThroughOutputNode.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/30/19.
6 | //
7 |
8 | import CoreGraphics
9 | import Foundation
10 |
11 | class PassThroughOutputNode: NodeOutput {
12 |
13 | // MARK: Lifecycle
14 |
15 | init(parent: NodeOutput?) {
16 | self.parent = parent
17 | }
18 |
19 | // MARK: Internal
20 |
21 | let parent: NodeOutput?
22 |
23 | var hasUpdate = false
24 | var isEnabled = true
25 |
26 | var outputPath: CGPath? {
27 | if let parent = parent {
28 | return parent.outputPath
29 | }
30 | return nil
31 | }
32 |
33 | func hasOutputUpdates(_ forFrame: CGFloat) -> Bool {
34 | /// Changes to this node do not affect downstream nodes.
35 | let parentUpdate = parent?.hasOutputUpdates(forFrame) ?? false
36 | /// Changes to upstream nodes do, however, affect this nodes state.
37 | hasUpdate = hasUpdate || parentUpdate
38 | return parentUpdate
39 | }
40 |
41 | func hasRenderUpdates(_ forFrame: CGFloat) -> Bool {
42 | /// Return true if there are upstream updates or if this node has updates
43 | let upstreamUpdates = parent?.hasOutputUpdates(forFrame) ?? false
44 | hasUpdate = hasUpdate || upstreamUpdates
45 | return hasUpdate
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/FillRenderer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FillRenderer.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/30/19.
6 | //
7 |
8 | import CoreGraphics
9 | import Foundation
10 | import QuartzCore
11 |
12 | extension FillRule {
13 | var cgFillRule: CGPathFillRule {
14 | switch self {
15 | case .evenOdd:
16 | return .evenOdd
17 | default:
18 | return .winding
19 | }
20 | }
21 |
22 | var caFillRule: CAShapeLayerFillRule {
23 | switch self {
24 | case .evenOdd:
25 | return CAShapeLayerFillRule.evenOdd
26 | default:
27 | return CAShapeLayerFillRule.nonZero
28 | }
29 | }
30 | }
31 |
32 | // MARK: - FillRenderer
33 |
34 | /// A rendered for a Path Fill
35 | final class FillRenderer: PassThroughOutputNode, Renderable {
36 | var shouldRenderInContext = false
37 |
38 | var color: CGColor? {
39 | didSet {
40 | hasUpdate = true
41 | }
42 | }
43 |
44 | var opacity: CGFloat = 0 {
45 | didSet {
46 | hasUpdate = true
47 | }
48 | }
49 |
50 | var fillRule: FillRule = .none {
51 | didSet {
52 | hasUpdate = true
53 | }
54 | }
55 |
56 | func render(_: CGContext) {
57 | // do nothing
58 | }
59 |
60 | func setupSublayers(layer _: CAShapeLayer) {
61 | // do nothing
62 | }
63 |
64 | func updateShapeLayer(layer: CAShapeLayer) {
65 | layer.fillColor = color
66 | layer.opacity = Float(opacity)
67 | layer.fillRule = fillRule.caFillRule
68 | hasUpdate = false
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientStrokeRenderer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GradientStrokeRenderer.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/30/19.
6 | //
7 |
8 | import Foundation
9 | import QuartzCore
10 |
11 | // MARK: - Renderer
12 |
13 | final class GradientStrokeRenderer: PassThroughOutputNode, Renderable {
14 |
15 | // MARK: Lifecycle
16 |
17 | override init(parent: NodeOutput?) {
18 | strokeRender = StrokeRenderer(parent: nil)
19 | gradientRender = LegacyGradientFillRenderer(parent: nil)
20 | strokeRender.color = CGColor(colorSpace: CGColorSpaceCreateDeviceRGB(), components: [1, 1, 1, 1])
21 | super.init(parent: parent)
22 | }
23 |
24 | // MARK: Internal
25 |
26 | var shouldRenderInContext = true
27 |
28 | let strokeRender: StrokeRenderer
29 | let gradientRender: LegacyGradientFillRenderer
30 |
31 | override func hasOutputUpdates(_ forFrame: CGFloat) -> Bool {
32 | let updates = super.hasOutputUpdates(forFrame)
33 | return updates || strokeRender.hasUpdate || gradientRender.hasUpdate
34 | }
35 |
36 | func updateShapeLayer(layer _: CAShapeLayer) {
37 | /// Not Applicable
38 | }
39 |
40 | func setupSublayers(layer _: CAShapeLayer) {
41 | /// Not Applicable
42 | }
43 |
44 | func render(_ inContext: CGContext) {
45 | guard inContext.path != nil, inContext.path!.isEmpty == false else {
46 | return
47 | }
48 |
49 | strokeRender.hasUpdate = false
50 | hasUpdate = false
51 | gradientRender.hasUpdate = false
52 |
53 | strokeRender.setupForStroke(inContext)
54 |
55 | inContext.replacePathWithStrokedPath()
56 |
57 | /// Now draw the gradient.
58 | gradientRender.render(inContext)
59 | }
60 |
61 | func renderBoundsFor(_ boundingBox: CGRect) -> CGRect {
62 | strokeRender.renderBoundsFor(boundingBox)
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/ShapeNode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PathNode.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/16/19.
6 | //
7 |
8 | import CoreGraphics
9 | import Foundation
10 |
11 | // MARK: - ShapeNodeProperties
12 |
13 | final class ShapeNodeProperties: NodePropertyMap, KeypathSearchable {
14 |
15 | // MARK: Lifecycle
16 |
17 | init(shape: Shape) {
18 | keypathName = shape.name
19 | path = NodeProperty(provider: KeyframeInterpolator(keyframes: shape.path.keyframes))
20 | keypathProperties = [
21 | "Path" : path,
22 | ]
23 | properties = Array(keypathProperties.values)
24 | }
25 |
26 | // MARK: Internal
27 |
28 | var keypathName: String
29 |
30 | let path: NodeProperty
31 | let keypathProperties: [String: AnyNodeProperty]
32 | let properties: [AnyNodeProperty]
33 |
34 | }
35 |
36 | // MARK: - ShapeNode
37 |
38 | final class ShapeNode: AnimatorNode, PathNode {
39 |
40 | // MARK: Lifecycle
41 |
42 | init(parentNode: AnimatorNode?, shape: Shape) {
43 | pathOutput = PathOutputNode(parent: parentNode?.outputNode)
44 | properties = ShapeNodeProperties(shape: shape)
45 | self.parentNode = parentNode
46 | }
47 |
48 | // MARK: Internal
49 |
50 | let properties: ShapeNodeProperties
51 |
52 | let pathOutput: PathOutputNode
53 |
54 | let parentNode: AnimatorNode?
55 | var hasLocalUpdates = false
56 | var hasUpstreamUpdates = false
57 | var lastUpdateFrame: CGFloat? = nil
58 |
59 | // MARK: Animator Node
60 | var propertyMap: NodePropertyMap & KeypathSearchable {
61 | properties
62 | }
63 |
64 | var isEnabled = true {
65 | didSet {
66 | pathOutput.isEnabled = isEnabled
67 | }
68 | }
69 |
70 | func rebuildOutputs(frame: CGFloat) {
71 | pathOutput.setPath(properties.path.value, updateFrame: frame)
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/NodeRenderSystem/Protocols/PathNode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PathNode.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/17/19.
6 | //
7 |
8 | import Foundation
9 |
10 | // MARK: - PathNode
11 |
12 | protocol PathNode {
13 | var pathOutput: PathOutputNode { get }
14 | }
15 |
16 | extension PathNode where Self: AnimatorNode {
17 |
18 | var outputNode: NodeOutput {
19 | pathOutput
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/NodeRenderSystem/Protocols/RenderNode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RenderNode.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/17/19.
6 | //
7 |
8 | import CoreGraphics
9 | import Foundation
10 | import QuartzCore
11 |
12 | // MARK: - RenderNode
13 |
14 | /// A protocol that defines a node that holds render instructions
15 | protocol RenderNode {
16 | var renderer: Renderable & NodeOutput { get }
17 | }
18 |
19 | // MARK: - Renderable
20 |
21 | /// A protocol that defines anything with render instructions
22 | protocol Renderable {
23 |
24 | /// The last frame in which this node was updated.
25 | var hasUpdate: Bool { get }
26 |
27 | func hasRenderUpdates(_ forFrame: CGFloat) -> Bool
28 |
29 | /// Determines if the renderer requires a custom context for drawing.
30 | /// If yes the shape layer will perform a custom drawing pass.
31 | /// If no the shape layer will be a standard CAShapeLayer
32 | var shouldRenderInContext: Bool { get }
33 |
34 | /// Passes in the CAShapeLayer to update
35 | func updateShapeLayer(layer: CAShapeLayer)
36 |
37 | /// Asks the renderer what the renderable bounds is for the given box.
38 | func renderBoundsFor(_ boundingBox: CGRect) -> CGRect
39 |
40 | /// Opportunity for renderers to inject sublayers
41 | func setupSublayers(layer: CAShapeLayer)
42 |
43 | /// Renders the shape in a custom context
44 | func render(_ inContext: CGContext)
45 | }
46 |
47 | extension RenderNode where Self: AnimatorNode {
48 |
49 | var outputNode: NodeOutput {
50 | renderer
51 | }
52 |
53 | }
54 |
55 | extension Renderable {
56 |
57 | func renderBoundsFor(_ boundingBox: CGRect) -> CGRect {
58 | /// Optional
59 | boundingBox
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/MainThread/NodeRenderSystem/RenderLayers/ShapeContainerLayer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ShapeContainerLayer.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/30/19.
6 | //
7 |
8 | import Foundation
9 | import QuartzCore
10 |
11 | /// The base layer that holds Shapes and Shape Renderers
12 | class ShapeContainerLayer: CALayer {
13 |
14 | // MARK: Lifecycle
15 |
16 | override init() {
17 | super.init()
18 | actions = [
19 | "position" : NSNull(),
20 | "bounds" : NSNull(),
21 | "anchorPoint" : NSNull(),
22 | "transform" : NSNull(),
23 | "opacity" : NSNull(),
24 | "hidden" : NSNull(),
25 | ]
26 | }
27 |
28 | required init?(coder _: NSCoder) {
29 | fatalError("init(coder:) has not been implemented")
30 | }
31 |
32 | override init(layer: Any) {
33 | guard let layer = layer as? ShapeContainerLayer else {
34 | fatalError("init(layer:) wrong class.")
35 | }
36 | super.init(layer: layer)
37 | }
38 |
39 | // MARK: Internal
40 |
41 | private(set) var renderLayers: [ShapeContainerLayer] = []
42 |
43 | var renderScale: CGFloat = 1 {
44 | didSet {
45 | updateRenderScale()
46 | }
47 | }
48 |
49 | func insertRenderLayer(_ layer: ShapeContainerLayer) {
50 | renderLayers.append(layer)
51 | insertSublayer(layer, at: 0)
52 | }
53 |
54 | func markRenderUpdates(forFrame: CGFloat) {
55 | if hasRenderUpdate(forFrame: forFrame) {
56 | rebuildContents(forFrame: forFrame)
57 | }
58 | guard isHidden == false else { return }
59 | renderLayers.forEach { $0.markRenderUpdates(forFrame: forFrame) }
60 | }
61 |
62 | func hasRenderUpdate(forFrame _: CGFloat) -> Bool {
63 | false
64 | }
65 |
66 | func rebuildContents(forFrame _: CGFloat) {
67 | /// Override
68 | }
69 |
70 | func updateRenderScale() {
71 | contentsScale = renderScale
72 | renderLayers.forEach({ $0.renderScale = renderScale })
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/Model/Assets/Asset.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Asset.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/9/19.
6 | //
7 |
8 | import Foundation
9 |
10 | public class Asset: Codable, DictionaryInitializable {
11 |
12 | // MARK: Lifecycle
13 |
14 | required public init(from decoder: Decoder) throws {
15 | let container = try decoder.container(keyedBy: Asset.CodingKeys.self)
16 | if let id = try? container.decode(String.self, forKey: .id) {
17 | self.id = id
18 | } else {
19 | id = String(try container.decode(Int.self, forKey: .id))
20 | }
21 | }
22 |
23 | required init(dictionary: [String: Any]) throws {
24 | if let id = dictionary[CodingKeys.id.rawValue] as? String {
25 | self.id = id
26 | } else if let id = dictionary[CodingKeys.id.rawValue] as? Int {
27 | self.id = String(id)
28 | } else {
29 | throw InitializableError.invalidInput
30 | }
31 | }
32 |
33 | // MARK: Public
34 |
35 | /// The ID of the asset
36 | public let id: String
37 |
38 | // MARK: Private
39 |
40 | private enum CodingKeys: String, CodingKey {
41 | case id
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/Model/Assets/PrecompAsset.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PrecompAsset.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/9/19.
6 | //
7 |
8 | import Foundation
9 |
10 | final class PrecompAsset: Asset {
11 |
12 | // MARK: Lifecycle
13 |
14 | required init(from decoder: Decoder) throws {
15 | let container = try decoder.container(keyedBy: PrecompAsset.CodingKeys.self)
16 | layers = try container.decode([LayerModel].self, ofFamily: LayerType.self, forKey: .layers)
17 | try super.init(from: decoder)
18 | }
19 |
20 | required init(dictionary: [String: Any]) throws {
21 | let layerDictionaries: [[String: Any]] = try dictionary.value(for: CodingKeys.layers)
22 | layers = try [LayerModel].fromDictionaries(layerDictionaries)
23 | try super.init(dictionary: dictionary)
24 | }
25 |
26 | // MARK: Internal
27 |
28 | enum CodingKeys: String, CodingKey {
29 | case layers
30 | }
31 |
32 | /// Layers of the precomp
33 | let layers: [LayerModel]
34 |
35 | override func encode(to encoder: Encoder) throws {
36 | try super.encode(to: encoder)
37 | var container = encoder.container(keyedBy: CodingKeys.self)
38 | try container.encode(layers, forKey: .layers)
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/Model/DictionaryInitializable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DictionaryInitializable.swift
3 | // Lottie
4 | //
5 | // Created by Marcelo Fabri on 5/5/22.
6 | //
7 |
8 | import Foundation
9 |
10 | // MARK: - InitializableError
11 |
12 | enum InitializableError: Error {
13 | case invalidInput
14 | }
15 |
16 | // MARK: - DictionaryInitializable
17 |
18 | protocol DictionaryInitializable {
19 |
20 | init(dictionary: [String: Any]) throws
21 |
22 | }
23 |
24 | // MARK: - AnyInitializable
25 |
26 | protocol AnyInitializable {
27 |
28 | init(value: Any) throws
29 |
30 | }
31 |
32 | extension Dictionary {
33 |
34 | @_disfavoredOverload
35 | func value(for key: KeyType) throws -> T where KeyType.RawValue == Key {
36 | guard let value = self[key.rawValue] as? T else {
37 | throw InitializableError.invalidInput
38 | }
39 | return value
40 | }
41 |
42 | func value(for key: KeyType) throws -> T where KeyType.RawValue == Key {
43 | if let value = self[key.rawValue] as? T {
44 | return value
45 | }
46 |
47 | if let value = self[key.rawValue] {
48 | return try T(value: value)
49 | }
50 |
51 | throw InitializableError.invalidInput
52 | }
53 |
54 | }
55 |
56 | // MARK: - Array + AnyInitializable
57 |
58 | extension Array: AnyInitializable where Element == Double {
59 |
60 | init(value: Any) throws {
61 | guard let array = value as? [Double] else {
62 | throw InitializableError.invalidInput
63 | }
64 | self = array
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/Model/Extensions/Bundle.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | #if os(iOS) || os(tvOS) || os(watchOS) || targetEnvironment(macCatalyst)
3 | import UIKit
4 | #endif
5 |
6 | extension Bundle {
7 | func getAnimationData(_ name: String, subdirectory: String? = nil) throws -> Data? {
8 | // Check for files in the bundle at the given path
9 | let name = name.removingJSONSuffix()
10 | if let url = url(forResource: name, withExtension: "json", subdirectory: subdirectory) {
11 | return try Data(contentsOf: url)
12 | }
13 |
14 | // Check for data assets (not available on macOS)
15 | #if os(iOS) || os(tvOS) || os(watchOS) || targetEnvironment(macCatalyst)
16 | let assetKey = subdirectory != nil ? "\(subdirectory ?? "")/\(name)" : name
17 | return NSDataAsset(name: assetKey, bundle: self)?.data
18 | #else
19 | return nil
20 | #endif
21 | }
22 | }
23 |
24 | extension String {
25 | fileprivate func removingJSONSuffix() -> String {
26 | // Allow filenames to be passed with a ".json" extension (but not other extensions)
27 | // to keep the behavior from Lottie 2.x - instead of failing to load the animation
28 | guard hasSuffix(".json") else {
29 | return self
30 | }
31 |
32 | return (self as NSString).deletingPathExtension
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/Model/Extensions/KeyedDecodingContainerExtensions.swift:
--------------------------------------------------------------------------------
1 | // From: https://medium.com/@kewindannerfjordremeczki/swift-4-0-decodable-heterogeneous-collections-ecc0e6b468cf
2 |
3 | import Foundation
4 |
5 | // MARK: - ClassFamily
6 |
7 | /// To support a new class family, create an enum that conforms to this protocol and contains the different types.
8 | protocol ClassFamily: Decodable {
9 | /// The discriminator key.
10 | static var discriminator: Discriminator { get }
11 |
12 | /// Returns the class type of the object corresponding to the value.
13 | func getType() -> AnyObject.Type
14 | }
15 |
16 | // MARK: - Discriminator
17 |
18 | /// Discriminator key enum used to retrieve discriminator fields in JSON payloads.
19 | enum Discriminator: String, CodingKey {
20 | case type = "ty"
21 | }
22 |
23 | extension KeyedDecodingContainer {
24 |
25 | /// Decode a heterogeneous list of objects for a given family.
26 | /// - Parameters:
27 | /// - heterogeneousType: The decodable type of the list.
28 | /// - family: The ClassFamily enum for the type family.
29 | /// - key: The CodingKey to look up the list in the current container.
30 | /// - Returns: The resulting list of heterogeneousType elements.
31 | func decode(_: [T].Type, ofFamily family: U.Type, forKey key: K) throws -> [T] {
32 | var container = try nestedUnkeyedContainer(forKey: key)
33 | var list = [T]()
34 | var tmpContainer = container
35 | while !container.isAtEnd {
36 | let typeContainer = try container.nestedContainer(keyedBy: Discriminator.self)
37 | let family: U = try typeContainer.decode(U.self, forKey: U.discriminator)
38 | if let type = family.getType() as? T.Type {
39 | list.append(try tmpContainer.decode(type))
40 | }
41 | }
42 | return list
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/Model/Layers/ImageLayerModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageLayer.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/8/19.
6 | //
7 |
8 | import Foundation
9 |
10 | /// A layer that holds an image.
11 | final class ImageLayerModel: LayerModel {
12 |
13 | // MARK: Lifecycle
14 |
15 | required init(from decoder: Decoder) throws {
16 | let container = try decoder.container(keyedBy: ImageLayerModel.CodingKeys.self)
17 | referenceID = try container.decode(String.self, forKey: .referenceID)
18 | try super.init(from: decoder)
19 | }
20 |
21 | required init(dictionary: [String: Any]) throws {
22 | referenceID = try dictionary.value(for: CodingKeys.referenceID)
23 | try super.init(dictionary: dictionary)
24 | }
25 |
26 | // MARK: Internal
27 |
28 | /// The reference ID of the image.
29 | let referenceID: String
30 |
31 | override func encode(to encoder: Encoder) throws {
32 | try super.encode(to: encoder)
33 | var container = encoder.container(keyedBy: CodingKeys.self)
34 | try container.encode(referenceID, forKey: .referenceID)
35 | }
36 |
37 | // MARK: Private
38 |
39 | private enum CodingKeys: String, CodingKey {
40 | case referenceID = "refId"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/Model/Layers/ShapeLayerModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ShapeLayer.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/8/19.
6 | //
7 |
8 | import Foundation
9 |
10 | /// A layer that holds vector shape objects.
11 | final class ShapeLayerModel: LayerModel {
12 |
13 | // MARK: Lifecycle
14 |
15 | required init(from decoder: Decoder) throws {
16 | let container = try decoder.container(keyedBy: ShapeLayerModel.CodingKeys.self)
17 | items = try container.decode([ShapeItem].self, ofFamily: ShapeType.self, forKey: .items)
18 | try super.init(from: decoder)
19 | }
20 |
21 | required init(dictionary: [String: Any]) throws {
22 | let itemDictionaries: [[String: Any]] = try dictionary.value(for: CodingKeys.items)
23 | items = try [ShapeItem].fromDictionaries(itemDictionaries)
24 | try super.init(dictionary: dictionary)
25 | }
26 |
27 | // MARK: Internal
28 |
29 | /// A list of shape items.
30 | let items: [ShapeItem]
31 |
32 | override func encode(to encoder: Encoder) throws {
33 | try super.encode(to: encoder)
34 | var container = encoder.container(keyedBy: CodingKeys.self)
35 | try container.encode(items, forKey: .items)
36 | }
37 |
38 | // MARK: Private
39 |
40 | private enum CodingKeys: String, CodingKey {
41 | case items = "shapes"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/Model/Layers/SolidLayerModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SolidLayer.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/8/19.
6 | //
7 |
8 | import Foundation
9 |
10 | /// A layer that holds a solid color.
11 | final class SolidLayerModel: LayerModel {
12 |
13 | // MARK: Lifecycle
14 |
15 | required init(from decoder: Decoder) throws {
16 | let container = try decoder.container(keyedBy: SolidLayerModel.CodingKeys.self)
17 | colorHex = try container.decode(String.self, forKey: .colorHex)
18 | width = try container.decode(Double.self, forKey: .width)
19 | height = try container.decode(Double.self, forKey: .height)
20 | try super.init(from: decoder)
21 | }
22 |
23 | required init(dictionary: [String: Any]) throws {
24 | colorHex = try dictionary.value(for: CodingKeys.colorHex)
25 | width = try dictionary.value(for: CodingKeys.width)
26 | height = try dictionary.value(for: CodingKeys.height)
27 | try super.init(dictionary: dictionary)
28 | }
29 |
30 | // MARK: Internal
31 |
32 | /// The color of the solid in Hex // Change to value provider.
33 | let colorHex: String
34 |
35 | /// The Width of the color layer
36 | let width: Double
37 |
38 | /// The height of the color layer
39 | let height: Double
40 |
41 | override func encode(to encoder: Encoder) throws {
42 | try super.encode(to: encoder)
43 | var container = encoder.container(keyedBy: CodingKeys.self)
44 | try container.encode(colorHex, forKey: .colorHex)
45 | try container.encode(width, forKey: .width)
46 | try container.encode(height, forKey: .height)
47 | }
48 |
49 | // MARK: Private
50 |
51 | private enum CodingKeys: String, CodingKey {
52 | case colorHex = "sc"
53 | case width = "sw"
54 | case height = "sh"
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/Model/Layers/TextLayerModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TextLayer.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/8/19.
6 | //
7 |
8 | import Foundation
9 |
10 | /// A layer that holds text.
11 | final class TextLayerModel: LayerModel {
12 |
13 | // MARK: Lifecycle
14 |
15 | required init(from decoder: Decoder) throws {
16 | let container = try decoder.container(keyedBy: TextLayerModel.CodingKeys.self)
17 | let textContainer = try container.nestedContainer(keyedBy: TextCodingKeys.self, forKey: .textGroup)
18 | text = try textContainer.decode(KeyframeGroup.self, forKey: .text)
19 | animators = try textContainer.decode([TextAnimator].self, forKey: .animators)
20 | try super.init(from: decoder)
21 | }
22 |
23 | required init(dictionary: [String: Any]) throws {
24 | let containerDictionary: [String: Any] = try dictionary.value(for: CodingKeys.textGroup)
25 | let textDictionary: [String: Any] = try containerDictionary.value(for: TextCodingKeys.text)
26 | text = try KeyframeGroup(dictionary: textDictionary)
27 | let animatorDictionaries: [[String: Any]] = try containerDictionary.value(for: TextCodingKeys.animators)
28 | animators = try animatorDictionaries.map({ try TextAnimator(dictionary: $0) })
29 | try super.init(dictionary: dictionary)
30 | }
31 |
32 | // MARK: Internal
33 |
34 | /// The text for the layer
35 | let text: KeyframeGroup
36 |
37 | /// Text animators
38 | let animators: [TextAnimator]
39 |
40 | override func encode(to encoder: Encoder) throws {
41 | try super.encode(to: encoder)
42 | var container = encoder.container(keyedBy: CodingKeys.self)
43 | var textContainer = container.nestedContainer(keyedBy: TextCodingKeys.self, forKey: .textGroup)
44 | try textContainer.encode(text, forKey: .text)
45 | try textContainer.encode(animators, forKey: .animators)
46 | }
47 |
48 | // MARK: Private
49 |
50 | private enum CodingKeys: String, CodingKey {
51 | case textGroup = "t"
52 | }
53 |
54 | private enum TextCodingKeys: String, CodingKey {
55 | case text = "d"
56 | case animators = "a"
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/Model/Objects/DashPattern.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DashPattern.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/22/19.
6 | //
7 |
8 | import Foundation
9 |
10 | // MARK: - DashElementType
11 |
12 | enum DashElementType: String, Codable {
13 | case offset = "o"
14 | case dash = "d"
15 | case gap = "g"
16 | }
17 |
18 | // MARK: - DashElement
19 |
20 | final class DashElement: Codable, DictionaryInitializable {
21 |
22 | // MARK: Lifecycle
23 |
24 | init(dictionary: [String: Any]) throws {
25 | let typeRawValue: String = try dictionary.value(for: CodingKeys.type)
26 | guard let type = DashElementType(rawValue: typeRawValue) else {
27 | throw InitializableError.invalidInput
28 | }
29 | self.type = type
30 | let valueDictionary: [String: Any] = try dictionary.value(for: CodingKeys.value)
31 | value = try KeyframeGroup(dictionary: valueDictionary)
32 | }
33 |
34 | // MARK: Internal
35 |
36 | enum CodingKeys: String, CodingKey {
37 | case type = "n"
38 | case value = "v"
39 | }
40 |
41 | let type: DashElementType
42 | let value: KeyframeGroup
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/Model/Objects/Marker.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Marker.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/9/19.
6 | //
7 |
8 | import Foundation
9 |
10 | /// A time marker
11 | final class Marker: Codable, DictionaryInitializable {
12 |
13 | // MARK: Lifecycle
14 |
15 | init(dictionary: [String: Any]) throws {
16 | name = try dictionary.value(for: CodingKeys.name)
17 | frameTime = try dictionary.value(for: CodingKeys.frameTime)
18 | durationFrameTime = try dictionary.value(for: CodingKeys.durationFrameTime)
19 | }
20 |
21 | // MARK: Internal
22 |
23 | enum CodingKeys: String, CodingKey {
24 | case name = "cm"
25 | case frameTime = "tm"
26 | case durationFrameTime = "dr"
27 | }
28 |
29 | /// The Marker Name
30 | let name: String
31 |
32 | /// The Frame time of the marker
33 | let frameTime: AnimationFrameTime
34 |
35 | /// The duration of the marker, in frames.
36 | let durationFrameTime: AnimationFrameTime
37 | }
38 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/Model/ShapeItems/Group.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GroupItem.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/8/19.
6 | //
7 |
8 | import Foundation
9 |
10 | /// An item that define a a group of shape items
11 | final class Group: ShapeItem {
12 |
13 | // MARK: Lifecycle
14 |
15 | required init(from decoder: Decoder) throws {
16 | let container = try decoder.container(keyedBy: Group.CodingKeys.self)
17 | items = try container.decode([ShapeItem].self, ofFamily: ShapeType.self, forKey: .items)
18 | try super.init(from: decoder)
19 | }
20 |
21 | required init(dictionary: [String: Any]) throws {
22 | let itemDictionaries: [[String: Any]] = try dictionary.value(for: CodingKeys.items)
23 | items = try [ShapeItem].fromDictionaries(itemDictionaries)
24 | try super.init(dictionary: dictionary)
25 | }
26 |
27 | init(items: [ShapeItem], name: String) {
28 | self.items = items
29 | super.init(name: name, type: .group, hidden: false)
30 | }
31 |
32 | // MARK: Internal
33 |
34 | /// A list of shape items.
35 | let items: [ShapeItem]
36 |
37 | override func encode(to encoder: Encoder) throws {
38 | try super.encode(to: encoder)
39 | var container = encoder.container(keyedBy: CodingKeys.self)
40 | try container.encode(items, forKey: .items)
41 | }
42 |
43 | // MARK: Private
44 |
45 | private enum CodingKeys: String, CodingKey {
46 | case items = "it"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/Model/ShapeItems/Merge.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Merge.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/8/19.
6 | //
7 |
8 | import Foundation
9 |
10 | // MARK: - MergeMode
11 |
12 | enum MergeMode: Int, Codable {
13 | case none
14 | case merge
15 | case add
16 | case subtract
17 | case intersect
18 | case exclude
19 | }
20 |
21 | // MARK: - Merge
22 |
23 | final class Merge: ShapeItem {
24 |
25 | // MARK: Lifecycle
26 |
27 | required init(from decoder: Decoder) throws {
28 | let container = try decoder.container(keyedBy: Merge.CodingKeys.self)
29 | mode = try container.decode(MergeMode.self, forKey: .mode)
30 | try super.init(from: decoder)
31 | }
32 |
33 | required init(dictionary: [String: Any]) throws {
34 | let modeRawType: Int = try dictionary.value(for: CodingKeys.mode)
35 | guard let mode = MergeMode(rawValue: modeRawType) else {
36 | throw InitializableError.invalidInput
37 | }
38 | self.mode = mode
39 | try super.init(dictionary: dictionary)
40 | }
41 |
42 | // MARK: Internal
43 |
44 | /// The mode of the merge path
45 | let mode: MergeMode
46 |
47 | override func encode(to encoder: Encoder) throws {
48 | try super.encode(to: encoder)
49 | var container = encoder.container(keyedBy: CodingKeys.self)
50 | try container.encode(mode, forKey: .mode)
51 | }
52 |
53 | // MARK: Private
54 |
55 | private enum CodingKeys: String, CodingKey {
56 | case mode = "mm"
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/Model/ShapeItems/Shape.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VectorShape.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/8/19.
6 | //
7 |
8 | import Foundation
9 |
10 | /// An item that defines an custom shape
11 | final class Shape: ShapeItem {
12 |
13 | // MARK: Lifecycle
14 |
15 | required init(from decoder: Decoder) throws {
16 | let container = try decoder.container(keyedBy: Shape.CodingKeys.self)
17 | path = try container.decode(KeyframeGroup.self, forKey: .path)
18 | direction = try container.decodeIfPresent(PathDirection.self, forKey: .direction)
19 | try super.init(from: decoder)
20 | }
21 |
22 | required init(dictionary: [String: Any]) throws {
23 | let pathDictionary: [String: Any] = try dictionary.value(for: CodingKeys.path)
24 | path = try KeyframeGroup(dictionary: pathDictionary)
25 | if
26 | let directionRawValue = dictionary[CodingKeys.direction.rawValue] as? Int,
27 | let direction = PathDirection(rawValue: directionRawValue)
28 | {
29 | self.direction = direction
30 | } else {
31 | direction = nil
32 | }
33 | try super.init(dictionary: dictionary)
34 | }
35 |
36 | // MARK: Internal
37 |
38 | /// The Path
39 | let path: KeyframeGroup
40 |
41 | let direction: PathDirection?
42 |
43 | override func encode(to encoder: Encoder) throws {
44 | try super.encode(to: encoder)
45 | var container = encoder.container(keyedBy: CodingKeys.self)
46 | try container.encode(path, forKey: .path)
47 | try container.encodeIfPresent(direction, forKey: .direction)
48 | }
49 |
50 | // MARK: Private
51 |
52 | private enum CodingKeys: String, CodingKey {
53 | case path = "ks"
54 | case direction = "d"
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/Model/Text/Font.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Font.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/9/19.
6 | //
7 |
8 | import Foundation
9 |
10 | // MARK: - Font
11 |
12 | final class Font: Codable, DictionaryInitializable {
13 |
14 | // MARK: Lifecycle
15 |
16 | init(dictionary: [String: Any]) throws {
17 | name = try dictionary.value(for: CodingKeys.name)
18 | familyName = try dictionary.value(for: CodingKeys.familyName)
19 | style = try dictionary.value(for: CodingKeys.style)
20 | ascent = try dictionary.value(for: CodingKeys.ascent)
21 | }
22 |
23 | // MARK: Internal
24 |
25 | let name: String
26 | let familyName: String
27 | let style: String
28 | let ascent: Double
29 |
30 | // MARK: Private
31 |
32 | private enum CodingKeys: String, CodingKey {
33 | case name = "fName"
34 | case familyName = "fFamily"
35 | case style = "fStyle"
36 | case ascent
37 | }
38 |
39 | }
40 |
41 | // MARK: - FontList
42 |
43 | /// A list of fonts
44 | final class FontList: Codable, DictionaryInitializable {
45 |
46 | // MARK: Lifecycle
47 |
48 | init(dictionary: [String: Any]) throws {
49 | let fontDictionaries: [[String: Any]] = try dictionary.value(for: CodingKeys.fonts)
50 | fonts = try fontDictionaries.map({ try Font(dictionary: $0) })
51 | }
52 |
53 | // MARK: Internal
54 |
55 | enum CodingKeys: String, CodingKey {
56 | case fonts = "list"
57 | }
58 |
59 | let fonts: [Font]
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/RootAnimationLayer.swift:
--------------------------------------------------------------------------------
1 | // Created by Cal Stephens on 12/13/21.
2 | // Copyright © 2021 Airbnb Inc. All rights reserved.
3 |
4 | import QuartzCore
5 |
6 | // MARK: - RootAnimationLayer
7 |
8 | /// A root `CALayer` responsible for playing a Lottie animation
9 | protocol RootAnimationLayer: CALayer {
10 | var currentFrame: AnimationFrameTime { get set }
11 | var renderScale: CGFloat { get set }
12 | var respectAnimationFrameRate: Bool { get set }
13 |
14 | var _animationLayers: [CALayer] { get }
15 | var imageProvider: AnimationImageProvider { get set }
16 | var textProvider: AnimationTextProvider { get set }
17 | var fontProvider: AnimationFontProvider { get set }
18 |
19 | /// The `CAAnimation` key corresponding to the primary animation.
20 | /// - `LottieAnimationView` uses this key to check if the animation is still active
21 | var primaryAnimationKey: AnimationKey { get }
22 |
23 | /// Whether or not this layer is currently playing an animation
24 | /// - If the layer returns `nil`, `LottieAnimationView` determines if an animation
25 | /// is playing by checking if there is an active animation for `primaryAnimationKey`
26 | var isAnimationPlaying: Bool? { get }
27 |
28 | /// Instructs this layer to remove all `CAAnimation`s,
29 | /// other than the `CAAnimation` managed by `LottieAnimationView` (if applicable)
30 | func removeAnimations()
31 |
32 | func reloadImages()
33 | func forceDisplayUpdate()
34 | func logHierarchyKeypaths()
35 |
36 | func setValueProvider(_ valueProvider: AnyValueProvider, keypath: AnimationKeypath)
37 | func getValue(for keypath: AnimationKeypath, atFrame: AnimationFrameTime?) -> Any?
38 | func getOriginalValue(for keypath: AnimationKeypath, atFrame: AnimationFrameTime?) -> Any?
39 |
40 | func layer(for keypath: AnimationKeypath) -> CALayer?
41 | func animatorNodes(for keypath: AnimationKeypath) -> [AnimatorNode]?
42 | }
43 |
44 | // MARK: - AnimationKey
45 |
46 | enum AnimationKey {
47 | /// The primary animation and its key should be managed by `LottieAnimationView`
48 | case managed
49 | /// The primary animation always uses the given key
50 | case specific(String)
51 | }
52 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/Utility/Debugging/AnimatorNodeDebugging.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimatorNodeDebugging.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/18/19.
6 | //
7 |
8 | import Foundation
9 |
10 | extension AnimatorNode {
11 |
12 | func printNodeTree() {
13 | parentNode?.printNodeTree()
14 | LottieLogger.shared.info(String(describing: type(of: self)))
15 |
16 | if let group = self as? GroupNode {
17 | LottieLogger.shared.info("* |Children")
18 | group.rootNode?.printNodeTree()
19 | LottieLogger.shared.info("*")
20 | } else {
21 | LottieLogger.shared.info("|")
22 | }
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/Utility/Debugging/TestHelpers.swift:
--------------------------------------------------------------------------------
1 | // Created by Cal Stephens on 1/28/22.
2 | // Copyright © 2022 Airbnb Inc. All rights reserved.
3 |
4 | enum TestHelpers {
5 | /// Whether or not snapshot tests are currently running in a test target
6 | static var snapshotTestsAreRunning = false
7 |
8 | /// Whether or not performance tests are currently running in a test target
9 | static var performanceTestsAreRunning = false
10 | }
11 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/Utility/Extensions/BlendMode+Filter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // File.swift
3 | //
4 | //
5 | // Created by Denis Koryttsev on 10.05.2022.
6 | //
7 |
8 | extension BlendMode {
9 | /// The Core Image filter name for this `BlendMode`, that can be applied to a `CALayer`'s `compositingFilter`.
10 | /// Supported compositing filters are defined here: https://developer.apple.com/library/archive/documentation/GraphicsImaging/Reference/CoreImageFilterReference/index.html#//apple_ref/doc/uid/TP30000136-SW71
11 | var filterName: String? {
12 | switch self {
13 | case .normal: return nil
14 | case .multiply: return "multiplyBlendMode"
15 | case .screen: return "screenBlendMode"
16 | case .overlay: return "overlayBlendMode"
17 | case .darken: return "darkenBlendMode"
18 | case .lighten: return "lightenBlendMode"
19 | case .colorDodge: return "colorDodgeBlendMode"
20 | case .colorBurn: return "colorBurnBlendMode"
21 | case .hardLight: return "hardLightBlendMode"
22 | case .softLight: return "softLightBlendMode"
23 | case .difference: return "differenceBlendMode"
24 | case .exclusion: return "exclusionBlendMode"
25 | case .hue: return "hueBlendMode"
26 | case .saturation: return "saturationBlendMode"
27 | case .color: return "colorBlendMode"
28 | case .luminosity: return "luminosityBlendMode"
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/Utility/Extensions/CGColor+RGB.swift:
--------------------------------------------------------------------------------
1 | // Created by Cal Stephens on 1/7/22.
2 | // Copyright © 2022 Airbnb Inc. All rights reserved.
3 |
4 | import QuartzCore
5 |
6 | extension CGColor {
7 | /// Initializes a `CGColor` using the given `RGB` values
8 | static func rgb(_ red: CGFloat, _ green: CGFloat, _ blue: CGFloat) -> CGColor {
9 | if #available(iOS 13.0, tvOS 13.0, macOS 10.5, *) {
10 | return CGColor(red: red, green: green, blue: blue, alpha: 1)
11 | } else {
12 | return CGColor(
13 | colorSpace: CGColorSpaceCreateDeviceRGB(),
14 | components: [red, green, blue])!
15 | }
16 | }
17 |
18 | /// Initializes a `CGColor` using the given `RGBA` values
19 | static func rgba(_ red: CGFloat, _ green: CGFloat, _ blue: CGFloat, _ alpha: CGFloat) -> CGColor {
20 | CGColor.rgb(red, green, blue).copy(alpha: alpha)!
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/Utility/Extensions/DataExtension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DataExtension.swift
3 | // Lottie
4 | //
5 | // Created by René Fouquet on 03.05.21.
6 | //
7 |
8 | import Foundation
9 | #if canImport(UIKit)
10 | import UIKit
11 | #elseif canImport(AppKit)
12 | import AppKit
13 | #endif
14 |
15 | extension Data {
16 |
17 | static func jsonData(from assetName: String, in bundle: Bundle) -> Data? {
18 | #if canImport(UIKit)
19 | return NSDataAsset(name: assetName, bundle: bundle)?.data
20 | #else
21 | if #available(macOS 10.11, *) {
22 | return NSDataAsset(name: assetName, bundle: bundle)?.data
23 | }
24 | return nil
25 | #endif
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/Utility/Extensions/StringExtensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StringExtensions.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/25/19.
6 | //
7 |
8 | import CoreGraphics
9 | import Foundation
10 |
11 | extension String {
12 |
13 | var cgColor: CGColor {
14 | let (red, green, blue) = hexColorComponents()
15 | return .rgb(red, green, blue)
16 | }
17 |
18 | func hexColorComponents() -> (red: CGFloat, green: CGFloat, blue: CGFloat) {
19 | var cString: String = trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
20 |
21 | if cString.hasPrefix("#") {
22 | cString.remove(at: cString.startIndex)
23 | }
24 |
25 | if (cString.count) != 6 {
26 | return (red: 0, green: 0, blue: 0)
27 | }
28 |
29 | var rgbValue: UInt64 = 0
30 | Scanner(string: cString).scanHexInt64(&rgbValue)
31 |
32 | return (
33 | red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
34 | green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
35 | blue: CGFloat(rgbValue & 0x0000FF) / 255.0)
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/Utility/Interpolatable/KeyframeExtensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // KeyframeExtensions.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/14/19.
6 | //
7 |
8 | import CoreGraphics
9 | import Foundation
10 |
11 | extension Keyframe where T: AnyInterpolatable {
12 | func interpolate(to: Keyframe, progress: CGFloat) -> T {
13 | value._interpolate(
14 | to: to.value,
15 | amount: progress,
16 | spatialOutTangent: spatialOutTangent?.pointValue,
17 | spatialInTangent: to.spatialInTangent?.pointValue)
18 | }
19 | }
20 |
21 | extension Keyframe {
22 | /// Interpolates the keyTime into a value from 0-1
23 | func interpolatedProgress(_ to: Keyframe, keyTime: CGFloat) -> CGFloat {
24 | let startTime = time
25 | let endTime = to.time
26 | if keyTime <= startTime {
27 | return 0
28 | }
29 | if endTime <= keyTime {
30 | return 1
31 | }
32 |
33 | if isHold {
34 | return 0
35 | }
36 |
37 | let outTanPoint = outTangent?.pointValue ?? .zero
38 | let inTanPoint = to.inTangent?.pointValue ?? CGPoint(x: 1, y: 1)
39 | var progress: CGFloat = keyTime.remap(fromLow: startTime, fromHigh: endTime, toLow: 0, toHigh: 1)
40 | if !outTanPoint.isZero || !inTanPoint.equalTo(CGPoint(x: 1, y: 1)) {
41 | /// Cubic interpolation
42 | progress = progress.cubicBezierInterpolate(.zero, outTanPoint, inTanPoint, CGPoint(x: 1, y: 1))
43 | }
44 | return progress
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Private/Utility/Primitives/CGPointExtension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CGPointExtension.swift
3 | // Lottie
4 | //
5 | // Created by Marcelo Fabri on 5/5/22.
6 | //
7 |
8 | import CoreGraphics
9 |
10 | extension CGPoint: AnyInitializable {
11 |
12 | // MARK: Lifecycle
13 |
14 | init(value: Any) throws {
15 | if let dictionary = value as? [String: CGFloat] {
16 | let x: CGFloat = try dictionary.value(for: CodingKeys.x)
17 | let y: CGFloat = try dictionary.value(for: CodingKeys.y)
18 | self.init(x: x, y: y)
19 | } else if
20 | let array = value as? [CGFloat],
21 | array.count > 1
22 | {
23 | self.init(x: array[0], y: array[1])
24 | } else {
25 | throw InitializableError.invalidInput
26 | }
27 | }
28 |
29 | // MARK: Private
30 |
31 | private enum CodingKeys: String {
32 | case x
33 | case y
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Public/AnimationCache/AnimationCacheProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimationCacheProvider.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 2/5/19.
6 | //
7 |
8 | import Foundation
9 | /// `AnimationCacheProvider` is a protocol that describes an Animation Cache.
10 | /// Animation Cache is used when loading `LottieAnimation` models. Using an Animation Cache
11 | /// can increase performance when loading an animation multiple times.
12 | ///
13 | /// Lottie comes with a prebuilt LRU Animation Cache.
14 | public protocol AnimationCacheProvider {
15 |
16 | func animation(forKey: String) -> LottieAnimation?
17 |
18 | func setAnimation(_ animation: LottieAnimation, forKey: String)
19 |
20 | func clearCache()
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Public/AnimationCache/LRUAnimationCache.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LRUAnimationCache.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 2/5/19.
6 | //
7 |
8 | import Foundation
9 |
10 | /// An Animation Cache that will store animations up to `cacheSize`.
11 | ///
12 | /// Once `cacheSize` is reached, the least recently used animation will be ejected.
13 | /// The default size of the cache is 100.
14 | public class LRUAnimationCache: AnimationCacheProvider {
15 |
16 | // MARK: Lifecycle
17 |
18 | public init() { }
19 |
20 | // MARK: Public
21 |
22 | /// The global shared Cache.
23 | public static let sharedCache = LRUAnimationCache()
24 |
25 | /// The size of the cache.
26 | public var cacheSize = 100
27 |
28 | /// Clears the Cache.
29 | public func clearCache() {
30 | cacheMap.removeAll()
31 | lruList.removeAll()
32 | }
33 |
34 | public func animation(forKey: String) -> LottieAnimation? {
35 | guard let animation = cacheMap[forKey] else {
36 | return nil
37 | }
38 | if let index = lruList.firstIndex(of: forKey) {
39 | lruList.remove(at: index)
40 | lruList.append(forKey)
41 | }
42 | return animation
43 | }
44 |
45 | public func setAnimation(_ animation: LottieAnimation, forKey: String) {
46 | cacheMap[forKey] = animation
47 | lruList.append(forKey)
48 | if lruList.count > cacheSize {
49 | let removed = lruList.remove(at: 0)
50 | if removed != forKey {
51 | cacheMap[removed] = nil
52 | }
53 | }
54 | }
55 |
56 | // MARK: Fileprivate
57 |
58 | fileprivate var cacheMap: [String: LottieAnimation] = [:]
59 | fileprivate var lruList: [String] = []
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Public/DynamicProperties/AnimationKeypath.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimationKeypath.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 2/4/19.
6 | //
7 |
8 | import Foundation
9 |
10 | /// `AnimationKeypath` is an object that describes a keypath search for nodes in the
11 | /// animation JSON. `AnimationKeypath` matches views and properties inside of `LottieAnimationView`
12 | /// to their backing `LottieAnimation` model by name.
13 | ///
14 | /// A keypath can be used to set properties on an existing animation, or can be validated
15 | /// with an existing `LottieAnimation`.
16 | ///
17 | /// `AnimationKeypath` can describe a specific object, or can use wildcards for fuzzy matching
18 | /// of objects. Acceptable wildcards are either "*" (star) or "**" (double star).
19 | /// Single star will search a single depth for the next object.
20 | /// Double star will search any depth.
21 | ///
22 | /// Read More at https://airbnb.io/lottie/#/ios?id=dynamic-animation-properties
23 | ///
24 | /// EG:
25 | /// @"Layer.Shape Group.Stroke 1.Color"
26 | /// Represents a specific color node on a specific stroke.
27 | ///
28 | /// @"**.Stroke 1.Color"
29 | /// Represents the color node for every Stroke named "Stroke 1" in the animation.
30 | public struct AnimationKeypath: Hashable, ExpressibleByStringLiteral {
31 |
32 | /// Creates a keypath from a dot-separated string. The string is separated by "."
33 | public init(keypath: String) {
34 | keys = keypath.components(separatedBy: ".")
35 | }
36 |
37 | /// Creates a keypath from a dot-separated string
38 | public init(stringLiteral: String) {
39 | self.init(keypath: stringLiteral)
40 | }
41 |
42 | /// Creates a keypath from a list of strings.
43 | public init(keys: [String]) {
44 | self.keys = keys
45 | }
46 |
47 | var keys: [String]
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Public/DynamicProperties/ValueProviders/ColorValueProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ColorValueProvider.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 2/4/19.
6 | //
7 |
8 | import CoreGraphics
9 | import Foundation
10 |
11 | /// A `ValueProvider` that returns a CGColor Value
12 | public final class ColorValueProvider: ValueProvider {
13 |
14 | // MARK: Lifecycle
15 |
16 | /// Initializes with a block provider
17 | public init(block: @escaping ColorValueBlock) {
18 | self.block = block
19 | color = LottieColor(r: 0, g: 0, b: 0, a: 1)
20 | keyframes = nil
21 | }
22 |
23 | /// Initializes with a single color.
24 | public init(_ color: LottieColor) {
25 | self.color = color
26 | block = nil
27 | keyframes = nil
28 | hasUpdate = true
29 | }
30 |
31 | /// Initializes with multiple colors, with timing information
32 | public init(_ keyframes: [Keyframe]) {
33 | self.keyframes = keyframes
34 | color = LottieColor(r: 0, g: 0, b: 0, a: 1)
35 | block = nil
36 | hasUpdate = true
37 | }
38 |
39 | // MARK: Public
40 |
41 | /// Returns a LottieColor for a CGColor(Frame Time)
42 | public typealias ColorValueBlock = (CGFloat) -> LottieColor
43 |
44 | /// The color value of the provider.
45 | public var color: LottieColor {
46 | didSet {
47 | hasUpdate = true
48 | }
49 | }
50 |
51 | // MARK: ValueProvider Protocol
52 |
53 | public var valueType: Any.Type {
54 | LottieColor.self
55 | }
56 |
57 | public var storage: ValueProviderStorage {
58 | if let block = block {
59 | return .closure { frame in
60 | self.hasUpdate = false
61 | return block(frame)
62 | }
63 | } else if let keyframes = keyframes {
64 | return .keyframes(keyframes)
65 | } else {
66 | hasUpdate = false
67 | return .singleValue(color)
68 | }
69 | }
70 |
71 | public func hasUpdate(frame _: CGFloat) -> Bool {
72 | if block != nil {
73 | return true
74 | }
75 | return hasUpdate
76 | }
77 |
78 | // MARK: Private
79 |
80 | private var hasUpdate = true
81 |
82 | private var block: ColorValueBlock?
83 | private var keyframes: [Keyframe]?
84 | }
85 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Public/DynamicProperties/ValueProviders/FloatValueProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DoubleValueProvider.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 2/4/19.
6 | //
7 |
8 | import CoreGraphics
9 | import Foundation
10 |
11 | /// A `ValueProvider` that returns a CGFloat Value
12 | public final class FloatValueProvider: ValueProvider {
13 |
14 | // MARK: Lifecycle
15 |
16 | /// Initializes with a block provider
17 | public init(block: @escaping CGFloatValueBlock) {
18 | self.block = block
19 | float = 0
20 | }
21 |
22 | /// Initializes with a single float.
23 | public init(_ float: CGFloat) {
24 | self.float = float
25 | block = nil
26 | hasUpdate = true
27 | }
28 |
29 | // MARK: Public
30 |
31 | /// Returns a CGFloat for a CGFloat(Frame Time)
32 | public typealias CGFloatValueBlock = (CGFloat) -> CGFloat
33 |
34 | public var float: CGFloat {
35 | didSet {
36 | hasUpdate = true
37 | }
38 | }
39 |
40 | // MARK: ValueProvider Protocol
41 |
42 | public var valueType: Any.Type {
43 | LottieVector1D.self
44 | }
45 |
46 | public var storage: ValueProviderStorage {
47 | if let block = block {
48 | return .closure { frame in
49 | self.hasUpdate = false
50 | return LottieVector1D(Double(block(frame)))
51 | }
52 | } else {
53 | hasUpdate = false
54 | return .singleValue(LottieVector1D(Double(float)))
55 | }
56 | }
57 |
58 | public func hasUpdate(frame _: CGFloat) -> Bool {
59 | if block != nil {
60 | return true
61 | }
62 | return hasUpdate
63 | }
64 |
65 | // MARK: Private
66 |
67 | private var hasUpdate = true
68 |
69 | private var block: CGFloatValueBlock?
70 | }
71 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Public/DynamicProperties/ValueProviders/PointValueProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PointValueProvider.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 2/4/19.
6 | //
7 |
8 | import CoreGraphics
9 | import Foundation
10 | /// A `ValueProvider` that returns a CGPoint Value
11 | public final class PointValueProvider: ValueProvider {
12 |
13 | // MARK: Lifecycle
14 |
15 | /// Initializes with a block provider
16 | public init(block: @escaping PointValueBlock) {
17 | self.block = block
18 | point = .zero
19 | }
20 |
21 | /// Initializes with a single point.
22 | public init(_ point: CGPoint) {
23 | self.point = point
24 | block = nil
25 | hasUpdate = true
26 | }
27 |
28 | // MARK: Public
29 |
30 | /// Returns a CGPoint for a CGFloat(Frame Time)
31 | public typealias PointValueBlock = (CGFloat) -> CGPoint
32 |
33 | public var point: CGPoint {
34 | didSet {
35 | hasUpdate = true
36 | }
37 | }
38 |
39 | // MARK: ValueProvider Protocol
40 |
41 | public var valueType: Any.Type {
42 | LottieVector3D.self
43 | }
44 |
45 | public var storage: ValueProviderStorage {
46 | if let block = block {
47 | return .closure { frame in
48 | self.hasUpdate = false
49 | return block(frame).vector3dValue
50 | }
51 | } else {
52 | hasUpdate = false
53 | return .singleValue(point.vector3dValue)
54 | }
55 | }
56 |
57 | public func hasUpdate(frame _: CGFloat) -> Bool {
58 | if block != nil {
59 | return true
60 | }
61 | return hasUpdate
62 | }
63 |
64 | // MARK: Private
65 |
66 | private var hasUpdate = true
67 |
68 | private var block: PointValueBlock?
69 | }
70 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Public/DynamicProperties/ValueProviders/SizeValueProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SizeValueProvider.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 2/4/19.
6 | //
7 |
8 | import CoreGraphics
9 | import Foundation
10 |
11 | /// A `ValueProvider` that returns a CGSize Value
12 | public final class SizeValueProvider: ValueProvider {
13 |
14 | // MARK: Lifecycle
15 |
16 | /// Initializes with a block provider
17 | public init(block: @escaping SizeValueBlock) {
18 | self.block = block
19 | size = .zero
20 | }
21 |
22 | /// Initializes with a single size.
23 | public init(_ size: CGSize) {
24 | self.size = size
25 | block = nil
26 | hasUpdate = true
27 | }
28 |
29 | // MARK: Public
30 |
31 | /// Returns a CGSize for a CGFloat(Frame Time)
32 | public typealias SizeValueBlock = (CGFloat) -> CGSize
33 |
34 | public var size: CGSize {
35 | didSet {
36 | hasUpdate = true
37 | }
38 | }
39 |
40 | // MARK: ValueProvider Protocol
41 |
42 | public var valueType: Any.Type {
43 | LottieVector3D.self
44 | }
45 |
46 | public var storage: ValueProviderStorage {
47 | if let block = block {
48 | return .closure { frame in
49 | self.hasUpdate = false
50 | return block(frame).vector3dValue
51 | }
52 | } else {
53 | hasUpdate = false
54 | return .singleValue(size.vector3dValue)
55 | }
56 | }
57 |
58 | public func hasUpdate(frame _: CGFloat) -> Bool {
59 | if block != nil {
60 | return true
61 | }
62 | return hasUpdate
63 | }
64 |
65 | // MARK: Private
66 |
67 | private var hasUpdate = true
68 |
69 | private var block: SizeValueBlock?
70 | }
71 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Public/FontProvider/AnimationFontProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimationFontProvider.swift
3 | // Lottie
4 | //
5 | // Created by Brandon Withrow on 8/5/20.
6 | // Copyright © 2020 YurtvilleProds. All rights reserved.
7 | //
8 |
9 | import CoreGraphics
10 | import CoreText
11 | import Foundation
12 |
13 | // MARK: - AnimationFontProvider
14 |
15 | /// Font provider is a protocol that is used to supply fonts to `LottieAnimationView`.
16 | ///
17 | public protocol AnimationFontProvider {
18 | func fontFor(family: String, size: CGFloat) -> CTFont?
19 | }
20 |
21 | // MARK: - DefaultFontProvider
22 |
23 | /// Default Font provider.
24 | public final class DefaultFontProvider: AnimationFontProvider {
25 |
26 | // MARK: Lifecycle
27 |
28 | public init() { }
29 |
30 | // MARK: Public
31 |
32 | public func fontFor(family: String, size: CGFloat) -> CTFont? {
33 | CTFontCreateWithName(family as CFString, size, nil)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Public/ImageProvider/AnimationImageProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LottieImageProvider.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 1/25/19.
6 | //
7 |
8 | import CoreGraphics
9 | import Foundation
10 |
11 | /// Image provider is a protocol that is used to supply images to `LottieAnimationView`.
12 | ///
13 | /// Some animations require a reference to an image. The image provider loads and
14 | /// provides those images to the `LottieAnimationView`. Lottie includes a couple of
15 | /// prebuilt Image Providers that supply images from a Bundle, or from a FilePath.
16 | ///
17 | /// Additionally custom Image Providers can be made to load images from a URL,
18 | /// or to Cache images.
19 | public protocol AnimationImageProvider {
20 | func imageForAsset(asset: ImageAsset) -> CGImage?
21 | }
22 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Public/Primitives/AnimationTime.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimationTime.swift
3 | // lottie-swift-iOS
4 | //
5 | // Created by Brandon Withrow on 2/6/19.
6 | //
7 |
8 | import CoreGraphics
9 | import Foundation
10 |
11 | /// Defines animation time in Frames (Seconds * Framerate).
12 | public typealias AnimationFrameTime = CGFloat
13 |
14 | /// Defines animation time by a progress from 0 (beginning of the animation) to 1 (end of the animation)
15 | public typealias AnimationProgressTime = CGFloat
16 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Public/Primitives/LottieColor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LottieColor.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 2/4/19.
6 | //
7 |
8 | import Foundation
9 |
10 | // MARK: - ColorFormatDenominator
11 |
12 | public enum ColorFormatDenominator: Hashable {
13 | case One
14 | case OneHundred
15 | case TwoFiftyFive
16 |
17 | var value: Double {
18 | switch self {
19 | case .One:
20 | return 1.0
21 | case .OneHundred:
22 | return 100.0
23 | case .TwoFiftyFive:
24 | return 255.0
25 | }
26 | }
27 | }
28 |
29 | // MARK: - Color
30 |
31 | @available(*, deprecated, renamed: "LottieColor", message: """
32 | `Lottie.Color` has been renamed to `LottieColor`, to prevent conflicts with \
33 | the `SwiftUI.Color` type. This notice will be removed in Lottie 4.0.
34 | """)
35 | public typealias Color = LottieColor
36 |
37 | // MARK: - LottieColor
38 |
39 | public struct LottieColor: Hashable {
40 |
41 | public var r: Double
42 | public var g: Double
43 | public var b: Double
44 | public var a: Double
45 |
46 | public init(r: Double, g: Double, b: Double, a: Double, denominator: ColorFormatDenominator = .One) {
47 | self.r = r / denominator.value
48 | self.g = g / denominator.value
49 | self.b = b / denominator.value
50 | self.a = a / denominator.value
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Public/Primitives/Vectors.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Vectors.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 2/4/19.
6 | //
7 |
8 | import Foundation
9 |
10 | // MARK: - Vector1D
11 |
12 | @available(*, deprecated, renamed: "LottieVector1D", message: """
13 | `Lottie.Vector1D` has been renamed to `LottieVector1D` for consistency with \
14 | the new `LottieVector3D` type. This notice will be removed in Lottie 4.0.
15 | """)
16 | public typealias Vector1D = LottieVector1D
17 |
18 | // MARK: - LottieVector1D
19 |
20 | public struct LottieVector1D: Hashable {
21 |
22 | public init(_ value: Double) {
23 | self.value = value
24 | }
25 |
26 | public let value: Double
27 |
28 | }
29 |
30 | // MARK: - Vector3D
31 |
32 | @available(*, deprecated, renamed: "LottieVector3D", message: """
33 | `Lottie.Vector3D` has been renamed to `LottieVector3D`, to prevent conflicts with \
34 | the Apple SDK `Spatial.Vector3D` type. This notice will be removed in Lottie 4.0.
35 | """)
36 | public typealias Vector3D = LottieVector3D
37 |
38 | // MARK: - LottieVector3D
39 |
40 | /// A three dimensional vector.
41 | /// These vectors are encoded and decoded from [Double]
42 | public struct LottieVector3D: Hashable {
43 |
44 | public let x: Double
45 | public let y: Double
46 | public let z: Double
47 |
48 | public init(x: Double, y: Double, z: Double) {
49 | self.x = x
50 | self.y = y
51 | self.z = z
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Public/TextProvider/AnimationTextProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimationImageProvider.swift
3 | // Lottie_iOS
4 | //
5 | // Created by Alexandr Goncharov on 07/06/2019.
6 | //
7 |
8 | import Foundation
9 |
10 | // MARK: - AnimationTextProvider
11 |
12 | /// Text provider is a protocol that is used to supply text to `LottieAnimationView`.
13 | public protocol AnimationTextProvider: AnyObject {
14 | func textFor(keypathName: String, sourceText: String) -> String
15 | }
16 |
17 | // MARK: - DictionaryTextProvider
18 |
19 | /// Text provider that simply map values from dictionary
20 | public final class DictionaryTextProvider: AnimationTextProvider {
21 |
22 | // MARK: Lifecycle
23 |
24 | public init(_ values: [String: String]) {
25 | self.values = values
26 | }
27 |
28 | // MARK: Public
29 |
30 | public func textFor(keypathName: String, sourceText: String) -> String {
31 | values[keypathName] ?? sourceText
32 | }
33 |
34 | // MARK: Internal
35 |
36 | let values: [String: String]
37 | }
38 |
39 | // MARK: - DefaultTextProvider
40 |
41 | /// Default text provider. Uses text in the animation file
42 | public final class DefaultTextProvider: AnimationTextProvider {
43 |
44 | // MARK: Lifecycle
45 |
46 | public init() { }
47 |
48 | // MARK: Public
49 |
50 | public func textFor(keypathName _: String, sourceText: String) -> String {
51 | sourceText
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Public/iOS/AnimationSubview.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimationSubview.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 2/4/19.
6 | //
7 |
8 | import Foundation
9 | #if os(iOS) || os(tvOS) || os(watchOS) || targetEnvironment(macCatalyst)
10 | import UIKit
11 |
12 | /// A view that can be added to a keypath of an AnimationView
13 | public final class AnimationSubview: UIView {
14 |
15 | var viewLayer: CALayer? {
16 | layer
17 | }
18 |
19 | }
20 | #endif
21 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Public/iOS/Compatibility/CompatibleAnimationKeypath.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CompatibleAnimationKeypath.swift
3 | // Lottie_iOS
4 | //
5 | // Created by Tyler Hedrick on 3/6/19.
6 | //
7 |
8 | import Foundation
9 | #if os(iOS) || os(tvOS) || os(watchOS) || targetEnvironment(macCatalyst)
10 |
11 | /// An Objective-C compatible wrapper around Lottie's AnimationKeypath
12 | @objc
13 | public final class CompatibleAnimationKeypath: NSObject {
14 |
15 | // MARK: Lifecycle
16 |
17 | /// Creates a keypath from a dot separated string. The string is separated by "."
18 | @objc
19 | public init(keypath: String) {
20 | animationKeypath = AnimationKeypath(keypath: keypath)
21 | }
22 |
23 | /// Creates a keypath from a list of strings.
24 | @objc
25 | public init(keys: [String]) {
26 | animationKeypath = AnimationKeypath(keys: keys)
27 | }
28 |
29 | // MARK: Public
30 |
31 | public let animationKeypath: AnimationKeypath
32 | }
33 | #endif
34 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Public/iOS/FilepathImageProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FilepathImageProvider.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 2/1/19.
6 | //
7 |
8 | import Foundation
9 | #if os(iOS) || os(tvOS) || os(watchOS) || targetEnvironment(macCatalyst)
10 | import UIKit
11 |
12 | /// Provides an image for a lottie animation from a provided Bundle.
13 | public class FilepathImageProvider: AnimationImageProvider {
14 |
15 | // MARK: Lifecycle
16 |
17 | /// Initializes an image provider with a specific filepath.
18 | ///
19 | /// - Parameter filepath: The absolute filepath containing the images.
20 | ///
21 | public init(filepath: String) {
22 | self.filepath = URL(fileURLWithPath: filepath)
23 | }
24 |
25 | public init(filepath: URL) {
26 | self.filepath = filepath
27 | }
28 |
29 | // MARK: Public
30 |
31 | public func imageForAsset(asset: ImageAsset) -> CGImage? {
32 | if
33 | asset.name.hasPrefix("data:"),
34 | let url = URL(string: asset.name),
35 | let data = try? Data(contentsOf: url),
36 | let image = UIImage(data: data)
37 | {
38 | return image.cgImage
39 | }
40 |
41 | let directPath = filepath.appendingPathComponent(asset.name).path
42 | if FileManager.default.fileExists(atPath: directPath) {
43 | return UIImage(contentsOfFile: directPath)?.cgImage
44 | }
45 |
46 | let pathWithDirectory = filepath.appendingPathComponent(asset.directory).appendingPathComponent(asset.name).path
47 | if FileManager.default.fileExists(atPath: pathWithDirectory) {
48 | return UIImage(contentsOfFile: pathWithDirectory)?.cgImage
49 | }
50 |
51 | // 注释你,真烦人
52 | // LottieLogger.shared.warn("Could not find image \"\(asset.name)\" in bundle \(pathWithDirectory)")
53 | return nil
54 | }
55 |
56 | // MARK: Internal
57 |
58 | let filepath: URL
59 | }
60 | #endif
61 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Public/iOS/LottieAnimationViewBase.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LottieAnimationViewBase.swift
3 | // lottie-swift-iOS
4 | //
5 | // Created by Brandon Withrow on 2/6/19.
6 | //
7 |
8 | #if os(iOS) || os(tvOS) || os(watchOS) || targetEnvironment(macCatalyst)
9 | import UIKit
10 |
11 | /// The base view for `LottieAnimationView` on iOS, tvOS, watchOS, and macCatalyst.
12 | ///
13 | /// Enables the `LottieAnimationView` implementation to be shared across platforms.
14 | public class LottieAnimationViewBase: UIView {
15 |
16 | // MARK: Public
17 |
18 | public override var contentMode: UIView.ContentMode {
19 | didSet {
20 | setNeedsLayout()
21 | }
22 | }
23 |
24 | public override func didMoveToWindow() {
25 | super.didMoveToWindow()
26 | animationMovedToWindow()
27 | }
28 |
29 | public override func layoutSubviews() {
30 | super.layoutSubviews()
31 | layoutAnimation()
32 | }
33 |
34 | // MARK: Internal
35 |
36 | var viewLayer: CALayer? {
37 | layer
38 | }
39 |
40 | var screenScale: CGFloat {
41 | UIScreen.main.scale
42 | }
43 |
44 | func layoutAnimation() {
45 | // Implemented by subclasses.
46 | }
47 |
48 | func animationMovedToWindow() {
49 | // Implemented by subclasses.
50 | }
51 |
52 | func commonInit() {
53 | contentMode = .scaleAspectFit
54 | clipsToBounds = true
55 | NotificationCenter.default.addObserver(
56 | self,
57 | selector: #selector(animationWillEnterForeground),
58 | name: UIApplication.willEnterForegroundNotification,
59 | object: nil)
60 | NotificationCenter.default.addObserver(
61 | self,
62 | selector: #selector(animationWillMoveToBackground),
63 | name: UIApplication.didEnterBackgroundNotification,
64 | object: nil)
65 | }
66 |
67 | @objc
68 | func animationWillMoveToBackground() {
69 | // Implemented by subclasses.
70 | }
71 |
72 | @objc
73 | func animationWillEnterForeground() {
74 | // Implemented by subclasses.
75 | }
76 |
77 | }
78 | #endif
79 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/lottie/Public/iOS/UIColorExtension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIColorExtension.swift
3 | // lottie-swift
4 | //
5 | // Created by Brandon Withrow on 2/4/19.
6 | //
7 |
8 | import Foundation
9 | #if os(iOS) || os(tvOS) || os(watchOS) || targetEnvironment(macCatalyst)
10 | import UIKit
11 |
12 | extension UIColor {
13 |
14 | public var lottieColorValue: LottieColor {
15 | var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
16 | getRed(&r, green: &g, blue: &b, alpha: &a)
17 | return LottieColor(r: Double(r), g: Double(g), b: Double(b), a: Double(a))
18 | }
19 |
20 | }
21 | #endif
22 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/ColorPickerClasses/ANImageBitmapRep/Compatibility/NSImage+ANImageBitmapRep.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSImage+ANImageBitmapRep.h
3 | // ImageBitmapRep
4 | //
5 | // Created by Alex Nichol on 10/23/11.
6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "TargetConditionals.h"
10 |
11 | #if TARGET_OS_IPHONE != 1
12 |
13 | #import
14 |
15 | @class ANImageBitmapRep;
16 |
17 | @interface NSImage (ANImageBitmapRep)
18 |
19 | #if __has_feature(objc_arc) == 1
20 | + (NSImage *)imageFromImageBitmapRep:(ANImageBitmapRep *)ibr __attribute__((ns_returns_autoreleased));
21 | - (ANImageBitmapRep *)imageBitmapRep __attribute__((ns_returns_autoreleased));
22 | - (NSImage *)imageByScalingToSize:(CGSize)sz __attribute__((ns_returns_autoreleased));
23 | - (NSImage *)imageFittingFrame:(CGSize)sz __attribute__((ns_returns_autoreleased));
24 | - (NSImage *)imageFillingFrame:(CGSize)sz __attribute__((ns_returns_autoreleased));
25 | #else
26 | + (NSImage *)imageFromImageBitmapRep:(ANImageBitmapRep *)ibr;
27 | - (ANImageBitmapRep *)imageBitmapRep;
28 | - (NSImage *)imageByScalingToSize:(CGSize)sz;
29 | - (NSImage *)imageFittingFrame:(CGSize)sz;
30 | - (NSImage *)imageFillingFrame:(CGSize)sz;
31 | #endif
32 |
33 | @end
34 |
35 | #endif
36 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/ColorPickerClasses/ANImageBitmapRep/Compatibility/NSImage+ANImageBitmapRep.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSImage+ANImageBitmapRep.m
3 | // ImageBitmapRep
4 | //
5 | // Created by Alex Nichol on 10/23/11.
6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "TargetConditionals.h"
10 |
11 | #if TARGET_OS_IPHONE != 1
12 |
13 | #import "NSImage+ANImageBitmapRep.h"
14 | #import "ANImageBitmapRep.h"
15 |
16 | @implementation NSImage (ANImageBitmapRep)
17 |
18 |
19 | + (NSImage *)imageFromImageBitmapRep:(ANImageBitmapRep *)ibr {
20 | return [ibr image];
21 | }
22 |
23 | - (ANImageBitmapRep *)imageBitmapRep {
24 | #if __has_feature(objc_arc) == 1
25 | return [[ANImageBitmapRep alloc] initWithImage:self];
26 | #else
27 | return [[[ANImageBitmapRep alloc] initWithImage:self] autorelease];
28 | #endif
29 | }
30 |
31 | - (NSImage *)imageByScalingToSize:(CGSize)sz {
32 | ANImageBitmapRep * imageBitmap = [[ANImageBitmapRep alloc] initWithImage:self];
33 | [imageBitmap setSize:BMPointMake(round(sz.width), round(sz.height))];
34 | NSImage * scaled = [imageBitmap image];
35 | #if __has_feature(objc_arc) != 1
36 | [imageBitmap release];
37 | #endif
38 | return scaled;
39 | }
40 |
41 | - (NSImage *)imageFittingFrame:(CGSize)sz {
42 | ANImageBitmapRep * imageBitmap = [[ANImageBitmapRep alloc] initWithImage:self];
43 | [imageBitmap setSizeFittingFrame:BMPointMake(round(sz.width), round(sz.height))];
44 | NSImage * scaled = [imageBitmap image];
45 | #if __has_feature(objc_arc) != 1
46 | [imageBitmap release];
47 | #endif
48 | return scaled;
49 | }
50 |
51 | - (NSImage *)imageFillingFrame:(CGSize)sz {
52 | ANImageBitmapRep * imageBitmap = [[ANImageBitmapRep alloc] initWithImage:self];
53 | [imageBitmap setSizeFillingFrame:BMPointMake(round(sz.width), round(sz.height))];
54 | NSImage * scaled = [imageBitmap image];
55 | #if __has_feature(objc_arc) != 1
56 | [imageBitmap release];
57 | #endif
58 | return scaled;
59 | }
60 |
61 | @end
62 |
63 | #endif
64 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/ColorPickerClasses/ANImageBitmapRep/Compatibility/OSCommonImage.h:
--------------------------------------------------------------------------------
1 | //
2 | // OSCommonImage.h
3 | // ImageBitmapRep
4 | //
5 | // Created by Alex Nichol on 10/23/11.
6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #ifndef ImageBitmapRep_OSCommonImage_h
10 | #define ImageBitmapRep_OSCommonImage_h
11 |
12 | #import "TargetConditionals.h"
13 | #import "CGImageContainer.h"
14 |
15 | #if TARGET_OS_IPHONE
16 | #import
17 | typedef UIImage ANImageObj;
18 | #elif TARGET_OS_MAC
19 | #import
20 | typedef NSImage ANImageObj;
21 | #endif
22 |
23 | CGImageRef CGImageFromANImage (ANImageObj * anImageObj);
24 | ANImageObj * ANImageFromCGImage (CGImageRef imageRef);
25 |
26 | #endif
27 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/ColorPickerClasses/ANImageBitmapRep/Compatibility/OSCommonImage.m:
--------------------------------------------------------------------------------
1 | //
2 | // OSCommonImage.c
3 | // ImageBitmapRep
4 | //
5 | // Created by Alex Nichol on 10/23/11.
6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #include "OSCommonImage.h"
10 |
11 | CGImageRef CGImageFromANImage (ANImageObj * anImageObj) {
12 | #if TARGET_OS_IPHONE
13 | return [anImageObj CGImage];
14 | #elif TARGET_OS_MAC
15 | CGImageSourceRef source;
16 | #if __has_feature(objc_arc) == 1
17 | source = CGImageSourceCreateWithData((__bridge CFDataRef)[anImageObj TIFFRepresentation], NULL);
18 | #else
19 | source = CGImageSourceCreateWithData((CFDataRef)[anImageObj TIFFRepresentation], NULL);
20 | #endif
21 | CGImageRef maskRef = CGImageSourceCreateImageAtIndex(source, 0, NULL);
22 | CFRelease(source);
23 | #if __has_feature(objc_arc) == 1
24 | CGImageRef autoreleased = (__bridge CGImageRef)CGImageReturnAutoreleased(maskRef);
25 | CGImageRelease(maskRef);
26 | return autoreleased;
27 | #else
28 | CGImageContainer * container = [CGImageContainer imageContainerWithImage:maskRef];
29 | CGImageRelease(maskRef);
30 | return [container image];
31 | #endif
32 | #endif
33 | }
34 |
35 | ANImageObj * ANImageFromCGImage (CGImageRef imageRef) {
36 | #if TARGET_OS_IPHONE
37 | return [UIImage imageWithCGImage:imageRef];
38 | #elif TARGET_OS_MAC
39 | NSImage * image = [[NSImage alloc] initWithCGImage:imageRef size:NSZeroSize];
40 | #if __has_feature(objc_arc) == 1
41 | return image;
42 | #else
43 | return [image autorelease];
44 | #endif
45 | #endif
46 | }
47 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/ColorPickerClasses/ANImageBitmapRep/Compatibility/UIImage+ANImageBitmapRep.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+ANImageBitmapRep.h
3 | // ImageBitmapRep
4 | //
5 | // Created by Alex Nichol on 8/11/11.
6 | // Copyright 2011 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "TargetConditionals.h"
10 |
11 | #if TARGET_OS_IPHONE
12 |
13 | @class ANImageBitmapRep;
14 |
15 | #import
16 |
17 | @interface UIImage (ANImageBitmapRep)
18 |
19 | #if __has_feature(objc_arc) == 1
20 | + (UIImage *)imageFromImageBitmapRep:(ANImageBitmapRep *)ibr __attribute__((ns_returns_autoreleased));
21 | - (ANImageBitmapRep *)imageBitmapRep __attribute__((ns_returns_autoreleased));
22 | - (UIImage *)imageByScalingToSize:(CGSize)sz __attribute__((ns_returns_autoreleased));
23 | - (UIImage *)imageFittingFrame:(CGSize)sz __attribute__((ns_returns_autoreleased));
24 | - (UIImage *)imageFillingFrame:(CGSize)sz __attribute__((ns_returns_autoreleased));
25 | #else
26 | + (UIImage *)imageFromImageBitmapRep:(ANImageBitmapRep *)ibr;
27 | - (ANImageBitmapRep *)imageBitmapRep;
28 | - (UIImage *)imageByScalingToSize:(CGSize)sz;
29 | - (UIImage *)imageFittingFrame:(CGSize)sz;
30 | - (UIImage *)imageFillingFrame:(CGSize)sz;
31 | #endif
32 |
33 | @end
34 |
35 | #endif
36 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/ColorPickerClasses/ANImageBitmapRep/Compatibility/UIImage+ANImageBitmapRep.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+ANImageBitmapRep.m
3 | // ImageBitmapRep
4 | //
5 | // Created by Alex Nichol on 8/11/11.
6 | // Copyright 2011 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "TargetConditionals.h"
10 |
11 | #if TARGET_OS_IPHONE
12 |
13 | #import "UIImage+ANImageBitmapRep.h"
14 | #import "ANImageBitmapRep.h"
15 |
16 | @implementation UIImage (ANImageBitmapRep)
17 |
18 |
19 | + (UIImage *)imageFromImageBitmapRep:(ANImageBitmapRep *)ibr {
20 | return [ibr image];
21 | }
22 |
23 | - (ANImageBitmapRep *)imageBitmapRep {
24 | #if __has_feature(objc_arc) == 1
25 | return [[ANImageBitmapRep alloc] initWithImage:self];
26 | #else
27 | return [[[ANImageBitmapRep alloc] initWithImage:self] autorelease];
28 | #endif
29 | }
30 |
31 | - (UIImage *)imageByScalingToSize:(CGSize)sz {
32 | ANImageBitmapRep * imageBitmap = [[ANImageBitmapRep alloc] initWithImage:self];
33 | [imageBitmap setSize:BMPointMake(round(sz.width), round(sz.height))];
34 | UIImage * scaled = [imageBitmap image];
35 | #if __has_feature(objc_arc) != 1
36 | [imageBitmap release];
37 | #endif
38 | return scaled;
39 | }
40 |
41 | - (UIImage *)imageFittingFrame:(CGSize)sz {
42 | ANImageBitmapRep * imageBitmap = [[ANImageBitmapRep alloc] initWithImage:self];
43 | [imageBitmap setSizeFittingFrame:BMPointMake(round(sz.width), round(sz.height))];
44 | UIImage * scaled = [imageBitmap image];
45 | #if __has_feature(objc_arc) != 1
46 | [imageBitmap release];
47 | #endif
48 | return scaled;
49 | }
50 |
51 | - (UIImage *)imageFillingFrame:(CGSize)sz {
52 | ANImageBitmapRep * imageBitmap = [[ANImageBitmapRep alloc] initWithImage:self];
53 | [imageBitmap setSizeFillingFrame:BMPointMake(round(sz.width), round(sz.height))];
54 | UIImage * scaled = [imageBitmap image];
55 | #if __has_feature(objc_arc) != 1
56 | [imageBitmap release];
57 | #endif
58 | return scaled;
59 | }
60 |
61 | @end
62 |
63 | #endif
64 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/ColorPickerClasses/ANImageBitmapRep/CoreGraphics/CGContextCreator.h:
--------------------------------------------------------------------------------
1 | //
2 | // CGContextCreator.h
3 | // ImageBitmapRep
4 | //
5 | // Created by Alex Nichol on 7/4/11.
6 | // Copyright 2011 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "TargetConditionals.h"
11 |
12 | #if TARGET_OS_IPHONE
13 | #import
14 | #elif TARGET_OS_MAC
15 | #import
16 | #endif
17 |
18 | /**
19 | * This class has several static methods for creating bitmap contexts.
20 | * These methods are pretty much only called when creating a new
21 | * ANImageBitmapRep.
22 | */
23 | @interface CGContextCreator : NSObject {
24 |
25 | }
26 |
27 | + (CGContextRef)newARGBBitmapContextWithSize:(CGSize)size;
28 | + (CGContextRef)newARGBBitmapContextWithImage:(CGImageRef)image;
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/ColorPickerClasses/ANImageBitmapRep/CoreGraphics/CGImageContainer.h:
--------------------------------------------------------------------------------
1 | //
2 | // CGImageContainer.h
3 | // ImageBitmapRep
4 | //
5 | // Created by Alex Nichol on 5/3/11.
6 | // Copyright 2011 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "TargetConditionals.h"
11 |
12 | #if TARGET_OS_IPHONE
13 | #import
14 | #elif TARGET_OS_MAC
15 | #import
16 | #endif
17 |
18 | #if __has_feature(objc_arc) != 1
19 |
20 | @interface CGImageContainer : NSObject {
21 | CGImageRef image;
22 | }
23 |
24 | /**
25 | * The image that this container encloses.
26 | */
27 | @property (readonly) CGImageRef image;
28 |
29 | /**
30 | * Create a new image container with an image.
31 | * @param anImage Will be retained and enclosed in this class.
32 | * This object will be released when the CGImageContainer is
33 | * deallocated. This can be nil.
34 | * @return The new image container, or nil if anImage is nil.
35 | */
36 | - (id)initWithImage:(CGImageRef)anImage;
37 |
38 | /**
39 | * Create a new image container with an image.
40 | * @param anImage Will be retained and enclosed in this class.
41 | * This object will be released when the CGImageContainer is
42 | * deallocated. This can be nil.
43 | * @return The new image container, or nil if anImage is nil.
44 | * The image container returned will be autoreleased.
45 | */
46 | + (CGImageContainer *)imageContainerWithImage:(CGImageRef)anImage;
47 |
48 | @end
49 |
50 | #else
51 |
52 | id CGImageReturnAutoreleased (CGImageRef original) __attribute__((ns_returns_autoreleased));
53 |
54 | #endif
55 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/ColorPickerClasses/ANImageBitmapRep/CoreGraphics/CGImageContainer.m:
--------------------------------------------------------------------------------
1 | //
2 | // CGImageContainer.m
3 | // ImageBitmapRep
4 | //
5 | // Created by Alex Nichol on 5/3/11.
6 | // Copyright 2011 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "CGImageContainer.h"
10 |
11 | #if __has_feature(objc_arc) != 1
12 |
13 | @implementation CGImageContainer
14 |
15 | @synthesize image;
16 |
17 | - (id)initWithImage:(CGImageRef)anImage {
18 | if ((self = [super init])) {
19 | image = CGImageRetain(anImage);
20 | }
21 | return self;
22 | }
23 |
24 | + (CGImageContainer *)imageContainerWithImage:(CGImageRef)anImage {
25 | CGImageContainer * container = [(CGImageContainer *)[CGImageContainer alloc] initWithImage:anImage];
26 | return [container autorelease];
27 | }
28 |
29 | - (void)dealloc {
30 | CGImageRelease(image);
31 | [super dealloc];
32 | }
33 |
34 | @end
35 |
36 | #else
37 |
38 | __attribute__((ns_returns_autoreleased))
39 | id CGImageReturnAutoreleased (CGImageRef original) {
40 | // CGImageRetain(original);
41 | return (__bridge id)original;
42 | }
43 |
44 | #endif
45 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/ColorPickerClasses/ANImageBitmapRep/Manipulators/BitmapContextManipulator.h:
--------------------------------------------------------------------------------
1 | //
2 | // BitmapContextManip.h
3 | // ImageBitmapRep
4 | //
5 | // Created by Alex Nichol on 10/14/11.
6 | // Copyright 2011 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "BitmapContextRep.h"
11 |
12 | @interface BitmapContextManipulator : NSObject {
13 | #if __has_feature(objc_arc) == 1
14 | __unsafe_unretained BitmapContextRep * bitmapContext;
15 | #else
16 | BitmapContextRep * bitmapContext;
17 | #endif
18 | }
19 |
20 | #if __has_feature(objc_arc) == 1
21 | @property (nonatomic, assign) BitmapContextRep * bitmapContext;
22 | #else
23 | @property (nonatomic, assign) BitmapContextRep * bitmapContext;
24 | #endif
25 |
26 | - (id)initWithContext:(BitmapContextRep *)aContext;
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/ColorPickerClasses/ANImageBitmapRep/Manipulators/BitmapContextManipulator.m:
--------------------------------------------------------------------------------
1 | //
2 | // BitmapContextManip.m
3 | // ImageBitmapRep
4 | //
5 | // Created by Alex Nichol on 10/14/11.
6 | // Copyright 2011 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "BitmapContextManipulator.h"
10 |
11 | @implementation BitmapContextManipulator
12 |
13 | @synthesize bitmapContext;
14 |
15 | - (id)initWithContext:(BitmapContextRep *)aContext {
16 | if ((self = [super init])) {
17 | self.bitmapContext = aContext;
18 | }
19 | return self;
20 | }
21 |
22 | - (void)forwardInvocation:(NSInvocation *)anInvocation {
23 | [anInvocation invokeWithTarget:bitmapContext];
24 | }
25 |
26 | #if __has_feature(objc_arc) != 1
27 |
28 | - (void)dealloc {
29 | self.bitmapContext = nil;
30 | [super dealloc];
31 | }
32 |
33 | #endif
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/ColorPickerClasses/ANImageBitmapRep/Manipulators/BitmapCropManipulator.h:
--------------------------------------------------------------------------------
1 | //
2 | // CroppableBitmapRep.h
3 | // ImageManip
4 | //
5 | // Created by Alex Nichol on 7/12/11.
6 | // Copyright 2011 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "BitmapContextManipulator.h"
11 |
12 | @protocol BitmapCropManipulator
13 |
14 | @optional
15 | - (void)cropFrame:(CGRect)frame;
16 | - (void)cropTopFrame:(CGRect)frame;
17 | - (void)cropTopEllipse:(CGRect)frame;
18 | - (CGImageRef)croppedImageWithFrame:(CGRect)frame;
19 |
20 | @end
21 |
22 | @interface BitmapCropManipulator : BitmapContextManipulator {
23 |
24 | }
25 |
26 | /**
27 | * Cuts a part of the bitmap out for a new bitmap.
28 | * @param frame The rectangle from which a portion of the image will
29 | * be cut.
30 | * The coordinates for this start at (0,0).
31 | * @discussion The coordinates for this method begin in the bottom
32 | * left corner. For a coordinate system starting from the top
33 | * left corner, use cropTopFrame: instead.
34 | */
35 | - (void)cropFrame:(CGRect)frame;
36 |
37 | /**
38 | * Cuts a part of the bitmap out for a new bitmap.
39 | * @param frame The rectangle from which a portion of the image will
40 | * be cut.
41 | * The coordinates for this start at (0,0).
42 | * @discussion The coordinates for this method begin in the top
43 | * left corner. For a coordinate system starting from the bottom
44 | * left corner, use cropFrame: instead.
45 | */
46 | - (void)cropTopFrame:(CGRect)frame;
47 |
48 | /**
49 | * Cuts an ellipse of the bitmap out for a new bitmap.
50 | * @param frame The rectangle around the ellipse to be cut. The
51 | * coordinates for this start at (0,0).
52 | * @discussion The coordinates for this method begin in the top
53 | * left corner. There is no alternative.
54 | */
55 | - (void)cropTopEllipse:(CGRect)frame;
56 |
57 | /**
58 | * Creates a new CGImageRef by cutting out a portion of this one.
59 | * This takes its behavoir from cropFrame.
60 | * @return An autoreleased CGImageRef that has been cropped from this
61 | * image.
62 | */
63 | - (CGImageRef)croppedImageWithFrame:(CGRect)frame;
64 |
65 | @end
66 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/ColorPickerClasses/ANImageBitmapRep/Manipulators/BitmapDrawManipulator.h:
--------------------------------------------------------------------------------
1 | //
2 | // BitmapDrawManipulator.h
3 | // FaceBlur
4 | //
5 | // Created by Alex Nichol on 7/1/12.
6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "BitmapContextManipulator.h"
11 |
12 | @protocol BitmapDrawManipulator
13 |
14 | @optional
15 | - (void)drawImage:(CGImageRef)image inRect:(CGRect)rect;
16 | - (void)drawEllipseInFrame:(CGRect)frame color:(CGColorRef)color;
17 |
18 | @end
19 |
20 | @interface BitmapDrawManipulator : BitmapContextManipulator
21 |
22 | /**
23 | * Overlays an image on the existing bitmap.
24 | * @param image The image to be overlayed.
25 | * @param rect The frame in which the image will be drawn.
26 | * The coordinates for this begin at the top-left hand
27 | * corner of the view.
28 | */
29 | - (void)drawImage:(CGImageRef)image inRect:(CGRect)rect;
30 |
31 | /**
32 | * Draws a colored ellipse in a given rectangle.
33 | * @param frame The rectangle in which to draw the ellipse
34 | * @param color The fill color for the ellipse. The coordinates
35 | * for this begin at the top-left hand corner of the view.
36 | */
37 | - (void)drawEllipseInFrame:(CGRect)frame color:(CGColorRef)color;
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/ColorPickerClasses/ANImageBitmapRep/Manipulators/BitmapDrawManipulator.m:
--------------------------------------------------------------------------------
1 | //
2 | // BitmapDrawManipulator.m
3 | // FaceBlur
4 | //
5 | // Created by Alex Nichol on 7/1/12.
6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "BitmapDrawManipulator.h"
10 |
11 | @implementation BitmapDrawManipulator
12 |
13 | - (void)drawImage:(CGImageRef)image inRect:(CGRect)rect {
14 | BMPoint size = [bitmapContext bitmapSize];
15 | // It's kind of rude to prevent them from doing something kind of cool, so let's not.
16 | // NSAssert(frame.origin.x >= 0 && frame.origin.x + frame.size.width <= size.x, @"Cropping frame must be within the bitmap.");
17 | // NSAssert(frame.origin.y >= 0 && frame.origin.y + frame.size.height <= size.y, @"Cropping frame must be within the bitmap.");
18 |
19 | CGPoint offset = CGPointMake(rect.origin.x, (size.y - (rect.origin.y + rect.size.height)));
20 |
21 | CGContextRef context = [[self bitmapContext] context];
22 | CGContextSaveGState(context);
23 | CGContextDrawImage(context, CGRectMake(offset.x, offset.y, rect.size.width, rect.size.height), image);
24 | CGContextRestoreGState(context);
25 | [self.bitmapContext setNeedsUpdate:YES];
26 | }
27 |
28 | - (void)drawEllipseInFrame:(CGRect)frame color:(CGColorRef)color {
29 | CGContextRef context = [[self bitmapContext] context];
30 | CGContextSaveGState(context);
31 | CGContextScaleCTM(context, 1, -1);
32 | CGContextTranslateCTM(context, 0, -[bitmapContext bitmapSize].y);
33 | CGContextSetFillColorWithColor(context, color);
34 | CGContextFillEllipseInRect(context, frame);
35 | CGContextRestoreGState(context);
36 | [self.bitmapContext setNeedsUpdate:YES];
37 | }
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/ColorPickerClasses/ANImageBitmapRep/Manipulators/BitmapRotationManipulator.h:
--------------------------------------------------------------------------------
1 | //
2 | // RotatableBitmapRep.h
3 | // ImageManip
4 | //
5 | // Created by Alex Nichol on 7/12/11.
6 | // Copyright 2011 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "BitmapContextManipulator.h"
11 |
12 | @protocol BitmapRotationManipulator
13 |
14 | @optional
15 | - (void)rotate:(CGFloat)degrees;
16 | - (CGImageRef)imageByRotating:(CGFloat)degrees;
17 |
18 | @end
19 |
20 | @interface BitmapRotationManipulator : BitmapContextManipulator {
21 |
22 | }
23 |
24 | /**
25 | * Rotate the image bitmap around its center by a certain number of degrees.
26 | * @param degrees The degrees from 0 to 360. This is not measured in radians.
27 | * @discussion This will resize the image if needed.
28 | */
29 | - (void)rotate:(CGFloat)degrees;
30 |
31 | /**
32 | * Create a new image by rotating this image bitmap around its center by a specified
33 | * number of degrees.
34 | * @param degrees The degrees (not in radians) by which the image should be rotated.
35 | * @discussion This will resize the image if needed.
36 | */
37 | - (CGImageRef)imageByRotating:(CGFloat)degrees;
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/ColorPickerClasses/ANImageBitmapRep/Manipulators/BitmapScaleManipulator.h:
--------------------------------------------------------------------------------
1 | //
2 | // ScalableBitmapRep.h
3 | // ImageManip
4 | //
5 | // Created by Alex Nichol on 7/12/11.
6 | // Copyright 2011 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "BitmapContextManipulator.h"
11 |
12 | @protocol BitmapScaleManipulator
13 |
14 | @optional
15 | - (void)setSize:(BMPoint)aSize;
16 | - (void)setSizeFittingFrame:(BMPoint)aSize;
17 | - (void)setSizeFillingFrame:(BMPoint)aSize;
18 |
19 | @end
20 |
21 | @interface BitmapScaleManipulator : BitmapContextManipulator {
22 |
23 | }
24 |
25 | /**
26 | * Stretches the bitmap context to a specified size.
27 | * @param aSize The new size to make the bitmap.
28 | * If this is the same as the current size, the bitmap
29 | * will not be changed.
30 | */
31 | - (void)setSize:(BMPoint)aSize;
32 |
33 | /**
34 | * Scales the image to fit a particular frame without stretching (bringing out of scale).
35 | * @param aSize The size to which the image scaled.
36 | * @discussion The actual image itself will most likely be smaller than the specified
37 | * size, leaving transparent edges to make the image fit the exact size.
38 | */
39 | - (void)setSizeFittingFrame:(BMPoint)aSize;
40 |
41 | /**
42 | * Scales the image to fill a particular frame without stretching.
43 | * This will most likely cause the left and right or top and bottom
44 | * edges of the image to be cut off.
45 | * @param aSize The size that the image will be forced to fill.
46 | */
47 | - (void)setSizeFillingFrame:(BMPoint)aSize;
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/ColorPickerClasses/RSColorFunctions.h:
--------------------------------------------------------------------------------
1 | //
2 | // RSColorFunctions.h
3 | // RSColorPicker
4 | //
5 | // Created by Ryan Sullivan on 3/12/13.
6 | //
7 |
8 | #import
9 | #import "ANImageBitmapRep.h"
10 |
11 | BMPixel RSPixelFromHSV(CGFloat H, CGFloat S, CGFloat V);
12 | void RSHSVFromPixel(BMPixel pixel, CGFloat *h, CGFloat *s, CGFloat *v);
13 |
14 | // four floats will be placed into `components`
15 | void RSGetComponentsForColor(CGFloat *components, UIColor *color);
16 |
17 | UIImage * RSUIImageWithScale(UIImage *img, CGFloat scale);
18 |
19 | UIImage * RSOpacityBackgroundImage(CGFloat length, CGFloat scale, UIColor *color);
20 |
21 | UIColor * RSRandomColorOpaque(BOOL isOpaque);
22 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/ColorPickerClasses/RSColorPickerState.h:
--------------------------------------------------------------------------------
1 | //
2 | // RSColorPickerState.h
3 | // RSColorPicker
4 | //
5 | // Created by Alex Nichol on 12/16/13.
6 | //
7 |
8 | #import
9 | #import "RSColorFunctions.h"
10 |
11 | /**
12 | * Represents the state of a color picker. This includes
13 | * the position on the color picker (for a square picker) that
14 | * is selected.
15 | *
16 | * Terms used:
17 | * "size" - the diameter of the color picker
18 | * "padding" - the amount of pixels on each side of the color picker
19 | * reserved for padding
20 | */
21 | @interface RSColorPickerState : NSObject {
22 | CGPoint scaledRelativePoint; // H & S
23 | CGFloat brightness; // V
24 | CGFloat alpha; // A
25 | }
26 |
27 | @property (readonly) CGFloat hue, saturation, brightness, alpha;
28 |
29 | /**
30 | * Creates a state with a 1.0 alpha and 1.0 brightness that would arise
31 | * by selecting `point` on a color picker of diameter `size` and padding `padding`.
32 | */
33 | + (RSColorPickerState *)stateForPoint:(CGPoint)point size:(CGFloat)size padding:(CGFloat)padding;
34 |
35 | /**
36 | * Create a state with a given color.
37 | */
38 | - (id)initWithColor:(UIColor *)selectionColor;
39 |
40 | /**
41 | * Create a state given a point on the unit circle and brightness+alpha
42 | */
43 | - (id)initWithScaledRelativePoint:(CGPoint)p brightness:(CGFloat)V alpha:(CGFloat)A;
44 |
45 | /**
46 | * Create a state given HSVA components.
47 | */
48 | - (id)initWithHue:(CGFloat)H saturation:(CGFloat)S brightness:(CGFloat)V alpha:(CGFloat)A;
49 |
50 | - (UIColor *)color;
51 |
52 | /**
53 | * Returns the position of this state on a color picker of size `size` and padding `padding`.
54 | * Note: this point may be outside of the unit circle if a point outside the unit circle
55 | * was picked to generate this state.
56 | */
57 | - (CGPoint)selectionLocationWithSize:(CGFloat)size padding:(CGFloat)padding;
58 |
59 | // This class is immutable, so these are helpful!
60 | - (RSColorPickerState *)stateBySettingBrightness:(CGFloat)newBright;
61 | - (RSColorPickerState *)stateBySettingAlpha:(CGFloat)newAlpha;
62 | - (RSColorPickerState *)stateBySettingHue:(CGFloat)newHue;
63 | - (RSColorPickerState *)stateBySettingSaturation:(CGFloat)newSaturation;
64 |
65 | @end
66 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/ColorPickerClasses/RSGenerateOperation.h:
--------------------------------------------------------------------------------
1 | //
2 | // GenerateOperation.h
3 | // RSColorPicker
4 | //
5 | // Created by Ryan on 7/22/13.
6 | //
7 |
8 | #import
9 | #import
10 |
11 | @class ANImageBitmapRep;
12 |
13 | @interface RSGenerateOperation : NSOperation
14 |
15 | -(id)initWithDiameter:(CGFloat)diameter andPadding:(CGFloat)padding;
16 |
17 | @property (readonly) CGFloat diameter;
18 | @property (readonly) CGFloat padding;
19 |
20 | @property ANImageBitmapRep *bitmap;
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/ColorPickerClasses/RSSelectionLayer.h:
--------------------------------------------------------------------------------
1 | //
2 | // RSSelectionView.h
3 | // RSColorPicker
4 | //
5 | // Created by Ryan Sullivan on 3/12/13.
6 | //
7 |
8 | #import
9 |
10 | @interface RSSelectionLayer : CALayer
11 | @end
12 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/ColorPickerClasses/RSSelectionLayer.m:
--------------------------------------------------------------------------------
1 | //
2 | // RSSelectionView.m
3 | // RSColorPicker
4 | //
5 | // Created by Ryan Sullivan on 3/12/13.
6 | //
7 |
8 | #import "RSSelectionLayer.h"
9 |
10 |
11 | @interface RSSelectionLayer ()
12 |
13 | @property (nonatomic, strong) CGColorRef outerRingColor __attribute__((NSObject));
14 | @property (nonatomic, strong) CGColorRef innerRingColor __attribute__((NSObject));
15 |
16 | @end
17 |
18 | @implementation RSSelectionLayer
19 |
20 | - (void)drawInContext:(CGContextRef)ctx {
21 | // if (!self.outerRingColor || !self.innerRingColor) {
22 | // self.outerRingColor = [[UIColor colorWithWhite:1 alpha:0.4] CGColor];
23 | // self.innerRingColor = [[UIColor colorWithWhite:0 alpha:0.2] CGColor];
24 | // }
25 | // CGRect rect = self.bounds;
26 | //
27 | // CGContextSetLineWidth(ctx, 1);
28 | // CGContextSetStrokeColorWithColor(ctx, self.outerRingColor);
29 | // CGContextStrokeEllipseInRect(ctx, CGRectInset(rect, 1.5, 1.5));
30 | //
31 | // CGContextSetLineWidth(ctx, 1);
32 | // CGContextSetStrokeColorWithColor(ctx, self.innerRingColor);
33 | // CGContextStrokeEllipseInRect(ctx, CGRectInset(rect, 3, 3));
34 |
35 | CGContextDrawImage(ctx, self.bounds, [UIImage imageNamed:@"slider-oval"].CGImage);
36 | }
37 |
38 | @end
39 |
40 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/DSDetailColorBoard.h:
--------------------------------------------------------------------------------
1 | //
2 | // DSDetailColorBoard.h
3 | // Infinitee2.0
4 | //
5 | // Created by 周健平 on 2017/11/13.
6 | // Copyright © 2017年 Infinitee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @protocol DSDetailColorBoardDelegate
14 |
15 | - (void)detailColorBoardDidChooseOriginColor;
16 | - (void)detailColorBoardDidChooseDefaultColor;
17 | - (void)detailColorBoardDidChooseTransparentGridColor;
18 | - (void)detailColorBoardDidChooseCustomColor:(UIColor *)color;
19 |
20 | @end
21 |
22 | @interface DSDetailColorBoard : UIView
23 |
24 | + (DSDetailColorBoard *)detailColorBoard;
25 |
26 | @property (nonatomic, weak) id delegate;
27 |
28 | @end
29 |
30 | NS_ASSUME_NONNULL_END
31 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/DSRGBAColorLabel.h:
--------------------------------------------------------------------------------
1 | //
2 | // DSRGBAColorLabel.h
3 | // Infinitee2.0
4 | //
5 | // Created by 周健平 on 2017/11/15.
6 | // Copyright © 2017年 Infinitee. All rights reserved.
7 | //
8 |
9 | #import
10 | @class DSRGBAColorLabel;
11 |
12 | @protocol DSRGBAColorLabelDelegate
13 |
14 | - (void)colorLabelDidClick:(DSRGBAColorLabel *)colorLabel;
15 |
16 | @end
17 |
18 | @interface DSRGBAColorLabel : UIView
19 | - (instancetype)initWithFrame:(CGRect)frame title:(NSString *)title delegate:(id)delegate;
20 |
21 | @property (nonatomic, weak) id delegate;
22 | @property (nonatomic, assign) int colorValue;
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/DSSliderBoard.h:
--------------------------------------------------------------------------------
1 | //
2 | // DSSliderBoard.h
3 | // Infinitee2.0
4 | //
5 | // Created by 周健平 on 2017/11/13.
6 | // Copyright © 2017年 Infinitee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @protocol DSSliderBoardDelegate
12 |
13 | - (void)sliderValueTouchBegin;
14 | - (void)sliderValueTouchDone;
15 | - (void)sliderValueDidChanged:(float)sliderValue;
16 |
17 | - (NSString *)sliderValueText:(float)sliderValue;
18 |
19 | @end
20 |
21 | @interface DSSliderBoard : UIView
22 |
23 | + (CGFloat)viewHeight;
24 |
25 | - (void)resetSliderValue:(float)sliderValue isAnimate:(BOOL)isAnimate;
26 | - (void)resetSliderValue:(float)sliderValue;
27 |
28 | @property (nonatomic, assign) id delegate;
29 |
30 | @property (nonatomic, assign) float sliderValue;
31 | @property (nonatomic, assign) float maxValue;
32 | @property (nonatomic, assign) float minValue;
33 |
34 | @property (nonatomic, weak) UISlider *slider;
35 |
36 | @end
37 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/RSBrightnessSlider.h:
--------------------------------------------------------------------------------
1 | //
2 | // RSBrightnessSlider.h
3 | // RSColorPicker
4 | //
5 | // Created by Ryan Sullivan on 8/12/11.
6 | //
7 |
8 | #import
9 | #import "RSColorPickerView.h"
10 |
11 | @interface RSBrightnessSlider : UISlider
12 |
13 | @property (nonatomic) RSColorPickerView *colorPicker;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/RSOpacitySlider.h:
--------------------------------------------------------------------------------
1 | //
2 | // RSOpacitySlider.h
3 | // RSColorPicker
4 | //
5 | // Created by Jared Allen on 5/16/13.
6 | // Copyright (c) 2013 Red Cactus LLC. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "RSColorPickerView.h"
11 |
12 | @interface RSOpacitySlider : UISlider
13 |
14 | @property (nonatomic) RSColorPickerView *colorPicker;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/RSOpacitySlider.m:
--------------------------------------------------------------------------------
1 | //
2 | // RSOpacitySlider.m
3 | // RSColorPicker
4 | //
5 | // Created by Jared Allen on 5/16/13.
6 | // Copyright (c) 2013 Red Cactus LLC. All rights reserved.
7 | //
8 |
9 | #import "RSOpacitySlider.h"
10 |
11 | #import "RSColorFunctions.h"
12 |
13 | @implementation RSOpacitySlider
14 |
15 | - (id)initWithFrame:(CGRect)frame {
16 | self = [super initWithFrame:frame];
17 | if (self) {
18 | [self initRoutine];
19 | }
20 | return self;
21 | }
22 |
23 | - (id)initWithCoder:(NSCoder *)aDecoder {
24 | self = [super initWithCoder:aDecoder];
25 | if (self) {
26 | [self initRoutine];
27 | }
28 | return self;
29 | }
30 |
31 | - (void)initRoutine {
32 | self.minimumValue = 0.0;
33 | self.maximumValue = 1.0;
34 | self.continuous = YES;
35 |
36 | self.enabled = YES;
37 | self.userInteractionEnabled = YES;
38 |
39 | [self addTarget:self action:@selector(myValueChanged:) forControlEvents:UIControlEventValueChanged];
40 |
41 | CGSize size = CGSizeMake(self.bounds.size.height - 2, self.bounds.size.height - 2);
42 | UIImage *thumbImage = [UIImage imageNamed:@"slider-oval"];
43 |
44 | UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
45 | [thumbImage drawInRect:CGRectMake(0, 0, size.width, size.height)];
46 | thumbImage = UIGraphicsGetImageFromCurrentImageContext();
47 | UIGraphicsEndImageContext();
48 |
49 | [self setThumbImage:thumbImage forState:UIControlStateNormal];
50 | [self setMinimumTrackTintColor:[UIColor clearColor]];
51 | [self setMaximumTrackTintColor:[UIColor clearColor]];
52 | }
53 |
54 | - (void)didMoveToWindow {
55 | if (!self.window) return;
56 |
57 | // UIImage *backgroundImage = RSOpacityBackgroundImage(16.f, self.window.screen.scale, [UIColor colorWithWhite:0.5 alpha:1.0]);
58 |
59 | }
60 |
61 | - (void)myValueChanged:(id)notif {
62 | _colorPicker.opacity = self.value;
63 | }
64 |
65 | - (void)setColorPicker:(RSColorPickerView *)cp {
66 | _colorPicker = cp;
67 | if (!_colorPicker) { return; }
68 | self.value = [_colorPicker brightness];
69 | }
70 |
71 | @end
72 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/SilderPlaceHolderView.h:
--------------------------------------------------------------------------------
1 | //
2 | // SilderPlaceHolderView.h
3 | // Infinitee2.0-Design
4 | //
5 | // Created by Jill on 16/9/26.
6 | // Copyright © 2016年 陈珏洁. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SilderPlaceHolderView : UIView
12 | - (instancetype)initWithFrame:(CGRect)frame baseColor:(UIColor *)baseColor;
13 | @property (nonatomic, strong) UIColor *baseColor;
14 | @property (nonatomic, strong) UIColor *sliderColor;
15 | @end
16 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ThirdLib/自定义取色板/SilderPlaceHolderView.m:
--------------------------------------------------------------------------------
1 | //
2 | // SilderPlaceHolderView.m
3 | // Infinitee2.0-Design
4 | //
5 | // Created by Jill on 16/9/26.
6 | // Copyright © 2016年 陈珏洁. All rights reserved.
7 | //
8 |
9 | #import "SilderPlaceHolderView.h"
10 |
11 | @implementation SilderPlaceHolderView
12 |
13 | - (instancetype)initWithFrame:(CGRect)frame baseColor:(UIColor *)baseColor {
14 | if (self = [super initWithFrame:frame]) {
15 | self.backgroundColor = [UIColor whiteColor];
16 | self.layer.masksToBounds = YES;
17 | self.layer.cornerRadius = frame.size.height * 0.5;
18 | // self.layer.borderWidth = 0.5;
19 | // self.layer.borderColor = [UIColor colorWithWhite:1 alpha:0.5].CGColor;
20 | self.baseColor = baseColor;
21 | }
22 | return self;
23 | }
24 |
25 | - (void)drawRect:(CGRect)rect {
26 | if (!self.baseColor || !self.sliderColor) return;
27 |
28 | CGContextRef ctx = UIGraphicsGetCurrentContext();
29 |
30 | CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
31 | NSArray *colors = @[(id)self.baseColor.CGColor,
32 | (id)self.sliderColor.CGColor];
33 |
34 | CGGradientRef myGradient = CGGradientCreateWithColors(space, (__bridge CFArrayRef)colors, NULL);
35 |
36 | CGContextDrawLinearGradient(ctx, myGradient, CGPointZero, CGPointMake(rect.size.width, 0), 0);
37 | CGGradientRelease(myGradient);
38 | CGColorSpaceRelease(space);
39 | }
40 |
41 | - (void)setSliderColor:(UIColor *)sliderColor {
42 | _sliderColor = sliderColor;
43 | [self setNeedsDisplay];
44 | }
45 |
46 | @end
47 |
--------------------------------------------------------------------------------
/AnimationPreviewer/ViewController/ViewController+Drop.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController+Drop.swift
3 | // AnimationPreviewer
4 | //
5 | // Created by 周健平 on 2023/5/10.
6 | //
7 |
8 | import UIKit
9 | import UniformTypeIdentifiers
10 |
11 | // MARK: -
12 | extension ViewController: UIDropInteractionDelegate {
13 |
14 | // 确定传入的物体是否为`AnimationData`对象
15 | func dropInteraction(_ interaction: UIDropInteraction, canHandle session: UIDropSession) -> Bool {
16 | return session.canLoadObjects(ofClass: AnimationData.self)
17 | }
18 |
19 | // 提取数据
20 | func dropInteraction(_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal {
21 | // let dropLocation = session.location(in: animView)
22 | let operation: UIDropOperation
23 | if session.canLoadObjects(ofClass: AnimationData.self) {
24 | operation = session.localDragSession == nil ? .copy : .move
25 | } else {
26 | operation = .cancel
27 | }
28 | return UIDropProposal(operation: operation)
29 | }
30 |
31 | // 加载数据
32 | func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) {
33 | session.loadObjects(ofClass: AnimationData.self) { [weak self] items in
34 | guard let self = self, let animData = items.first as? AnimationData else { return }
35 | self.replaceAnimation(with: animData.rawData)
36 | }
37 | }
38 |
39 | // 数据划出
40 | func dropInteraction(_ interaction: UIDropInteraction, sessionDidExit session: UIDropSession) {
41 |
42 | }
43 |
44 | }
45 |
46 |
47 |
--------------------------------------------------------------------------------
/AnimationPreviewer/background1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/background1.jpg
--------------------------------------------------------------------------------
/AnimationPreviewer/background2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rogue24/AnimationPreviewer/1f1c3661dfffd218c7bb567d49c82d4970649aaa/AnimationPreviewer/background2.jpg
--------------------------------------------------------------------------------
/MacPlugin/Channel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Channel.swift
3 | // MacPlugin
4 | //
5 | // Created by 周健平 on 2023/5/8.
6 | //
7 |
8 | import Foundation
9 |
10 | @objc(Channel)
11 | protocol Channel: NSObjectProtocol {
12 |
13 | /// 初始化
14 | init()
15 |
16 | /// 初始化配置
17 | func setup()
18 |
19 | /// 保存图片到下载文件夹
20 | func saveImage(_ imageData: Data, completion: @escaping (_ isSuccess: Bool) -> ())
21 |
22 | /// 保存视频到下载文件夹
23 | func saveVideo(_ videoPath: NSString, completion: @escaping (_ isSuccess: Bool) -> ())
24 |
25 | /// 打开Lottie文件夹或zip文件
26 | func pickLottie(completion: @escaping (_ data: Data?) -> ())
27 |
28 | /// 打开SVGA文件
29 | func pickSVGA(completion: @escaping (_ data: Data?) -> ())
30 |
31 | /// 打开GIF文件
32 | func pickGIF(completion: @escaping (_ data: Data?) -> ())
33 |
34 | /// 打开图片 ( jpeg, png )
35 | func pickImage(completion: @escaping (_ data: Data?) -> ())
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/MacPlugin/MacPlugin-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Use this file to import your target's public headers that you would like to expose to Swift.
3 | //
4 |
5 |
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment the next line to define a global platform for your project
2 | platform :ios, '15.0'
3 |
4 | target 'AnimationPreviewer' do
5 | # Comment the next line if you don't want to use dynamic frameworks
6 | use_frameworks!
7 |
8 | pod 'SSZipArchive'
9 | pod 'SnapKit'
10 | pod 'Protobuf', '= 3.22.1'
11 |
12 | post_install do |installer|
13 | installer.pods_project.targets.each do |target|
14 | target.build_configurations.each do |config|
15 | config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0'
16 | end
17 | end
18 | end
19 |
20 | end
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AnimationPreviewer
2 |
3 |  一个用于快速预览`Lottie`&`SVGA`&`GIF`的Mac小工具。
4 |
5 | Feature:
6 | ✅ 可立即预览 Lottie & SVGA & GIF 的动画效果;
7 | ✅ 可截取动画任意一帧生成图片;
8 | ✅ 可将动画制作成视频并导出;
9 | ✅ 提供多种预览模式;
10 | ✅ 支持拖拽动画文件到App;
11 | ✅ 支持通过菜单栏打开动画文件;
12 | ✅ 支持自定义App背景。
13 |
14 | ## 使用效果
15 |
16 | - 快速预览动画效果(把`Lottie文件`/`SVGA文件`/`GIF文件`/`zip包`丢进App即可):
17 |
18 | 
19 |
20 | - 可截取动画的任意一帧图片保存 & 可将动画制作成视频并导出(`Lottie`&`SVGA`&`GIF`都支持):
21 |
22 | 
23 |
24 | ## Tips
25 |
26 | 1. 拖拽预览支持`Lottie文件`、`SVGA文件`、`GIF文件`及其对应的`zip包`。
27 |
28 | 2. 📢 注意【带图片】的`Lottie`文件的内容需要跟以下规格保持一致:
29 |
30 | ```swift
31 | lottie_dir:
32 | - data.json
33 | - images:
34 | - img_0.png
35 | img_1.png
36 | img_2.png
37 | ...
38 | ```
39 |
40 | 3. 除了拖拽,还能通过菜单栏打开动画文件:
41 |
42 | 
43 |
44 | 4. 可以自定义App背景图片:
45 |
46 | 
47 |
48 | 5. 可以自定义预览区域的背景色:
49 |
50 | 
51 |
--------------------------------------------------------------------------------