├── README.md
├── SSMetalImageFilter
├── Resource
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── WorkPlay.jpg
│ └── TestImage.jpg
├── AppDelegate.swift
├── Info.plist
├── View
│ └── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
└── Controller
│ └── FilterViewController.swift
├── SSMetalImageFilter.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── project.pbxproj
└── .gitignore
/README.md:
--------------------------------------------------------------------------------
1 | # SSMetalImageFilter
--------------------------------------------------------------------------------
/SSMetalImageFilter/Resource/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/SSMetalImageFilter/Resource/WorkPlay.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mobile-simformsolutions/SSMetalImageFilter/HEAD/SSMetalImageFilter/Resource/WorkPlay.jpg
--------------------------------------------------------------------------------
/SSMetalImageFilter/Resource/TestImage.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mobile-simformsolutions/SSMetalImageFilter/HEAD/SSMetalImageFilter/Resource/TestImage.jpg
--------------------------------------------------------------------------------
/SSMetalImageFilter.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SSMetalImageFilter.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/SSMetalImageFilter/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // SSMetalImageFilter
4 | //
5 | // Created by Vishva Bhatt on 01/02/21.
6 | //
7 |
8 | import UIKit
9 |
10 | @main
11 | class AppDelegate: UIResponder, UIApplicationDelegate {
12 |
13 | var window: UIWindow?
14 |
15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
16 | // Override point for customization after application launch.
17 | return true
18 | }
19 |
20 |
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/SSMetalImageFilter/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSupportsIndirectInputEvents
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/SSMetalImageFilter/Resource/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/SSMetalImageFilter/View/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 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## User settings
6 | xcuserdata/
7 |
8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
9 | *.xcscmblueprint
10 | *.xccheckout
11 |
12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
13 | build/
14 | DerivedData/
15 | *.moved-aside
16 | *.pbxuser
17 | !default.pbxuser
18 | *.mode1v3
19 | !default.mode1v3
20 | *.mode2v3
21 | !default.mode2v3
22 | *.perspectivev3
23 | !default.perspectivev3
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 |
28 | ## App packaging
29 | *.ipa
30 | *.dSYM.zip
31 | *.dSYM
32 |
33 | ## Playgrounds
34 | timeline.xctimeline
35 | playground.xcworkspace
36 |
37 | # Swift Package Manager
38 | #
39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
40 | # Packages/
41 | # Package.pins
42 | # Package.resolved
43 | # *.xcodeproj
44 | #
45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
46 | # hence it is not needed unless you have added a package configuration file to your project
47 | # .swiftpm
48 |
49 | .build/
50 |
51 | # CocoaPods
52 | #
53 | # We recommend against adding the Pods directory to your .gitignore. However
54 | # you should judge for yourself, the pros and cons are mentioned at:
55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
56 | #
57 | # Pods/
58 | #
59 | # Add this line if you want to avoid checking in source code from the Xcode workspace
60 | # *.xcworkspace
61 |
62 | # Carthage
63 | #
64 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
65 | # Carthage/Checkouts
66 |
67 | Carthage/Build/
68 |
69 | # Accio dependency management
70 | Dependencies/
71 | .accio/
72 |
73 | # fastlane
74 | #
75 | # It is recommended to not store the screenshots in the git repo.
76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed.
77 | # For more information about the recommended setup visit:
78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
79 |
80 | fastlane/report.xml
81 | fastlane/Preview.html
82 | fastlane/screenshots/**/*.png
83 | fastlane/test_output
84 |
85 | # Code Injection
86 | #
87 | # After new code Injection tools there's a generated folder /iOSInjectionProject
88 | # https://github.com/johnno1962/injectionforxcode
89 |
90 | iOSInjectionProject/
91 |
--------------------------------------------------------------------------------
/SSMetalImageFilter/Controller/FilterViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FilterViewController.swift
3 | // SSMetalImageFilter
4 | //
5 | // Created by Vishva Bhatt on 10/04/21.
6 | //
7 |
8 | import UIKit
9 | import MetalKit
10 |
11 | enum PhotoTest : String {
12 | case workPlay = "WorkPlay"
13 | case tropical = "TestImage"
14 |
15 | }
16 |
17 | class FilterViewController: UIViewController {
18 |
19 | //MARK: Outlets
20 | @IBOutlet weak var imageView: UIImageView!
21 | @IBOutlet weak var saturationSlider: UISlider!
22 | @IBOutlet weak var modeSegment: UISegmentedControl!
23 | @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
24 | @IBOutlet weak var metalView: MTKView!
25 |
26 | //MARK: Metal resources
27 | var device: MTLDevice!
28 | var commandQueue: MTLCommandQueue!
29 | var sourceTexture: MTLTexture!
30 |
31 |
32 | //MARK: Core Image resources
33 | var context: CIContext!
34 | let inputImageViewImage = CIImage()
35 | let saturationFilter = CIFilter(name: "CIColorControls")
36 | let colorSpace = CGColorSpaceCreateDeviceRGB()
37 |
38 | var inputImageURL : URL!
39 | var currentImage : PhotoTest = PhotoTest.workPlay
40 |
41 | //MARK: View Life Cycle
42 | override func viewDidLoad() {
43 | self.setupMetal()
44 | }
45 |
46 | //MARK: User defined methods
47 | func setupMetal(){
48 | device = MTLCreateSystemDefaultDevice()
49 | commandQueue = device.makeCommandQueue()
50 |
51 | metalView.delegate = self
52 | metalView.device = device
53 | metalView.framebufferOnly = false
54 |
55 | context = CIContext(mtlDevice: device)
56 |
57 | // load texture as an MTL Texture
58 | let loader = MTKTextureLoader(device: device)
59 | guard let url = Bundle.main.url(forResource: currentImage.rawValue, withExtension: "jpg"), let image = UIImage(named: "\(currentImage.rawValue).jpg") else {
60 | return
61 | }
62 | inputImageURL = url;
63 | self.imageView.image = image
64 | // simulator shows this upside down, real devices show real way up
65 | #if targetEnvironment(simulator)
66 | sourceTexture = try! loader.newTexture(URL: url,
67 | options: [:])
68 | #else
69 | sourceTexture = try! loader.newTexture(URL: url,
70 | options: [MTKTextureLoader.Option.origin: MTKTextureLoader.Origin.flippedVertically])
71 | #endif
72 | self.metalView.clearColor = MTLClearColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0)
73 | }
74 |
75 | func handleViewStates(isUserInteractionEnabled:Bool=false) {
76 | DispatchQueue.main.async {
77 | if (isUserInteractionEnabled == false) {
78 | self.activityIndicator.startAnimating()
79 |
80 | }else {
81 | self.activityIndicator.stopAnimating()
82 | }
83 | }
84 | }
85 |
86 | //MARK: Actions
87 | @IBAction func saturationSliderChanges(_ sender: UISlider) {
88 | if (self.modeSegment.selectedSegmentIndex == 1) {
89 | let valueofSlider = sender.value
90 | DispatchQueue.global(qos: .userInitiated).async {[weak self] in
91 | guard let self = self else {
92 | return
93 | }
94 | self.handleViewStates(isUserInteractionEnabled: false)
95 | if let freshSaturationFilter = self.saturationFilter, let inputImage = CIImage(contentsOf: self.inputImageURL) {
96 | freshSaturationFilter.setValue(inputImage, forKey: kCIInputImageKey)
97 | freshSaturationFilter.setValue(valueofSlider, forKey: kCIInputSaturationKey)
98 | if let output = freshSaturationFilter.outputImage {
99 | if let cgimg = self.context.createCGImage(output, from: output.extent) {
100 | let processedImage = UIImage(cgImage: cgimg)
101 | DispatchQueue.main.async {
102 | self.imageView.image = processedImage;
103 | }
104 | self.handleViewStates(isUserInteractionEnabled: true)
105 |
106 | }
107 | } else {
108 | self.handleViewStates(isUserInteractionEnabled: true)
109 | }
110 | } else {
111 | self.handleViewStates(isUserInteractionEnabled: true)
112 | }
113 | }
114 | }
115 | }
116 |
117 | @IBAction func defaultAction(_ sender: UIButton) {
118 | self.saturationSlider.value = 1.0;
119 | if (self.modeSegment.selectedSegmentIndex == 1) {
120 | self.saturationSliderChanges(self.saturationSlider)
121 | }
122 | }
123 |
124 | @IBAction func viewModeChanged(_ sender: UISegmentedControl) {
125 | self.defaultAction(UIButton())
126 | self.saturationSlider.isContinuous = sender.selectedSegmentIndex == 0
127 | self.metalView.isHidden = !(sender.selectedSegmentIndex == 0)
128 | self.imageView.isHidden = sender.selectedSegmentIndex == 0
129 | if (sender.selectedSegmentIndex == 1) {
130 | self.metalView.isPaused = true
131 | } else {
132 | self.metalView.isPaused = false
133 | }
134 | }
135 |
136 | @IBAction func saveImageAction(_ sender: UIButton) {
137 | guard let outputImage = self.saturationFilter?.outputImage else {
138 | return
139 | }
140 |
141 | let processedImage = UIImage(ciImage: outputImage, scale: 1, orientation: UIImage.Orientation.downMirrored)
142 | let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
143 | if let filePath = paths.first?.appendingPathComponent("FilteredImage.jpg") {
144 | print("Output Path \(filePath)")
145 | if FileManager.default.fileExists(atPath: filePath.path) {
146 | try? FileManager.default.removeItem(atPath: filePath.path)
147 | }
148 | do {
149 | try processedImage.jpegData(compressionQuality: 0.8)?.write(to: filePath, options: .atomic)
150 | } catch {
151 | // Handle the error
152 | }
153 | }
154 | }
155 |
156 | }
157 | //MARK: Confirmed Delegation
158 |
159 | extension FilterViewController: MTKViewDelegate {
160 |
161 | func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {}
162 |
163 | func draw(in view: MTKView) {
164 | if let currentDrawable = view.currentDrawable, let sourceTexture = sourceTexture , let commandBuffer = commandQueue.makeCommandBuffer(), let inputImage = CIImage(mtlTexture: sourceTexture), let saturationFilter = saturationFilter {
165 |
166 | // you can chain multiple filters here
167 | saturationFilter.setValue(inputImage, forKey: kCIInputImageKey)
168 | saturationFilter.setValue(saturationSlider.value as NSNumber, forKey: kCIInputSaturationKey)
169 |
170 | let bounds = CGRect(x: 0, y: 0, width: view.drawableSize.width, height: view.drawableSize.height)
171 |
172 | let scaleX = view.drawableSize.width / inputImage.extent.width
173 | let scaleY = view.drawableSize.height / inputImage.extent.height
174 | var scale : CGFloat = 1.0
175 | scale = (scaleY > scaleX) ? min(scaleX, scaleY) : max(scaleX, scaleY)
176 |
177 | let width = inputImage.extent.width * scale
178 | let height = inputImage.extent.height * scale
179 | let originX = (bounds.width - width) / 2
180 | let originY = (bounds.height - height) / 2
181 |
182 | if let saturationOutput = saturationFilter.outputImage {
183 | let scaledImage = saturationOutput
184 | .transformed(by: CGAffineTransform(scaleX: scale, y: scale))
185 | .transformed(by: CGAffineTransform(translationX: originX < 0 ? 0 : originX, y: originY < 0 ? 0 : originY))
186 |
187 | context.render(scaledImage,
188 | to: currentDrawable.texture,
189 | commandBuffer: commandBuffer,
190 | bounds: bounds,
191 | colorSpace: colorSpace)
192 |
193 | commandBuffer.present(currentDrawable)
194 | commandBuffer.commit()
195 | }
196 | }
197 | }
198 | }
199 |
--------------------------------------------------------------------------------
/SSMetalImageFilter/View/Base.lproj/Main.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 |
27 |
28 |
29 |
37 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/SSMetalImageFilter.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 83946F4B26666AE900842FD9 /* FilterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83959EA5262217590003492F /* FilterViewController.swift */; };
11 | 83B58CDD25C8385A00DDFB22 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83B58CDC25C8385A00DDFB22 /* AppDelegate.swift */; };
12 | 83B58CE425C8385A00DDFB22 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 83B58CE225C8385A00DDFB22 /* Main.storyboard */; };
13 | 83B58CE625C8385B00DDFB22 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 83B58CE525C8385B00DDFB22 /* Assets.xcassets */; };
14 | 83B58CE925C8385B00DDFB22 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 83B58CE725C8385B00DDFB22 /* LaunchScreen.storyboard */; };
15 | 83D1BCF6267C93F0001E1C9F /* WorkPlay.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 83D1BCF5267C93F0001E1C9F /* WorkPlay.jpg */; };
16 | 83F87E0D267B7A2E00B3BD94 /* TestImage.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 83C614C4265CC9420053C197 /* TestImage.jpg */; };
17 | /* End PBXBuildFile section */
18 |
19 | /* Begin PBXFileReference section */
20 | 83959EA5262217590003492F /* FilterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterViewController.swift; sourceTree = ""; };
21 | 83B58CD925C8385A00DDFB22 /* SSMetalImageFilter.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SSMetalImageFilter.app; sourceTree = BUILT_PRODUCTS_DIR; };
22 | 83B58CDC25C8385A00DDFB22 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
23 | 83B58CE325C8385A00DDFB22 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
24 | 83B58CE525C8385B00DDFB22 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
25 | 83B58CE825C8385B00DDFB22 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
26 | 83B58CEA25C8385B00DDFB22 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
27 | 83C614C4265CC9420053C197 /* TestImage.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = TestImage.jpg; sourceTree = ""; };
28 | 83D1BCF5267C93F0001E1C9F /* WorkPlay.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = WorkPlay.jpg; sourceTree = ""; };
29 | /* End PBXFileReference section */
30 |
31 | /* Begin PBXFrameworksBuildPhase section */
32 | 83B58CD625C8385A00DDFB22 /* Frameworks */ = {
33 | isa = PBXFrameworksBuildPhase;
34 | buildActionMask = 2147483647;
35 | files = (
36 | );
37 | runOnlyForDeploymentPostprocessing = 0;
38 | };
39 | /* End PBXFrameworksBuildPhase section */
40 |
41 | /* Begin PBXGroup section */
42 | 83959EA22622170C0003492F /* View */ = {
43 | isa = PBXGroup;
44 | children = (
45 | 83B58CE225C8385A00DDFB22 /* Main.storyboard */,
46 | 83B58CE725C8385B00DDFB22 /* LaunchScreen.storyboard */,
47 | );
48 | path = View;
49 | sourceTree = "";
50 | };
51 | 83959EA3262217190003492F /* Controller */ = {
52 | isa = PBXGroup;
53 | children = (
54 | 83959EA5262217590003492F /* FilterViewController.swift */,
55 | );
56 | path = Controller;
57 | sourceTree = "";
58 | };
59 | 83959EA42622172B0003492F /* Resource */ = {
60 | isa = PBXGroup;
61 | children = (
62 | 83D1BCF5267C93F0001E1C9F /* WorkPlay.jpg */,
63 | 83B58CE525C8385B00DDFB22 /* Assets.xcassets */,
64 | 83C614C4265CC9420053C197 /* TestImage.jpg */,
65 | );
66 | path = Resource;
67 | sourceTree = "";
68 | };
69 | 83B58CD025C8385A00DDFB22 = {
70 | isa = PBXGroup;
71 | children = (
72 | 83B58CDB25C8385A00DDFB22 /* SSMetalImageFilter */,
73 | 83B58CDA25C8385A00DDFB22 /* Products */,
74 | );
75 | sourceTree = "";
76 | };
77 | 83B58CDA25C8385A00DDFB22 /* Products */ = {
78 | isa = PBXGroup;
79 | children = (
80 | 83B58CD925C8385A00DDFB22 /* SSMetalImageFilter.app */,
81 | );
82 | name = Products;
83 | sourceTree = "";
84 | };
85 | 83B58CDB25C8385A00DDFB22 /* SSMetalImageFilter */ = {
86 | isa = PBXGroup;
87 | children = (
88 | 83B58CDC25C8385A00DDFB22 /* AppDelegate.swift */,
89 | 83B58CEA25C8385B00DDFB22 /* Info.plist */,
90 | 83959EA42622172B0003492F /* Resource */,
91 | 83959EA3262217190003492F /* Controller */,
92 | 83959EA22622170C0003492F /* View */,
93 | );
94 | path = SSMetalImageFilter;
95 | sourceTree = "";
96 | };
97 | /* End PBXGroup section */
98 |
99 | /* Begin PBXNativeTarget section */
100 | 83B58CD825C8385A00DDFB22 /* ImageFilter_ML */ = {
101 | isa = PBXNativeTarget;
102 | buildConfigurationList = 83B58CED25C8385B00DDFB22 /* Build configuration list for PBXNativeTarget "ImageFilter_ML" */;
103 | buildPhases = (
104 | 83B58CD525C8385A00DDFB22 /* Sources */,
105 | 83B58CD625C8385A00DDFB22 /* Frameworks */,
106 | 83B58CD725C8385A00DDFB22 /* Resources */,
107 | );
108 | buildRules = (
109 | );
110 | dependencies = (
111 | );
112 | name = ImageFilter_ML;
113 | productName = ImageFilter_ML;
114 | productReference = 83B58CD925C8385A00DDFB22 /* SSMetalImageFilter.app */;
115 | productType = "com.apple.product-type.application";
116 | };
117 | /* End PBXNativeTarget section */
118 |
119 | /* Begin PBXProject section */
120 | 83B58CD125C8385A00DDFB22 /* Project object */ = {
121 | isa = PBXProject;
122 | attributes = {
123 | LastSwiftUpdateCheck = 1210;
124 | LastUpgradeCheck = 1210;
125 | ORGANIZATIONNAME = Simform;
126 | TargetAttributes = {
127 | 83B58CD825C8385A00DDFB22 = {
128 | CreatedOnToolsVersion = 12.1;
129 | };
130 | };
131 | };
132 | buildConfigurationList = 83B58CD425C8385A00DDFB22 /* Build configuration list for PBXProject "SSMetalImageFilter" */;
133 | compatibilityVersion = "Xcode 9.3";
134 | developmentRegion = en;
135 | hasScannedForEncodings = 0;
136 | knownRegions = (
137 | en,
138 | Base,
139 | );
140 | mainGroup = 83B58CD025C8385A00DDFB22;
141 | productRefGroup = 83B58CDA25C8385A00DDFB22 /* Products */;
142 | projectDirPath = "";
143 | projectRoot = "";
144 | targets = (
145 | 83B58CD825C8385A00DDFB22 /* ImageFilter_ML */,
146 | );
147 | };
148 | /* End PBXProject section */
149 |
150 | /* Begin PBXResourcesBuildPhase section */
151 | 83B58CD725C8385A00DDFB22 /* Resources */ = {
152 | isa = PBXResourcesBuildPhase;
153 | buildActionMask = 2147483647;
154 | files = (
155 | 83D1BCF6267C93F0001E1C9F /* WorkPlay.jpg in Resources */,
156 | 83B58CE925C8385B00DDFB22 /* LaunchScreen.storyboard in Resources */,
157 | 83F87E0D267B7A2E00B3BD94 /* TestImage.jpg in Resources */,
158 | 83B58CE625C8385B00DDFB22 /* Assets.xcassets in Resources */,
159 | 83B58CE425C8385A00DDFB22 /* Main.storyboard in Resources */,
160 | );
161 | runOnlyForDeploymentPostprocessing = 0;
162 | };
163 | /* End PBXResourcesBuildPhase section */
164 |
165 | /* Begin PBXSourcesBuildPhase section */
166 | 83B58CD525C8385A00DDFB22 /* Sources */ = {
167 | isa = PBXSourcesBuildPhase;
168 | buildActionMask = 2147483647;
169 | files = (
170 | 83946F4B26666AE900842FD9 /* FilterViewController.swift in Sources */,
171 | 83B58CDD25C8385A00DDFB22 /* AppDelegate.swift in Sources */,
172 | );
173 | runOnlyForDeploymentPostprocessing = 0;
174 | };
175 | /* End PBXSourcesBuildPhase section */
176 |
177 | /* Begin PBXVariantGroup section */
178 | 83B58CE225C8385A00DDFB22 /* Main.storyboard */ = {
179 | isa = PBXVariantGroup;
180 | children = (
181 | 83B58CE325C8385A00DDFB22 /* Base */,
182 | );
183 | name = Main.storyboard;
184 | sourceTree = "";
185 | };
186 | 83B58CE725C8385B00DDFB22 /* LaunchScreen.storyboard */ = {
187 | isa = PBXVariantGroup;
188 | children = (
189 | 83B58CE825C8385B00DDFB22 /* Base */,
190 | );
191 | name = LaunchScreen.storyboard;
192 | sourceTree = "";
193 | };
194 | /* End PBXVariantGroup section */
195 |
196 | /* Begin XCBuildConfiguration section */
197 | 83B58CEB25C8385B00DDFB22 /* Debug */ = {
198 | isa = XCBuildConfiguration;
199 | buildSettings = {
200 | ALWAYS_SEARCH_USER_PATHS = NO;
201 | CLANG_ANALYZER_NONNULL = YES;
202 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
203 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
204 | CLANG_CXX_LIBRARY = "libc++";
205 | CLANG_ENABLE_MODULES = YES;
206 | CLANG_ENABLE_OBJC_ARC = YES;
207 | CLANG_ENABLE_OBJC_WEAK = YES;
208 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
209 | CLANG_WARN_BOOL_CONVERSION = YES;
210 | CLANG_WARN_COMMA = YES;
211 | CLANG_WARN_CONSTANT_CONVERSION = YES;
212 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
213 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
214 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
215 | CLANG_WARN_EMPTY_BODY = YES;
216 | CLANG_WARN_ENUM_CONVERSION = YES;
217 | CLANG_WARN_INFINITE_RECURSION = YES;
218 | CLANG_WARN_INT_CONVERSION = YES;
219 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
220 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
221 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
222 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
223 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
224 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
225 | CLANG_WARN_STRICT_PROTOTYPES = YES;
226 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
227 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
228 | CLANG_WARN_UNREACHABLE_CODE = YES;
229 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
230 | COPY_PHASE_STRIP = NO;
231 | DEBUG_INFORMATION_FORMAT = dwarf;
232 | ENABLE_STRICT_OBJC_MSGSEND = YES;
233 | ENABLE_TESTABILITY = YES;
234 | GCC_C_LANGUAGE_STANDARD = gnu11;
235 | GCC_DYNAMIC_NO_PIC = NO;
236 | GCC_NO_COMMON_BLOCKS = YES;
237 | GCC_OPTIMIZATION_LEVEL = 0;
238 | GCC_PREPROCESSOR_DEFINITIONS = (
239 | "DEBUG=1",
240 | "$(inherited)",
241 | );
242 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
243 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
244 | GCC_WARN_UNDECLARED_SELECTOR = YES;
245 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
246 | GCC_WARN_UNUSED_FUNCTION = YES;
247 | GCC_WARN_UNUSED_VARIABLE = YES;
248 | IPHONEOS_DEPLOYMENT_TARGET = 14.1;
249 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
250 | MTL_FAST_MATH = YES;
251 | ONLY_ACTIVE_ARCH = YES;
252 | SDKROOT = iphoneos;
253 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
254 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
255 | };
256 | name = Debug;
257 | };
258 | 83B58CEC25C8385B00DDFB22 /* Release */ = {
259 | isa = XCBuildConfiguration;
260 | buildSettings = {
261 | ALWAYS_SEARCH_USER_PATHS = NO;
262 | CLANG_ANALYZER_NONNULL = YES;
263 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
264 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
265 | CLANG_CXX_LIBRARY = "libc++";
266 | CLANG_ENABLE_MODULES = YES;
267 | CLANG_ENABLE_OBJC_ARC = YES;
268 | CLANG_ENABLE_OBJC_WEAK = YES;
269 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
270 | CLANG_WARN_BOOL_CONVERSION = YES;
271 | CLANG_WARN_COMMA = YES;
272 | CLANG_WARN_CONSTANT_CONVERSION = YES;
273 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
274 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
275 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
276 | CLANG_WARN_EMPTY_BODY = YES;
277 | CLANG_WARN_ENUM_CONVERSION = YES;
278 | CLANG_WARN_INFINITE_RECURSION = YES;
279 | CLANG_WARN_INT_CONVERSION = YES;
280 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
281 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
282 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
283 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
284 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
285 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
286 | CLANG_WARN_STRICT_PROTOTYPES = YES;
287 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
288 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
289 | CLANG_WARN_UNREACHABLE_CODE = YES;
290 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
291 | COPY_PHASE_STRIP = NO;
292 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
293 | ENABLE_NS_ASSERTIONS = NO;
294 | ENABLE_STRICT_OBJC_MSGSEND = YES;
295 | GCC_C_LANGUAGE_STANDARD = gnu11;
296 | GCC_NO_COMMON_BLOCKS = YES;
297 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
298 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
299 | GCC_WARN_UNDECLARED_SELECTOR = YES;
300 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
301 | GCC_WARN_UNUSED_FUNCTION = YES;
302 | GCC_WARN_UNUSED_VARIABLE = YES;
303 | IPHONEOS_DEPLOYMENT_TARGET = 14.1;
304 | MTL_ENABLE_DEBUG_INFO = NO;
305 | MTL_FAST_MATH = YES;
306 | SDKROOT = iphoneos;
307 | SWIFT_COMPILATION_MODE = wholemodule;
308 | SWIFT_OPTIMIZATION_LEVEL = "-O";
309 | VALIDATE_PRODUCT = YES;
310 | };
311 | name = Release;
312 | };
313 | 83B58CEE25C8385B00DDFB22 /* Debug */ = {
314 | isa = XCBuildConfiguration;
315 | buildSettings = {
316 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
317 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
318 | CODE_SIGN_STYLE = Automatic;
319 | DEVELOPMENT_TEAM = K7XJG666ZW;
320 | INFOPLIST_FILE = "$(SRCROOT)/SSMetalImageFilter/Info.plist";
321 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
322 | LD_RUNPATH_SEARCH_PATHS = (
323 | "$(inherited)",
324 | "@executable_path/Frameworks",
325 | );
326 | PRODUCT_BUNDLE_IDENTIFIER = com.metalimagefilter;
327 | PRODUCT_NAME = SSMetalImageFilter;
328 | SWIFT_VERSION = 5.0;
329 | TARGETED_DEVICE_FAMILY = 1;
330 | };
331 | name = Debug;
332 | };
333 | 83B58CEF25C8385B00DDFB22 /* Release */ = {
334 | isa = XCBuildConfiguration;
335 | buildSettings = {
336 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
337 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
338 | CODE_SIGN_IDENTITY = "Apple Development";
339 | CODE_SIGN_STYLE = Automatic;
340 | DEVELOPMENT_TEAM = K7XJG666ZW;
341 | INFOPLIST_FILE = "$(SRCROOT)/SSMetalImageFilter/Info.plist";
342 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
343 | LD_RUNPATH_SEARCH_PATHS = (
344 | "$(inherited)",
345 | "@executable_path/Frameworks",
346 | );
347 | PRODUCT_BUNDLE_IDENTIFIER = com.metalimagefilter;
348 | PRODUCT_NAME = SSMetalImageFilter;
349 | PROVISIONING_PROFILE_SPECIFIER = "";
350 | SWIFT_VERSION = 5.0;
351 | TARGETED_DEVICE_FAMILY = 1;
352 | };
353 | name = Release;
354 | };
355 | /* End XCBuildConfiguration section */
356 |
357 | /* Begin XCConfigurationList section */
358 | 83B58CD425C8385A00DDFB22 /* Build configuration list for PBXProject "SSMetalImageFilter" */ = {
359 | isa = XCConfigurationList;
360 | buildConfigurations = (
361 | 83B58CEB25C8385B00DDFB22 /* Debug */,
362 | 83B58CEC25C8385B00DDFB22 /* Release */,
363 | );
364 | defaultConfigurationIsVisible = 0;
365 | defaultConfigurationName = Release;
366 | };
367 | 83B58CED25C8385B00DDFB22 /* Build configuration list for PBXNativeTarget "ImageFilter_ML" */ = {
368 | isa = XCConfigurationList;
369 | buildConfigurations = (
370 | 83B58CEE25C8385B00DDFB22 /* Debug */,
371 | 83B58CEF25C8385B00DDFB22 /* Release */,
372 | );
373 | defaultConfigurationIsVisible = 0;
374 | defaultConfigurationName = Release;
375 | };
376 | /* End XCConfigurationList section */
377 | };
378 | rootObject = 83B58CD125C8385A00DDFB22 /* Project object */;
379 | }
380 |
--------------------------------------------------------------------------------