├── Demo
├── Demo
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── AccentColor.colorset
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Preview Content
│ │ └── Preview Assets.xcassets
│ │ │ └── Contents.json
│ ├── DemoApp.swift
│ ├── Demo.entitlements
│ ├── Box.swift
│ └── ContentView.swift
└── Demo.xcodeproj
│ ├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ └── project.pbxproj
├── .gitignore
├── Package.swift
├── LICENSE
├── README.md
└── Sources
└── ImageMorphing
└── MorphingImage.swift
/Demo/Demo/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Demo/Demo/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | /*.xcodeproj
5 | xcuserdata/
6 | DerivedData/
7 | .swiftpm/config/registries.json
8 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
9 | .netrc
10 |
--------------------------------------------------------------------------------
/Demo/Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Demo/Demo/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 |
--------------------------------------------------------------------------------
/Demo/Demo/DemoApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DemoApp.swift
3 | // Demo
4 | //
5 | // Created by Jeremy Marchand on 01/10/2022.
6 | //
7 |
8 | import SwiftUI
9 |
10 | @main
11 | struct DemoApp: App {
12 | var body: some Scene {
13 | WindowGroup {
14 | ContentView()
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Demo/Demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Demo/Demo/Demo.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.user-selected.read-only
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version: 5.7
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "ImageMorphing",
8 | platforms: [.iOS(.v15), .macOS(.v12), .tvOS(.v15)],
9 | products: [
10 | .library(
11 | name: "ImageMorphing",
12 | targets: ["ImageMorphing"]),
13 | ],
14 | targets: [
15 | .target(
16 | name: "ImageMorphing",
17 | dependencies: [])
18 | ]
19 | )
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Jérémy Marchand
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ImageMorphing
2 |
3 | Apply morphing animation to images.
4 |
5 | Implementation is using 100% SwiftUI API by leveraging SwiftUI animation and Canvas.
6 |
7 | https://user-images.githubusercontent.com/4249097/193521856-17ec03ea-4a33-481d-808b-0c21d142509b.mp4
8 |
9 | ## Adding Image Morphing as a Dependency
10 | Add package to XCode or in a `Package.swift`
11 |
12 | ```swift
13 | .package(url: "https://github.com/kodlian/ImageMorphing", from: "1.0.0"),
14 | ```
15 |
16 | ## Usage
17 |
18 | Use MorphingImage as you will do with standard Image:
19 |
20 | ```swift
21 | MorphingImage("MyImage") // custom asset
22 | .frame(width: 64, height: 64)
23 |
24 | MorphingImage(systemName: "heart.fill") // SF Symbol
25 | .frame(width: 64, height: 64)
26 | ```
27 |
28 | When the image changes, a morphing animation will be performed between the old and new images. The base images are only used as template, the resulting image applies the foreground style currently defined in the context.
29 |
30 | Duration of morphing animation can be customized through a modifier:
31 |
32 | ```swift
33 | MorphingImage(..)
34 | .morphingImageDuration(1.5)
35 | ```
36 |
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "platform" : "ios",
6 | "size" : "1024x1024"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "scale" : "1x",
11 | "size" : "16x16"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "scale" : "2x",
16 | "size" : "16x16"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "scale" : "1x",
21 | "size" : "32x32"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "scale" : "2x",
26 | "size" : "32x32"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "scale" : "1x",
31 | "size" : "128x128"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "scale" : "2x",
36 | "size" : "128x128"
37 | },
38 | {
39 | "idiom" : "mac",
40 | "scale" : "1x",
41 | "size" : "256x256"
42 | },
43 | {
44 | "idiom" : "mac",
45 | "scale" : "2x",
46 | "size" : "256x256"
47 | },
48 | {
49 | "idiom" : "mac",
50 | "scale" : "1x",
51 | "size" : "512x512"
52 | },
53 | {
54 | "idiom" : "mac",
55 | "scale" : "2x",
56 | "size" : "512x512"
57 | }
58 | ],
59 | "info" : {
60 | "author" : "xcode",
61 | "version" : 1
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Demo/Demo/Box.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Box.swift
3 | // Demo
4 | //
5 | // Created by Jeremy Marchand on 01/10/2022.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct Box: View {
11 | let title: String
12 | let subtitle: String
13 |
14 |
15 | @ViewBuilder
16 | let content: () -> Content
17 |
18 | var headerText: Text {
19 | Text(title)
20 | .font(.title.weight(.semibold))
21 | + Text("\n")
22 | + Text(subtitle)
23 | .font(.subheadline)
24 | }
25 |
26 | var body: some View {
27 | VStack {
28 | headerText
29 | .fixedSize()
30 | .multilineTextAlignment(.center)
31 | Divider()
32 | content()
33 | .padding(.top)
34 | .shadow(color: .white, radius: 4)
35 | .shadow(color: .purple.opacity(0.45), radius: 30)
36 | }
37 | .padding(30)
38 | .background(background)
39 | .padding(.horizontal, 30)
40 | .padding(.vertical, 15)
41 | }
42 |
43 | var background: some View {
44 | RoundedRectangle(cornerRadius: 30, style: .continuous)
45 | .foregroundColor(.white)
46 | .shadow(color: .black.opacity(0.10), radius: 30)
47 | }
48 | }
49 |
50 | struct Box_Previews: PreviewProvider {
51 | static var previews: some View {
52 | Box(title: "title", subtitle: "subtile") {
53 | Text("Box Content")
54 | }.padding(30)
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Demo/Demo/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // Demo
4 | //
5 | // Created by Jeremy Marchand on 01/10/2022.
6 | //
7 |
8 | import SwiftUI
9 | import ImageMorphing
10 |
11 | struct ContentView: View {
12 | let names = [
13 | "circle.fill",
14 | "heart.fill",
15 | "star.fill",
16 | "bell.fill",
17 | "bookmark.fill",
18 | "tag.fill",
19 | "bolt.fill",
20 | "play.fill",
21 | "pause.fill",
22 | "squareshape.fill",
23 | "key.fill",
24 | "hexagon.fill",
25 | "gearshape.fill",
26 | ]
27 |
28 | @State
29 | var index = 0
30 | var nextIndex: Int {
31 | return (index + 1) % names.count
32 | }
33 |
34 | let gradient = Gradient(colors: [.purple, .red])
35 |
36 | var body: some View {
37 | ScrollView {
38 | Box(title: "It is morphing time!", subtitle: "Demo") {
39 | demo
40 | }
41 | Box(title: "How to use?", subtitle: "100% SwiftUI") {
42 | howTo
43 | }
44 | }
45 | .foregroundStyle(
46 | .linearGradient(gradient, startPoint: .top, endPoint: .bottom)
47 | )
48 | .frame(maxWidth: .infinity, maxHeight: .infinity)
49 | }
50 |
51 | @ViewBuilder
52 | var demo: some View {
53 | MorphingImage(systemName: names[index])
54 | .frame(width: 128, height: 128)
55 | .padding()
56 | Button {
57 | index = nextIndex
58 | } label: {
59 | Label {
60 | Text("Next")
61 | .fontWeight(.semibold)
62 | } icon: {
63 | MorphingImage(systemName: names[nextIndex])
64 | .frame(width: 16, height: 16)
65 | }
66 | }
67 | .foregroundColor(.white)
68 | .buttonStyle(.borderedProminent)
69 | .buttonBorderShape(.capsule)
70 | .accentColor(.purple)
71 | .multilineTextAlignment(.center)
72 | }
73 |
74 | @ViewBuilder
75 | var howTo: some View {
76 | Text("""
77 | **MorphingImage("MyImage")**
78 | .frame(width: 64, height: 64)
79 |
80 | **MorphingImage(systemName: "star.fill")**
81 | .frame(width: 64, height: 64)
82 | """).font(.caption)
83 | }
84 | }
85 |
86 |
87 | struct ContentView_Previews: PreviewProvider {
88 | static var previews: some View {
89 | ContentView()
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/Sources/ImageMorphing/MorphingImage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MorphingImage.swift
3 | // Morphing
4 | //
5 | // Created by Jeremy Marchand on 01/10/2022.
6 | //
7 |
8 | import SwiftUI
9 |
10 | /// A Morphing Image that animates when image change.
11 | ///
12 | /// When images change, an animation will be performed to morph previous image to the new image. It uses a combinaison of a blur and an alpha threshold effects.
13 | ///
14 | /// The morphing image uses a base Image as a the template for the resulting image and applies the current foreground style.
15 | ///
16 | /// The animation duration is by default set to 1 second but can be customized through the modifier ``morphingImageDuration(_:)``
17 | ///
18 | /// The size of the morphing image is inherited from the container and not the template image.
19 | /// - Parameter duration: Duration of the morphing animate.
20 | public struct MorphingImage: View {
21 | @Environment(\.morphingImageDuration)
22 | var duration
23 |
24 | /// Creates a morphing image that you can use as symbol for controls.
25 | ///
26 | /// - Parameters:
27 | /// - name: The name of the image resource to lookup.
28 | /// - bundle: The bundle to search for the image resource.
29 | /// If `nil`, SwiftUI uses the main `Bundle`. Defaults to `nil`.
30 | public init(_ name: String, bundle: Bundle? = nil) {
31 | self.image = Image(name, bundle: bundle)
32 | self.name = name
33 | }
34 |
35 | /// Creates a system symbol morphing image.
36 | ///
37 | /// This initializer creates an image using a system-provided symbol. Use
38 | /// [SF Symbols](https://developer.apple.com/design/resources/#sf-symbols)
39 | /// to find symbols and their corresponding names.
40 | ///
41 | /// - Parameters:
42 | /// - systemName: The name of the system symbol image.
43 | /// Use the SF Symbols app to look up the names of system symbol images.
44 | public init(systemName: String) {
45 | self.image = Image(systemName: systemName)
46 | self.name = systemName
47 | }
48 |
49 | let image: Image
50 | let name: String
51 |
52 | @State
53 | private var blurRadius: Double = 0
54 |
55 | @State
56 | private var currentTask: Task?
57 |
58 | public var body: some View {
59 | GeometryReader { reader in
60 | // Adapt blur radius to the size.
61 | let size = max(reader.size.width, reader.size.height)
62 | let blurRadius = min(size * 0.05, 20)
63 |
64 | Canvas { context, size in
65 | context.clipToLayer { context in
66 | context.addFilter(.alphaThreshold(min: 0.5))
67 | context.drawLayer { context in
68 | let view = context.resolveSymbol(id: 0)!
69 | context.draw(view, at: CGPoint(x: size.width / 2, y: size.height / 2))
70 | }
71 | }
72 | context.fill(Path(CGRect(origin: .zero, size: size)), with: .foreground)
73 | } symbols: {
74 | symbol(forSize: reader.size).tag(0)
75 | }
76 | .onChange(of: image) { _ in
77 | currentTask?.cancel()
78 | currentTask = Task {
79 | let halfDuration = duration / 2
80 | withAnimation(.easeIn(duration: halfDuration)) {
81 | self.blurRadius = blurRadius
82 | }
83 | try await Task.sleep(nanoseconds: UInt64(Int64(duration * 500_000_000)))
84 | withAnimation(.easeOut(duration: halfDuration)) {
85 | self.blurRadius = 0
86 | }
87 | }
88 | }
89 | }
90 | }
91 |
92 | private func symbol(forSize size: CGSize) -> some View {
93 | ZStack {
94 | image
95 | .resizable()
96 | .aspectRatio(contentMode: .fit)
97 | .frame(width: size.width, height: size.height)
98 | .id(name)
99 | }
100 | .animation(.easeInOut(duration: duration), value: name)
101 | .blur(radius: self.blurRadius)
102 | }
103 | }
104 |
105 | // MARK: - Environment
106 | private struct MorphingDurationKey: EnvironmentKey {
107 | static var defaultValue: Double = 1
108 | }
109 |
110 | private extension EnvironmentValues {
111 | var morphingImageDuration: Double {
112 | get {
113 | self[MorphingDurationKey.self]
114 | } set {
115 | self[MorphingDurationKey.self] = newValue
116 | }
117 | }
118 | }
119 |
120 | public extension View {
121 | func morphingImageDuration(_ value: Double) -> some View {
122 | self.environment(\.morphingImageDuration, value)
123 | }
124 | }
125 |
126 | // MARK: - Preview
127 | struct MorphingImage_Previews: PreviewProvider {
128 | static let names = [
129 | "circle.fill",
130 | "heart.fill",
131 | "star.fill",
132 | "bell.fill",
133 | "bookmark.fill",
134 | "tag.fill",
135 | "bolt.fill",
136 | "play.fill",
137 | "pause.fill",
138 | "squareshape.fill",
139 | "key.fill",
140 | "hexagon.fill",
141 | "gearshape.fill",
142 | ]
143 |
144 | static var previews: some View {
145 | TimelineView(.animation(minimumInterval: 2)) { context in
146 | MorphingImage(systemName: names.randomElement()!)
147 | }
148 | .foregroundColor(.accentColor)
149 | .frame(width: 128, height: 128)
150 | .previewLayout(.fixed(width: 128, height: 128))
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/Demo/Demo.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 56;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 455E9DDA28E8CBD70033E264 /* DemoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 455E9DD928E8CBD70033E264 /* DemoApp.swift */; };
11 | 455E9DDC28E8CBD70033E264 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 455E9DDB28E8CBD70033E264 /* ContentView.swift */; };
12 | 455E9DDE28E8CBD80033E264 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 455E9DDD28E8CBD80033E264 /* Assets.xcassets */; };
13 | 455E9DE228E8CBD80033E264 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 455E9DE128E8CBD80033E264 /* Preview Assets.xcassets */; };
14 | 455E9DEB28E8CBF60033E264 /* ImageMorphing in Frameworks */ = {isa = PBXBuildFile; productRef = 455E9DEA28E8CBF60033E264 /* ImageMorphing */; };
15 | 4561D7A828E8CDE100F90609 /* Box.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4561D7A728E8CDE100F90609 /* Box.swift */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXFileReference section */
19 | 455E9DD628E8CBD70033E264 /* Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Demo.app; sourceTree = BUILT_PRODUCTS_DIR; };
20 | 455E9DD928E8CBD70033E264 /* DemoApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoApp.swift; sourceTree = ""; };
21 | 455E9DDB28E8CBD70033E264 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
22 | 455E9DDD28E8CBD80033E264 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
23 | 455E9DDF28E8CBD80033E264 /* Demo.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Demo.entitlements; sourceTree = ""; };
24 | 455E9DE128E8CBD80033E264 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
25 | 455E9DE828E8CBEB0033E264 /* ImageMorphing */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = ImageMorphing; path = ..; sourceTree = ""; };
26 | 4561D7A728E8CDE100F90609 /* Box.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Box.swift; sourceTree = ""; };
27 | /* End PBXFileReference section */
28 |
29 | /* Begin PBXFrameworksBuildPhase section */
30 | 455E9DD328E8CBD70033E264 /* Frameworks */ = {
31 | isa = PBXFrameworksBuildPhase;
32 | buildActionMask = 2147483647;
33 | files = (
34 | 455E9DEB28E8CBF60033E264 /* ImageMorphing in Frameworks */,
35 | );
36 | runOnlyForDeploymentPostprocessing = 0;
37 | };
38 | /* End PBXFrameworksBuildPhase section */
39 |
40 | /* Begin PBXGroup section */
41 | 455E9DCD28E8CBD70033E264 = {
42 | isa = PBXGroup;
43 | children = (
44 | 455E9DE828E8CBEB0033E264 /* ImageMorphing */,
45 | 455E9DD828E8CBD70033E264 /* Demo */,
46 | 455E9DD728E8CBD70033E264 /* Products */,
47 | 455E9DE928E8CBF60033E264 /* Frameworks */,
48 | );
49 | sourceTree = "";
50 | };
51 | 455E9DD728E8CBD70033E264 /* Products */ = {
52 | isa = PBXGroup;
53 | children = (
54 | 455E9DD628E8CBD70033E264 /* Demo.app */,
55 | );
56 | name = Products;
57 | sourceTree = "";
58 | };
59 | 455E9DD828E8CBD70033E264 /* Demo */ = {
60 | isa = PBXGroup;
61 | children = (
62 | 455E9DD928E8CBD70033E264 /* DemoApp.swift */,
63 | 455E9DDB28E8CBD70033E264 /* ContentView.swift */,
64 | 4561D7A728E8CDE100F90609 /* Box.swift */,
65 | 455E9DDD28E8CBD80033E264 /* Assets.xcassets */,
66 | 455E9DDF28E8CBD80033E264 /* Demo.entitlements */,
67 | 455E9DE028E8CBD80033E264 /* Preview Content */,
68 | );
69 | path = Demo;
70 | sourceTree = "";
71 | };
72 | 455E9DE028E8CBD80033E264 /* Preview Content */ = {
73 | isa = PBXGroup;
74 | children = (
75 | 455E9DE128E8CBD80033E264 /* Preview Assets.xcassets */,
76 | );
77 | path = "Preview Content";
78 | sourceTree = "";
79 | };
80 | 455E9DE928E8CBF60033E264 /* Frameworks */ = {
81 | isa = PBXGroup;
82 | children = (
83 | );
84 | name = Frameworks;
85 | sourceTree = "";
86 | };
87 | /* End PBXGroup section */
88 |
89 | /* Begin PBXNativeTarget section */
90 | 455E9DD528E8CBD70033E264 /* Demo */ = {
91 | isa = PBXNativeTarget;
92 | buildConfigurationList = 455E9DE528E8CBD80033E264 /* Build configuration list for PBXNativeTarget "Demo" */;
93 | buildPhases = (
94 | 455E9DD228E8CBD70033E264 /* Sources */,
95 | 455E9DD328E8CBD70033E264 /* Frameworks */,
96 | 455E9DD428E8CBD70033E264 /* Resources */,
97 | );
98 | buildRules = (
99 | );
100 | dependencies = (
101 | );
102 | name = Demo;
103 | packageProductDependencies = (
104 | 455E9DEA28E8CBF60033E264 /* ImageMorphing */,
105 | );
106 | productName = Demo;
107 | productReference = 455E9DD628E8CBD70033E264 /* Demo.app */;
108 | productType = "com.apple.product-type.application";
109 | };
110 | /* End PBXNativeTarget section */
111 |
112 | /* Begin PBXProject section */
113 | 455E9DCE28E8CBD70033E264 /* Project object */ = {
114 | isa = PBXProject;
115 | attributes = {
116 | BuildIndependentTargetsInParallel = 1;
117 | LastSwiftUpdateCheck = 1410;
118 | LastUpgradeCheck = 1410;
119 | TargetAttributes = {
120 | 455E9DD528E8CBD70033E264 = {
121 | CreatedOnToolsVersion = 14.1;
122 | };
123 | };
124 | };
125 | buildConfigurationList = 455E9DD128E8CBD70033E264 /* Build configuration list for PBXProject "Demo" */;
126 | compatibilityVersion = "Xcode 14.0";
127 | developmentRegion = en;
128 | hasScannedForEncodings = 0;
129 | knownRegions = (
130 | en,
131 | Base,
132 | );
133 | mainGroup = 455E9DCD28E8CBD70033E264;
134 | productRefGroup = 455E9DD728E8CBD70033E264 /* Products */;
135 | projectDirPath = "";
136 | projectRoot = "";
137 | targets = (
138 | 455E9DD528E8CBD70033E264 /* Demo */,
139 | );
140 | };
141 | /* End PBXProject section */
142 |
143 | /* Begin PBXResourcesBuildPhase section */
144 | 455E9DD428E8CBD70033E264 /* Resources */ = {
145 | isa = PBXResourcesBuildPhase;
146 | buildActionMask = 2147483647;
147 | files = (
148 | 455E9DE228E8CBD80033E264 /* Preview Assets.xcassets in Resources */,
149 | 455E9DDE28E8CBD80033E264 /* Assets.xcassets in Resources */,
150 | );
151 | runOnlyForDeploymentPostprocessing = 0;
152 | };
153 | /* End PBXResourcesBuildPhase section */
154 |
155 | /* Begin PBXSourcesBuildPhase section */
156 | 455E9DD228E8CBD70033E264 /* Sources */ = {
157 | isa = PBXSourcesBuildPhase;
158 | buildActionMask = 2147483647;
159 | files = (
160 | 4561D7A828E8CDE100F90609 /* Box.swift in Sources */,
161 | 455E9DDC28E8CBD70033E264 /* ContentView.swift in Sources */,
162 | 455E9DDA28E8CBD70033E264 /* DemoApp.swift in Sources */,
163 | );
164 | runOnlyForDeploymentPostprocessing = 0;
165 | };
166 | /* End PBXSourcesBuildPhase section */
167 |
168 | /* Begin XCBuildConfiguration section */
169 | 455E9DE328E8CBD80033E264 /* Debug */ = {
170 | isa = XCBuildConfiguration;
171 | buildSettings = {
172 | ALWAYS_SEARCH_USER_PATHS = NO;
173 | CLANG_ANALYZER_NONNULL = YES;
174 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
175 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
176 | CLANG_ENABLE_MODULES = YES;
177 | CLANG_ENABLE_OBJC_ARC = YES;
178 | CLANG_ENABLE_OBJC_WEAK = YES;
179 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
180 | CLANG_WARN_BOOL_CONVERSION = YES;
181 | CLANG_WARN_COMMA = YES;
182 | CLANG_WARN_CONSTANT_CONVERSION = YES;
183 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
184 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
185 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
186 | CLANG_WARN_EMPTY_BODY = YES;
187 | CLANG_WARN_ENUM_CONVERSION = YES;
188 | CLANG_WARN_INFINITE_RECURSION = YES;
189 | CLANG_WARN_INT_CONVERSION = YES;
190 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
191 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
192 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
193 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
194 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
195 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
196 | CLANG_WARN_STRICT_PROTOTYPES = YES;
197 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
198 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
199 | CLANG_WARN_UNREACHABLE_CODE = YES;
200 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
201 | COPY_PHASE_STRIP = NO;
202 | DEBUG_INFORMATION_FORMAT = dwarf;
203 | ENABLE_STRICT_OBJC_MSGSEND = YES;
204 | ENABLE_TESTABILITY = YES;
205 | GCC_C_LANGUAGE_STANDARD = gnu11;
206 | GCC_DYNAMIC_NO_PIC = NO;
207 | GCC_NO_COMMON_BLOCKS = YES;
208 | GCC_OPTIMIZATION_LEVEL = 0;
209 | GCC_PREPROCESSOR_DEFINITIONS = (
210 | "DEBUG=1",
211 | "$(inherited)",
212 | );
213 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
214 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
215 | GCC_WARN_UNDECLARED_SELECTOR = YES;
216 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
217 | GCC_WARN_UNUSED_FUNCTION = YES;
218 | GCC_WARN_UNUSED_VARIABLE = YES;
219 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
220 | MTL_FAST_MATH = YES;
221 | ONLY_ACTIVE_ARCH = YES;
222 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
223 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
224 | };
225 | name = Debug;
226 | };
227 | 455E9DE428E8CBD80033E264 /* Release */ = {
228 | isa = XCBuildConfiguration;
229 | buildSettings = {
230 | ALWAYS_SEARCH_USER_PATHS = NO;
231 | CLANG_ANALYZER_NONNULL = YES;
232 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
233 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
234 | CLANG_ENABLE_MODULES = YES;
235 | CLANG_ENABLE_OBJC_ARC = YES;
236 | CLANG_ENABLE_OBJC_WEAK = YES;
237 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
238 | CLANG_WARN_BOOL_CONVERSION = YES;
239 | CLANG_WARN_COMMA = YES;
240 | CLANG_WARN_CONSTANT_CONVERSION = YES;
241 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
242 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
243 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
244 | CLANG_WARN_EMPTY_BODY = YES;
245 | CLANG_WARN_ENUM_CONVERSION = YES;
246 | CLANG_WARN_INFINITE_RECURSION = YES;
247 | CLANG_WARN_INT_CONVERSION = YES;
248 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
249 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
250 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
251 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
252 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
253 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
254 | CLANG_WARN_STRICT_PROTOTYPES = YES;
255 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
256 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
257 | CLANG_WARN_UNREACHABLE_CODE = YES;
258 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
259 | COPY_PHASE_STRIP = NO;
260 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
261 | ENABLE_NS_ASSERTIONS = NO;
262 | ENABLE_STRICT_OBJC_MSGSEND = YES;
263 | GCC_C_LANGUAGE_STANDARD = gnu11;
264 | GCC_NO_COMMON_BLOCKS = YES;
265 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
266 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
267 | GCC_WARN_UNDECLARED_SELECTOR = YES;
268 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
269 | GCC_WARN_UNUSED_FUNCTION = YES;
270 | GCC_WARN_UNUSED_VARIABLE = YES;
271 | MTL_ENABLE_DEBUG_INFO = NO;
272 | MTL_FAST_MATH = YES;
273 | SWIFT_COMPILATION_MODE = wholemodule;
274 | SWIFT_OPTIMIZATION_LEVEL = "-O";
275 | };
276 | name = Release;
277 | };
278 | 455E9DE628E8CBD80033E264 /* Debug */ = {
279 | isa = XCBuildConfiguration;
280 | buildSettings = {
281 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
282 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
283 | CODE_SIGN_ENTITLEMENTS = Demo/Demo.entitlements;
284 | CODE_SIGN_STYLE = Automatic;
285 | CURRENT_PROJECT_VERSION = 1;
286 | DEVELOPMENT_ASSET_PATHS = "\"Demo/Preview Content\"";
287 | ENABLE_HARDENED_RUNTIME = YES;
288 | ENABLE_PREVIEWS = YES;
289 | GENERATE_INFOPLIST_FILE = YES;
290 | "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
291 | "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
292 | "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
293 | "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES;
294 | "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES;
295 | "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES;
296 | "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault;
297 | "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
298 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
299 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
300 | IPHONEOS_DEPLOYMENT_TARGET = 15.1;
301 | LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
302 | "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
303 | MACOSX_DEPLOYMENT_TARGET = 13.0;
304 | MARKETING_VERSION = 1.0;
305 | PRODUCT_BUNDLE_IDENTIFIER = com.kodlian.ImageMorphingDemo;
306 | PRODUCT_NAME = "$(TARGET_NAME)";
307 | SDKROOT = auto;
308 | SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
309 | SWIFT_EMIT_LOC_STRINGS = YES;
310 | SWIFT_VERSION = 5.0;
311 | TARGETED_DEVICE_FAMILY = "1,2";
312 | };
313 | name = Debug;
314 | };
315 | 455E9DE728E8CBD80033E264 /* Release */ = {
316 | isa = XCBuildConfiguration;
317 | buildSettings = {
318 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
319 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
320 | CODE_SIGN_ENTITLEMENTS = Demo/Demo.entitlements;
321 | CODE_SIGN_STYLE = Automatic;
322 | CURRENT_PROJECT_VERSION = 1;
323 | DEVELOPMENT_ASSET_PATHS = "\"Demo/Preview Content\"";
324 | ENABLE_HARDENED_RUNTIME = YES;
325 | ENABLE_PREVIEWS = YES;
326 | GENERATE_INFOPLIST_FILE = YES;
327 | "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
328 | "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
329 | "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
330 | "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES;
331 | "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES;
332 | "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES;
333 | "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault;
334 | "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
335 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
336 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
337 | IPHONEOS_DEPLOYMENT_TARGET = 15.1;
338 | LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
339 | "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
340 | MACOSX_DEPLOYMENT_TARGET = 13.0;
341 | MARKETING_VERSION = 1.0;
342 | PRODUCT_BUNDLE_IDENTIFIER = com.kodlian.ImageMorphingDemo;
343 | PRODUCT_NAME = "$(TARGET_NAME)";
344 | SDKROOT = auto;
345 | SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
346 | SWIFT_EMIT_LOC_STRINGS = YES;
347 | SWIFT_VERSION = 5.0;
348 | TARGETED_DEVICE_FAMILY = "1,2";
349 | };
350 | name = Release;
351 | };
352 | /* End XCBuildConfiguration section */
353 |
354 | /* Begin XCConfigurationList section */
355 | 455E9DD128E8CBD70033E264 /* Build configuration list for PBXProject "Demo" */ = {
356 | isa = XCConfigurationList;
357 | buildConfigurations = (
358 | 455E9DE328E8CBD80033E264 /* Debug */,
359 | 455E9DE428E8CBD80033E264 /* Release */,
360 | );
361 | defaultConfigurationIsVisible = 0;
362 | defaultConfigurationName = Release;
363 | };
364 | 455E9DE528E8CBD80033E264 /* Build configuration list for PBXNativeTarget "Demo" */ = {
365 | isa = XCConfigurationList;
366 | buildConfigurations = (
367 | 455E9DE628E8CBD80033E264 /* Debug */,
368 | 455E9DE728E8CBD80033E264 /* Release */,
369 | );
370 | defaultConfigurationIsVisible = 0;
371 | defaultConfigurationName = Release;
372 | };
373 | /* End XCConfigurationList section */
374 |
375 | /* Begin XCSwiftPackageProductDependency section */
376 | 455E9DEA28E8CBF60033E264 /* ImageMorphing */ = {
377 | isa = XCSwiftPackageProductDependency;
378 | productName = ImageMorphing;
379 | };
380 | /* End XCSwiftPackageProductDependency section */
381 | };
382 | rootObject = 455E9DCE28E8CBD70033E264 /* Project object */;
383 | }
384 |
--------------------------------------------------------------------------------