├── .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 | ![icon](https://github.com/Rogue24/JPCover/raw/master/AnimationPreviewer/icon.png) 一个用于快速预览`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 | ![example1](https://github.com/Rogue24/JPCover/raw/master/AnimationPreviewer/example1.gif) 19 | 20 | - 可截取动画的任意一帧图片保存 & 可将动画制作成视频并导出(`Lottie`&`SVGA`&`GIF`都支持): 21 | 22 | ![example2](https://github.com/Rogue24/JPCover/raw/master/AnimationPreviewer/example2.gif) 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 | ![example3](https://github.com/Rogue24/JPCover/raw/master/AnimationPreviewer/example3.jpeg) 43 | 44 | 4. 可以自定义App背景图片: 45 | 46 | ![example4](https://github.com/Rogue24/JPCover/raw/master/AnimationPreviewer/example4.jpeg) 47 | 48 | 5. 可以自定义预览区域的背景色: 49 | 50 | ![example5](https://github.com/Rogue24/JPCover/raw/master/AnimationPreviewer/example5.gif) 51 | --------------------------------------------------------------------------------